Skip to content
9 changes: 9 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ status update, and blocker report.

## docs/ index

This is a flat working index for Claude Code sessions. For an
audience-grouped map (including `docs/proposals/`, `docs/audits/`,
`docs/reports/`) see [`docs/README.md`](docs/README.md); for a cold
external reader's orientation to the whole fork, see
[`docs/overview.md`](docs/overview.md).

- [`docs/troubleshooting.md`](docs/troubleshooting.md) — symptom-first
index of recurring blockers (grep your error text here first, before
re-deriving a fix or reading anything else below).
Expand All @@ -109,6 +115,9 @@ status update, and blocker report.
— the "Print!" export page's ordering tabs and flag icons.
- [`docs/features/printing-tags.md`](docs/features/printing-tags.md) — the
"What's That Card?" printing-consensus tagging system, backend + frontend.
- [`docs/features/moderation.md`](docs/features/moderation.md) — Discord
OAuth login, the `Moderators` group gate, sensitive-tag approval queue,
card reports.
- [`docs/features/local-file-source.md`](docs/features/local-file-source.md)
— backend `LOCAL_FILE` catalog source type.
- [`docs/features/card-dom-api.md`](docs/features/card-dom-api.md) —
Expand Down
87 changes: 87 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# docs/ — map of this directory

An honest index, grouped by why you'd be reading rather than by folder.
New here? Start with [`overview.md`](overview.md) — it's written for a
reader with zero prior context on this fork. `CLAUDE.md` (repo root) has
its own flat docs index too, but that one's a working index for Claude
Code sessions specifically; this one's for everybody else.

## Understanding the system

The methodology and the systems it governs.

- [`overview.md`](overview.md) — what this fork is, how it relates to
upstream, and where everything else in this list fits.
- [`theory.md`](theory.md) — the printing-identification pipeline as
candidate-constrained decoding: false-accept bound, prior-art comparison,
soundness mechanisms. Written for an external reader; doubles as the
federation pitch's technical annex. **Reviewed and approved by the owner,
2026-07-17.**
- [`federation-v1.md`](federation-v1.md) — federation verdict exchange
format v1 (spec; no implementation yet — instances would share resolved
consensus verdicts as signed JSON, never raw votes).
- [`upstreaming/vote-system.md`](upstreaming/vote-system.md) — the vote
system (printing/artist/tag weighted consensus) as a cherry-pick
extraction manifest for upstreaming to `chilli-axe/mpc-autofill`; also
the clearest single write-up of how that system is built, commit by
commit.
- [`features/printing-tags.md`](features/printing-tags.md) — the "What's
That Card?" printing-consensus tagging system and vote-queue funnel,
backend + frontend. Stages 1–7 are the current-state reference; Stage 8
onward (local/zero-API-cost backfill) is documented live in the next
entry instead.
- [`features/catalog-completion-plan.md`](features/catalog-completion-plan.md)
— the six-part catalog-completion package (Stage 8+): run-cohort safety,
`content_phash` backfill, evidence recovery, LANDS, residual
classification, and the formal note that became `theory.md`. The live
source of truth for anything past Stage 7.
- [`features/moderation.md`](features/moderation.md) — Discord OAuth login,
the `Moderators` group gate, the sensitive-tag approval queue, card
reports.
- [`features/card-dom-api.md`](features/card-dom-api.md) — generic
`data-card-*` attributes + `mpc:card-selected` event for external
tooling/testing/accessibility.

## Operating it

Deployment, incidents, and cross-session lessons.

- [`infrastructure.md`](infrastructure.md) — Docker build/deploy, secrets &
credentials, telemetry removal, CI/CD state, push policy, the
upstreaming workflow, the drives.csv history-rewrite incident.
- [`troubleshooting.md`](troubleshooting.md) — symptom-first index of
recurring blockers. Grep your error text here before re-deriving a fix.
- [`lessons.md`](lessons.md) — terse, reusable cross-session lessons (CI
vs. local venv trust, worktree port collisions, ES mapping drift, and
more).

## Plans & proposals

One-word status per doc; see each file for the full survey/spec.

