Skip to content

docs(adr): sweep all 20 ADRs — align the amendment convention, fix four stale claims - #34

Merged
ancsingabor merged 1 commit into
mainfrom
docs/adr-sweep
Oct 1, 2026
Merged

ancsingabor merged 1 commit into
mainfrom
docs/adr-sweep

Conversation

@ancsingabor

Copy link
Copy Markdown
Owner

The docs/guide/ pass is finished, so this is the layer-2 sweep. Every ADR was read against the code. Nothing is shortened — they stay the complete record, per CLAUDE.md. What changes is that each file now says on its Status: line whether it has moved since acceptance, and four claims that had gone false are corrected.

Real defects, found by checking each ADR against code

ADR Claim Reality
013 header: (implemented Milestone 1) Not implemented. No app/[lang]/; proxy.ts has no locale logic at all; config/copy/index.ts still says "once app/[lang]/ routing lands". The config half (brand.defaultLocale, brand.locales, getCopy) did land
010 sources.source_kind is a required column source_kind is the Postgres enum type; the column is sources.kind. And the tier is not required — 0005's constraint only forbids a tier on scientific/historical, and sourceSchema.authority_tier is .nullable().default(null)
005 gate check 3: "every claim-bearing sentence retains ≥1 citation" ADR-018 establishes this is undecidable over free prose and replaces it. 005 had no pointer, so a reader of it alone takes the stronger guarantee as the one the code makes
002 "chunks references it" Neither table references the other; chunk_units joins them, for the one case a units.chunk_id column could not model

ADR-010 is the one with teeth. The schema makes the category error that ADR exists to prevent unrepresentable in one direction only: ranking a physics paper by ecclesial authority cannot be expressed, but ingesting an encyclical with no tier at all can — it would pass the manifest schema, the database and every assertion in assert.ts, then reach context assembly as an unlabelled block. It has not bitten only because both sources are tiered by hand and there are two of them. The check is now owed in status.md; the honest place for it is the manifest schema, beside the resolved license ADR-003 already demands.

ADR-013's defect had a sibling in README.md, which said "Apologia serves /hu/… and /en/…". Fixed in the same pass.

Smaller corrections

  • 004 listed embed among the stages that run — it is deliberately unwritten
  • 015's integration-row cell still read "decided when the first one is written" although its own amendment decides it (Vitest)
  • 023's "234 cases over ~1,550 lines" is now dated; it is 252 over ~3,450
  • 009 said the honeypot field is retained. The helper is, and is tested — but no form renders it, because there is no question box yet

The alignment

Every ADR that has moved now carries its story on the Status: line, in the shape ADR-019 already used. docs/adr/README.md repeats it in the index's Status column and states the layering explicitly: the guide is the way in, these are the argument behind it, and where they disagree the ADR is right.

Thirteen of the twenty carry a marker. Seven have a dated ## Amendment or ## Open question; three were superseded by a later ADR (004, 005 by 023/018; 014 by 017); 011, 017 and 020 record a correction made elsewhere. The seven that stand exactly as accepted are 001, 006, 009, 016, 018, 021, 022 — largely the ones whose subject has not been built. In this repository a decision gets corrected when code meets it, so an unamended ADR is usually an untested one. The count ships with the one-liner that re-derives it.

ADR-023's two post-acceptance corrections (outcome 4, the restated bundle limit) were sitting at ### inside ## Trade-offs, which read as part of the original argument. Promoted to a dated ## Amendment.

One lead disproved

The honeypot was carried into this session as a field named by ADR-009 and ADR-015 and existing in no code. It exists — isHoneypotTripped() in lib/rate-limit.ts, with unit tests. ADR-015's row was correct all along; only ADR-009's wording needed the precision.

Checks

docs:lint green (20 ADRs, 302 links, 25 anchors) · npm test 350/350 · tsc --noEmit clean.

🤖 Generated with Claude Code

…ur stale claims

The docs/guide/ pass is done, so this is the layer-2 sweep. The ADRs stay the
complete record and nothing here is shortened; what changes is that each file
now says on its Status line whether it has moved since it was accepted, and
four claims that had gone false are corrected.

Real defects found by checking each ADR against the code:

ADR-013's header said "(implemented Milestone 1)". It is not implemented.
`app/[lang]/` does not exist, `proxy.ts` has no locale logic at all, and
`config/copy/index.ts` still says "once app/[lang]/ routing lands" in the
future tense the header should have used. The config half did land. Amended
with the split, and the same claim is fixed in README.md, which said
"Apologia serves /hu/… and /en/…".

ADR-010 said `sources.source_kind` is a required column. `source_kind` is the
Postgres enum *type*; the column is `sources.kind` — the same slip already
fixed in architecture.md, still live here. Worse, the tier is not required:
`0005`'s constraint only forbids a tier on scientific and historical sources,
and `sourceSchema.authority_tier` is `.nullable().default(null)`, so an
encyclical with no tier would pass the manifest, the database and every
assertion, then reach context assembly unlabelled. Amended; the check is owed
in the manifest schema and recorded in status.md.

ADR-005's Decision block still lists "every claim-bearing sentence retains ≥1
citation" with no pointer to ADR-018, which establishes that the check is
undecidable over free prose and replaces it. A reader of 005 alone would take
the stronger guarantee as the one the code makes.

ADR-002's consequence said "`chunks` references it". Neither table references
the other; they are joined by `chunk_units`, and the reason is the one case a
`units.chunk_id` column could not model.

Smaller corrections: ADR-004's Context listed `embed` among the stages that run
(it is deliberately unwritten); ADR-015's integration-row cell still read
"decided when the first one is written" although its own amendment decides it;
ADR-023's "234 cases over ~1,550 lines" is dated, now 252 over ~3,450; ADR-009
said the honeypot *field* is retained — the helper is, and is tested, but no
form renders it because there is no question box yet.

The alignment: every ADR that has moved now carries the story in its Status
line, in the shape ADR-019 already used, and docs/adr/README.md repeats it in
the index's Status column with the layering stated — the guide is the way in,
these are the argument behind it. ADR-023's two post-acceptance corrections
were sitting at ### inside Trade-offs, which read as part of the original
argument; promoted to a dated ## Amendment.

One thing the sweep disproved: the honeypot was carried in memory as a field
named by two ADRs and existing in no code. It exists, in lib/rate-limit.ts,
with unit tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ancsingabor
ancsingabor merged commit 4131071 into main Oct 1, 2026
2 checks passed
@ancsingabor
ancsingabor deleted the docs/adr-sweep branch October 1, 2026 14:33
ancsingabor added a commit that referenced this pull request Oct 1, 2026
chore: drop a stray vitest reporter output committed in #34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant