ADR-0143 — Path-agnostic check: the entire CLI contract
Context
- The check engine is already pure. Every rule in the checks contract operates on parsed records with filesystem access injected as predicates; only the command plumbing resolves workspaces, stores, and repo roots. The purity boundary the codebase already enforces is the product boundary this decision draws.
- Every other verb lost its subject. With the store retired (ADR-0141) and promotion retired (ADR-0142), the launch spine, evidence capture, gate, scaffolds, seeding, staleness reconcile, board/status projections, and store management have nothing to operate on.
- Reinforcement posture. ADR-0140 Decision 2: the CLI's one job is the deterministic honesty floor — the facts a lazy or dishonest reviewer cannot fake (coverage-complete, command-matches, pass-needs-evidence, ref-resolves) plus the single-artifact lint, at zero model cost.
Decision
-
The surface.
suspec check <artifact> [--spec <path>] [--task <path>]andsuspec check --contract(the checks contract as JSON). Nothing else — no other command, no interactive mode, no dashboard. Level: enforced (suspec-cli). -
Path-agnostic, always. The CLI reads exactly the files it is handed by full path. It never resolves a store, a config, a repo root, or a workspace tree. The exceptions are three reference checks — C009, C015, and C010 (Decision 4) — each of which resolves one level of sibling directory relative to the passed artifact and never walks a tree or touches a store. The primary artifact's kind is read from its own frontmatter; companions are always explicit flags. Level: enforced (suspec-cli).
-
A missing required companion blocks.
--specis required for every review;--taskis required iff the review's frontmatter names atask:(a task-less 1:1 review reconciles spec-keyed, against the spec's full requirement set) — a--taskpassed but not referenced is refused as a wiring mistake, never silently ignored. A review checked without a companion it needs exits blocking (2) naming the missing flag — the honesty floor never degrades silently into a shallower check. Level: enforced (suspec-cli). -
Reference checks resolve artifact-relative. C009 (source refs) and C015 (citation anchors) resolve against the passed artifact's own directory —
sources.mdis the spec's sibling — never against a workspace root. C010 (change-planpreserves:/SPEC-id#AC-NNNrefs) is the narrow exception to Decision 2's no-siblings-scan rule: it resolvesSPEC-id#AC-NNNby scanning the plan's own directory for sibling*/spec.mdfiles, one level beside the plan, never a tree walk. Level: enforced (suspec-cli). -
C017 leaves the adopter contract. The orphaned-reference scan presumes a governed tree to walk; catalog hygiene is the catalog repo's own concern (narrows ADR-0097; C016's check and hard-error severity stand untouched — the gate-path/reconcile-path split it was framed against narrows per Decision 7, same as C013/C020). Level: convention.
-
Contract 0.16.0.
checks/checks.yaml(canon) and the CLI's contract table move together in one logical change; the sibling-canon drift guard stays the enforcement. Level: enforced (drift-guard test + CI). -
Exit codes are the API. 0 clean · 1 warning · 2 blocking;
--jsonstays the structured face. Severity previously expressed as "blocks at the gate face" is expressed as blocking severity at check time — the human owns what blocks a merge (narrows ADR-0097 (C016's gate-path-vs-reconcile-path split), ADR-0129, and ADR-0128: the checks and their hard severities stand; the gate face they referenced retires). Level: enforced (suspec-cli). -
Family consequences. corpus-mcp adapts this surface only — path-explicit tools, shell-out posture unchanged. The
suspec show <task|spec|review|checks> --jsonread family ADR-0085 grew as "the loader surface the MCP needs" — and ADR-0110 confirms shipped (suspec show spec) — retires with the rest of the multi-verb surface; only ADR-0085's shell-out, never-import-core architecture survives (narrows ADR-0085 and ADR-0110; see Upheld). Theagents emitCodex emitter retires; the committed Codex projections become hand-maintained (narrows ADR-0098: the universal AGENTS.md discipline stands; the emitter and its sync guard retire). Level: convention.
Superseded and narrowed decisions
Superseded:
- ADR-0136 — the launcher boundary loses its subject: there is no launcher, no worktree orchestration, no prompt generation, no run record.
- ADR-0084 — the prepare verbs (
pull,promote, scaffolds) retire with their subjects. - ADR-0107 and
ADR-0130 — the staleness reconcile ran inside
review/check --staleness; both verbs retire. Staleness stays a review concern the reviewer owns by reading the diff.
Narrowed:
- ADR-0077 — reconcile-only, markdown-only, verdict-free, facts-not-verdicts (D8): all stand, sharpened — the harness of composable parts collapses to the one composable part that earned its keep. The multi-verb surface retires.
- ADR-0097, ADR-0128, ADR-0129 — per Decisions 5 and 7.
- ADR-0098 — per Decision 8.
- ADR-0085 and
ADR-0110 — per Decision 8: the
suspec show … --jsonread family ADR-0085 grew (shipped per ADR-0110'ssuspec show spec) retires with the multi-verb surface; ADR-0085's shell-out, never-import-core architecture is what actually survives (see Upheld). ADR-0110's Scope and Coverage sub-decisions stand; its Pins sub-decision (reviewed-sha:evidence-hash:, written bysuspec stamp) retires with the staleness machinery it served — ADR-0107/ADR-0130 (Superseded, above) — Decision 1's exhaustive surface ("nothing else — no other command") leaves nostampcommand to write it.
Upheld: ADR-0085 (shell-out, never import-core architecture only — its read-family growth narrows, above), ADR-0063 (levels as stated), ADR-0079/ADR-0083 (the surviving checks' semantics).
Alternatives considered
| Alternative | Why rejected |
|---|---|
Positional multi-file with role pairing (suspec check review.md spec.md task.md) | Pairing inference between positionals is hidden resolution — the exact organ this decision removes; explicit flags are deterministic and self-documenting. |
| Keep a path-agnostic scaffold verb | Skills carry the artifact shapes; an agent writes files natively. A scaffold verb is surface without subject. |
Keep --staleness (git-backed advisory) | It resolves a repo root and reads git — both banned by Decision 2; the reviewer reads the diff. |
| Warn (exit 1) on a review checked without companions | Silently downgrades the floor's strongest checks (C012/C013/C020 simply don't run); a floor that degrades quietly is not a floor. |
Consequences
- Positive: the CLI becomes a pure function over files it is handed — trivially testable, trivially portable, no location opinions; the drift guard keeps canon and implementation honest; the check is runnable by hand, in CI, or through MCP identically.
- Negative: no tool lists, resumes, or manages work in flight — by design, that capability left with the store; anyone wanting it composes it from their own harness.
- Neutral: contract 0.16.0 is a breaking bump consumed only by the repo family (nothing external pins 0.15.0).
Status
Accepted (2026-07-10). Supersedes ADR-0136, ADR-0084, ADR-0107, ADR-0130; narrows ADR-0077, ADR-0097, ADR-0128, ADR-0129, ADR-0098, ADR-0085 (its read-family growth only — the shell-out architecture is upheld), ADR-0110; upholds ADR-0085 (shell-out, never-import-core architecture), ADR-0063, ADR-0079/ADR-0083 (the surviving checks' semantics). Part of the ADR-0140 re-founding.
Propagation
docs/adrs/README.md— ledger row + disposition flips (0136, 0084, 0107, 0130, 0077, 0097, 0128, 0129, 0098, 0085, 0110).- Canon:
checks/checks.yaml→ 0.16.0 (C009/C015 re-scope wording, C017 removal);docs/reference/cli.md(two-invocation rewrite),docs/reference/checks.md,checks/README.md,docs/10-integrations.md. - corpus-cli: the surgery — 19 command retirements, store/gate/launch/Tui/Workspace cull, explicit-path review checking, contract bump, test rebuild, gates green.
- corpus-mcp: path-pass-through realign + fixture regeneration against the rebuilt CLI.
- corpus-agents: drop the retired verbs from agent bodies; retire the codex-sync guard; freeze
.codex/as hand-maintained.
Need a starting point? Install the skills