| Doc | Status |
| -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| [`proposals/proposal-f-public-stats-page.md`](proposals/proposal-f-public-stats-page.md) — public `/stats` transparency page | HOLD |
| [`proposals/proposal-g-user-accounts-saved-decks.md`](proposals/proposal-g-user-accounts-saved-decks.md) — user accounts + saved decks via Discord OAuth | HOLD |

Not every shipped proposal-lettered feature has a survey doc here — some
(e.g. Proposal A, Proposal D) went straight from idea to shipped PR without
a separate written spec. This list is only the ones that got a dedicated
doc.

## Records

Point-in-time findings and relayed work products, not living reference.

- **`audits/`** — not yet on this branch. `docs/audits/ui-content-audit.md`
(12 UI content-accuracy findings, HOLD) exists on the unmerged
`claude/ui-content-audit` branch; that PR (#56) is deliberately held open
until the audit worker adds a per-row disposition column reflecting the
build pass (PRs #64/#65). Not this pass's to merge — will appear here
once #56 lands.
- [`reports/`](reports/README.md) — the report-relay convention (see that
directory's own README). No reports have merged to this branch yet: the
convention and its first files live on the `report-relay`/`report-relay-2`
branches and are expected to land in a docs batch soon. The README is
written now so the directory has its orientation in place before that
merge.
17 changes: 10 additions & 7 deletions docs/features/card-dom-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ confirmed (prev/next arrows or grid selector), with the same fields

### Printing-candidate extension

The printing-tag candidate grids (`PrintingTagQueue.tsx`'s standalone
queue and `PrintingTagPicker.tsx`'s embedded picker in
The printing-tag candidate grids (`QuestionFeed.tsx`'s unified vote queue
and `PrintingTagPicker.tsx`'s embedded picker in
`CardDetailedViewModal.tsx`) carry a sibling helper,
`getPrintingCandidateDataAttributes(cardName, candidate)` — not a reuse of
`getCardDataAttributes`, since `PrintingCandidate` (`schema_types.ts`)
Expand All @@ -40,15 +40,18 @@ The "No match" button intentionally carries none of these attributes.
## Key files

- `frontend/src/common/cardDom.ts`
- `frontend/src/components/Card.tsx`, `CardSlot.tsx`,
`CardDetailedViewModal.tsx`
- `frontend/src/features/printingTags/PrintingTagQueue.tsx`,
`PrintingTagPicker.tsx`
- `frontend/src/features/card/Card.tsx`, `CardSlot.tsx`
- `frontend/src/features/cardDetailedView/CardDetailedViewModal.tsx`
- `frontend/src/features/questionFeed/QuestionFeed.tsx`,
`frontend/src/features/printingTags/PrintingTagPicker.tsx`,
`cardPanel.tsx`
- `frontend/docs/dom-api.md` (stability: best-effort, semver-ish,
additive-only)

## Status

Documented in `frontend/docs/dom-api.md`. Test coverage in
`CardSlot.spec.ts`, `PrintingTagQueue.spec.ts`, `PrintingTagPicker.spec.ts`
`CardSlot.spec.ts`, `PrintingTagPicker.spec.ts`, and the
`QuestionFeed*.spec.ts` suite (unified vote queue, successor to the old
standalone `PrintingTagQueue.tsx` this API originally shipped against)
— real Playwright runs against the mocked backend, not just typecheck.
6 changes: 3 additions & 3 deletions docs/features/catalog-completion-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ are the only classification targets across every part below.

---

## Part 1 — Run-cohort safety (in progress, finish as planned)
## Part 1 — Run-cohort safety (merged, PR #28)

Revocability via a **separate column**, never an `anonymous_id` suffix.
Confirmed via two parallel research passes (git history in this branch's
Expand Down Expand Up @@ -402,7 +402,7 @@ and live-traffic-fairness control, not a cost control, so the WAIT sequencing ab

---

## Part 3 — Shared evidence-recovery module (after PR #27 merges; expanded)
## Part 3 — Shared evidence-recovery module (built, HOLD #P3 — write pass pending)

Insight: artist is a property of the ARTWORK, not the printing — art-
identity evidence supports artist votes even where printing votes are
Expand Down Expand Up @@ -611,7 +611,7 @@ Part 3's frame-mismatch census number for its share of this pool).

---

## Part 6 — Formal note (starts only after the full-catalog run's final report exists)
## Part 6 — Formal note (merged — docs/theory.md)

`docs/theory.md`: the pipeline as candidate-constrained unique decoding
over a closed codebook.
Expand Down
2 changes: 1 addition & 1 deletion docs/features/google-drive-connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ real upload, no confirmation a file actually lands in Drive.

## Key files

- `frontend/src/components/GoogleDriveBackendConfig.tsx`,
- `frontend/src/features/backend/GoogleDriveBackendConfig.tsx`,
`LocalFolderBackendConfig.tsx`, `BackendConfig.tsx`
- `frontend/src/features/googleDrive/` (`googleDriveAuth.ts`,
`googleDriveConfig.ts`, `GoogleDriveService.ts`)
Expand Down
12 changes: 7 additions & 5 deletions docs/features/moderation.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,14 +330,16 @@ documented here so the reasoning survives if either file is ever touched:

## Known gaps / follow-ups

- Live Discord OAuth verified working end-to-end in production 2026-07-15
(server-side plumbing via `curl` simulation, then a real moderator's
browser round-trip) — see "nginx routing and proxy headers for
`/accounts/`" above.
- Discord guild-role sync for a federation-wide moderator roster (see "Who is
a moderator").
- Federation export/import of moderation verdicts is v1.1
([[../federation-v1.md]]) — explicitly out of scope here.
- No consequences yet for resolved `low-res` / `incorrect-info`.
- The rate limiter shares the existing single-gunicorn-worker in-process-cache
caveat ([[printing-tags.md]]).
caveat (documented as a code comment on `post_submit_printing_tag`,
`cardpicker/views.py:860-863` — not currently written up in any doc).

**Verified, not a gap**: live Discord OAuth working end-to-end in production
2026-07-15 (server-side plumbing via `curl` simulation, then a real
moderator's browser round-trip) — see "nginx routing and proxy headers for
`/accounts/`" above.
5 changes: 3 additions & 2 deletions docs/features/pdf-generator.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ Full spec + approval record: `docs/proposals/proposal-b-bleed-normalization.md`.
`failures` array — see bug 4), `pdfRenderService.ts`, `useRenderPDF.ts`
- `frontend/src/features/pdf/PDFCanvasPreview.tsx`
- `frontend/scripts/copy-pdf-worker.js`
- `frontend/src/components/PDFGeneratorModal.tsx`,
`FinishedMyProject.tsx`, `ProjectEditor.tsx`
- `frontend/src/features/pdf/PDFGeneratorModal.tsx`,
`frontend/src/features/export/FinishedMyProject.tsx`,
`frontend/src/components/ProjectEditor.tsx`
- `frontend/tests/PDFGenerator.spec.ts` — mocked-CDN Playwright coverage for
bug 4 (preview warning, confirm-gated download/cancel, and a real-image
success-path regression check)
Expand Down
5 changes: 4 additions & 1 deletion docs/features/print-export-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ requiring hand-rolled SVG specifically.

## Key files

- `frontend/src/components/FinishedMyProject.tsx`
- `frontend/src/features/export/FinishedMyProject.tsx`
- `frontend/src/components/flags.tsx`
- `frontend/public/*.svg` (vendored flag icons)

Expand All @@ -45,3 +45,6 @@ addition).

- The NotMPC flow steps still carry a TODO for manual verification against
the real site (currently based on an automated read only).
- The PringlePrints flow steps carry the identical TODO (`FinishedMyProject.tsx:347`)
— steps/pricing/service-area were derived from a one-time read of
pringleprints.ca, not a manual walkthrough, and may have changed since.
15 changes: 8 additions & 7 deletions docs/features/printing-tags.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Printing-aware card tagging ("What's That Card?" vote queue)

_Current-state reference, as of 2026-07-16._ Full stage-by-stage build
_Current-state reference, as of 2026-07-17._ Full stage-by-stage build
history (Stages 1–7 below): `git log e4eb6cb3 -- docs/features/printing-tags.md`
and earlier commits — that SHA is the last commit before this file was
rewritten from a linear changelog into this reference.
Expand Down Expand Up @@ -1498,7 +1498,7 @@ unrelated to the OCR token-position bug above. Two separate fixes, not
one parser fix arriving twice - the D2.5 deterministic tier is **not**
implied by this OCR fix and was not built.

## Key files
## Key files (Stage 8 era, historical)

- Backend: `cardpicker/printing_consensus.py`,
`cardpicker/printing_metadata_import.py`,
Expand Down Expand Up @@ -1533,7 +1533,7 @@ implied by this OCR fix and was not built.
`get_baked_git_sha`), `cardpicker/management/commands/purge_machine_votes.py`,
migration `0061_pilotrunledger_cardartistvote_run_id_and_more.py`

## Known gaps
## Known gaps (Stage 8 era, historical)

- The Stage 7 layout (starburst/card/chip-ring composition) was hand-tuned
via iterative screenshot review, not built against a real design system -
Expand Down Expand Up @@ -1563,8 +1563,8 @@ implied by this OCR fix and was not built.
feedback.
- Stage numbering: Stage 4 (no-match reason tags, merged as PR #12),
Stage 5 (tag identity/presentation decoupling via `Tag.display_name`,
merged as PR #14), and Stage 6 (this document's current stage —
deductive printing-tag backfill) reflect three concurrently-developed
merged as PR #14), and Stage 6 (deductive printing-tag backfill) reflect
three concurrently-developed
branches sharing this one doc file, numbered in landing order to avoid
collisions.
- **Future work: anonymous_id trust scoring via honeypot questions**
Expand Down Expand Up @@ -1722,8 +1722,9 @@ federation, deferred), item 5 (questionFeed ordering mirror, separate follow-up
Scryfall's own token detection), task #111 (unrelated CI noise in the thumbnail-refresh
trigger), PR #19's disposition (owner's convenience).

**Full-catalog run: not yet fired.** This report is the synthesizing deliverable requested
before that authorization - awaiting explicit owner go-ahead.
**Full-catalog run: since fired and completed** (see `catalog-completion-plan.md`'s Status
section for final numbers). This report was the synthesizing deliverable requested before
that authorization.

## Two fast-follows, built after HOLD #2 (2026-07-16)

Expand Down
24 changes: 13 additions & 11 deletions docs/infrastructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,19 @@ this fixed and its follow-on hardening. Fixed by `eaece1fd` (#18,
rebuild that previously spent 25+ minutes uploading a ~2GB context now
uploads single-digit megabytes and finishes in ~5 minutes.
- Postgres/ES: `docker-compose.yml` (dev, base file) publishes
`127.0.0.1:5432`/`127.0.0.1:9200` deliberately — they were
internet-exposed at one point. `docker-compose.prod.yml` OVERRIDES both
to `ports: []` — a fresh `docker compose -f docker-compose.prod.yml up`
publishes neither port to the host at all. The containers actually
running on this box (as of 2026-07-18) still answer on
`127.0.0.1:5432`/`127.0.0.1:9200` regardless — they predate the `ports: []` override and haven't been recreated since (Docker doesn't
retroactively apply a compose-file port change to an already-running
container). Don't rely on this from a fresh script: if postgres/
elasticsearch are ever recreated (version bump, `--force-recreate`,
etc.) under the current prod compose file, host-port access silently
disappears.
`127.0.0.1:5432`/`127.0.0.1:9200` deliberately - they were
internet-exposed at one point. `docker-compose.prod.yml` overrides both
services' `ports:` to `[]` (Compose replaces, not merges, list fields) -
a fresh `docker compose -f docker-compose.prod.yml up` publishes neither
port to the host at all, only `expose:` for container-to-container
access. The containers actually running on this box (as of 2026-07-18)
still answer on `127.0.0.1:5432`/`127.0.0.1:9200` regardless - they
predate the `ports: []` override and haven't been recreated since
(Docker doesn't retroactively apply a compose-file port change to an
already-running container). Don't rely on this from a fresh script: if
postgres/elasticsearch are ever recreated (version bump,
`--force-recreate`, etc.) under the current prod compose file, host-port
access silently disappears.
- **After `docker compose up -d django worker` (or any command that
recreates the `django` container), also restart `nginx`** — see
[[troubleshooting.md]] ("nginx 502s everything after a django container
Expand Down
Loading