Skip to content

ADR-0045: "Part of the chosen stack" and "installed today" are different claims, and one of them is checkable

Status: Accepted Date: 2026-09-10

Decisions

D-105 A claim that a package is installed is recorded in a checkable block and verified by a gate; a claim that it is part of the chosen stack is worded as a plan

The spec carries a fenced stack-claims block naming each package it asserts is present, per app. Prose still mentions packages naturally; the block is the part that must be true, and STACKCLAIMS fails the run when it is not.

D-38's stack list is a plan, verified against the sibling project's source when ADR-0020 was written. It is not a claim about this repository's manifests, and the two must not share a phrase.

Context

The spec asserted four times that a package was already a dependency. Three were false, and they were found in about thirty seconds by reading two package.json files:

ClaimWhereReality
"Playwright is already in the stack and can assert this directly"Seam 4absent
"Vitest with @vue/test-utils is the existing home for this"Seam 2absent
"Zod is already in the stack"Testing Decisionsabsent
"jsqr is a current dependency"§3, twice, and Risks item 1absent when written; installed on 2026-09-09 by an agent building the QR route

The two that matter carry this project's verification strategy. Seam 2 asserts presentation rules — a Source Span on every safety field, Not Stated where a record is silent — which require mounting a component, and nothing in this repository has ever mounted one. Seam 4 is the zero-network assertion, widened by D-94 to every surface, and its stated mechanism was not installed.

Risks item 1 is where the fourth did damage. It reasons that camera Identification is the largest cost of the platform decision and offers, as half the mitigation, that "the QR route is unaffected and cheap, because jsqr is already a dependency". A risk assessment resting on an unchecked premise is worse than one resting on none, because it reads as though someone looked.

Why these four and not D-38's list. ADR-0020 verified D-38 against the sibling repository's source, and that verification holds. These four sit in §1, §3 and the Seams — added later, beyond what D-38 covered, and never checked against anything. The confusion is that D-38's Zod and the spec's "Zod is already in the stack" read identically while meaning different things: one is a stack we chose, the other is a manifest entry. Only the second can be false in a way that misleads someone into planning work on it.

Why a gate here when ADR-0044 refused one. ADR-0044 declined to build a check for stretched Coverage rows because judging whether a finding supports a claim is a reading task. Whether a package is in a manifest is a parsing task. The two defects look alike — both are "the document says something untrue" — and only one is mechanically reachable. Reaching for the reachable one is not inconsistency; declining to notice the difference would be.

Decision

The spec names the packages it claims are installed, in one block, and a gate checks them. Claims about the chosen stack are worded as plans and are governed by D-38.

Rejected options

  • Correct the four claims and add no gate — rejected. The spec had already acquired four, and one of them was corrected on 2026-09-09 while the other three sat unnoticed in the same file. Nothing prevents a fifth.
  • A standing rule that a stack claim cites where it was verified — rejected as strictly weaker than the same rule enforced by a script, and available only because ADR-0044 had no better option for its own defect.
  • Install all three so every claim becomes true — rejected. It makes a sentence true by acquiring a dependency, which is the error running backwards, and it is heaviest for Playwright, which needs browser binaries and a harness rather than a line in a manifest.
  • Have the gate infer claims from prose — rejected. It would guess which backticked word is a package, and a checker that guesses is a checker that gets ignored the first time it is wrong.
  • Check D-38's chosen stack against the manifests too — rejected. It would fail on vue-i18n and Zod, which are correctly planned and correctly absent, and a gate whose first act is to fail correct work teaches that its failures are noise.

This ruling may not be re-decided

If a change contradicts this ADR: stop and raise it. Do not implement over it.

Specifically: do not write "already in the stack" about a package that is not in a manifest — say it is part of the chosen stack and not yet installed; do not silence STACKCLAIMS by deleting the block rather than the false claim; and do not install a package to make a sentence true.

Consequences

What becomes easy. A spec claim about tooling can now be trusted, which matters most for the seams: a reader planning verification work will not discover mid-task that the named tool does not exist.

What was fixed on the way. @vue/test-utils was installed, because Seam 2 needs it, the components exist as of 2026-09-09, and it is one light dependency. Playwright was not installed: Seam 4 needs a running app, browser binaries and a harness, and that is its own work rather than something to smuggle into a spec correction. Seam 4 is now marked specified-but-not-executable, with a ticket.

What this does not reach. Claims about the world that are not package names — a provider's retention policy, a finding's contents, what an SDS section contains. Those stay with adversarial review, and this repository now has three separate records of that being the only defence.

Coverage

No upstream finding lands here. The ruling came from checking the spec's own assertions against the repository, which is the case D-104 describes.

UpstreamLanded inEvidenceNote