Skip to main content
manual page/ ADRs

ADR-0116 — Shipped-spec invariant + status/spec coherence check

sourceSource: suspec/docs/adrs/0116-shipped-spec-invariant.mdModified: 2026-06-30
Sections
4
Format
Markdown
Order
152 / 156

Context

ADR-0108 made the spec an Active living container with a small status set (draft → ready → active → superseded); ADR-0110 made each ## Execution change-cycle entry the durable, structured residue of a closed change (Scope, the AC→evidence Coverage digest, the SHA/hash Pins). Together they assume a spec's recorded lifecycle and its board placement stay coherent. Nothing checks that they do.

The Phase 3 family sweep (workflow wf9rvvwys) found the drift this leaves open. SPEC-suspec-agents was marked shipped on the workspace board, yet:

  • its own frontmatter status still said ready (board and spec disagreed about whether the work was done);
  • it carried no ## Execution section at all — the AC→evidence digest ADR-0110 calls for a closed spec was simply absent, so the requirement→evidence linkage for a "shipped" feature did not exist;
  • one of its acceptance criteria still named a retired artifact, an AC that could never have closed against the work that actually shipped.

A spec the board calls shipped, with no Execution record, a disagreeing status, and an AC pointing at a thing that no longer exists, is the exact silent-staleness failure ADR-0108 set out to catch — and it slipped because the lifecycle is held by discipline alone, with no coherence gate. This was one of the recurring classes the sweep traced to a missing automated gate: humans caught it, no check did.

Decision

Propose an invariant — a spec marked shipped on the board MUST be coherent with its own record — and propose extending the existing suspec check to verify it. A spec is shipped-coherent iff:

  1. Status agrees. When the board places a spec in a terminal/shipped column, the spec's own frontmatter status is the agreeing terminal value (active for an amended-and-shipped living spec, or superseded with a superseded_by: pointer) — never still draft/ready. The two records of "is this done?" must not contradict each other.

  2. Execution is present. A shipped spec carries at least one ## Execution change-cycle entry (ADR-0110): the durable Scope + AC→evidence Coverage digest for the change that shipped. A spec the board calls done with no Execution record is incoherent — the requirement→evidence linkage for a shipped feature is exactly the residue ADR-0110 keeps.

Spec-side shipped; board-signal half deferred. suspec check (the toolable subset, ADR-0063) now carries the spec-status↔## Execution coherence (SPEC-method-gates): it flags an active spec with no ## Execution, and a non-active (draft/ready/done) spec that carries one. The other half — failing when the board marks a spec shipped but the spec disagrees — is NOT built: the board's State column is freeform prose, not a low-FP signal to parse, so that half stays the deferred toolable follow-up. The check is 0-FP by construction on the board signal: it fires only on a spec the board itself declares shipped, so a draft/ready/in-flight spec is never touched, and a legacy or 1:1-simple spec that the board has not marked shipped is never forced into the structured form. (The AC-names-a-retired- artifact symptom is left to the ADR-0108 reference-snapshot staleness mechanism and to review — it is not part of this coherence check.)

_Level: toolable — the spec-status↔Execution checks shipped (suspec check: active-spec-no-execution

  • nonactive-spec-with-execution, suspec-cli). The board-signal half stays proposed (the freeform board is not a low-FP parse target); it remains a discipline-and-review obligation until/unless built._

Consequences

  • The shipped/ready contradiction the sweep found becomes detectable instead of relying on a human reading both the board and the frontmatter. The board and the spec stop being two records that can silently disagree about whether a feature is done.
  • A shipped spec is forced to carry its ADR-0110 evidence digest — the gate makes the durable AC→evidence residue a precondition of "shipped," not an optional courtesy that a fast close can skip.
  • Cost: another suspec check core check to specify and (later) build and maintain; until it ships this is one more discipline-and-review obligation, which is precisely the failure mode the sweep showed discipline alone does not hold. The honest cost is the gap between this proposed record and a shipped checker — this ADR closes nothing on its own.
  • Coupling to the board reader. The check needs to read the board's shipped signal as well as the spec; it inherits whatever the board representation is. If a spec is shipped without ever touching the board, the gate has no signal to fire on — it covers board-recorded shipped specs, not every closed one.

Affected obligations / constraints

  • Refines: ADR-0108 (adds a coherence gate to the living-spec lifecycle it defines) and ADR-0110 (makes a present ## Execution digest a precondition of a board-shipped spec). Grounded by: the Phase 3 family sweep (wf9rvvwys, SPEC-suspec-agents).
  • Does NOT change: the spec status set, the ## Execution format, the verdict model, or the checks contract — no checks.yaml rule is added here (the checker is proposed, not shipped; ADR-0063). ADRs 0108/0110 are refined by reference, never edited (Nygard immutability).

Starter kit: Set up a workspace