System reference · Part 5
Doctrine
The standing rules the coding planner rests on: the single writer, guards against floors against gates, the deny primitive, channel discipline, revision-bound approvals and evidence.
These are the standing rules the mechanism above depends on. They were written during the rebuild and are stated here in their current form; where the rebuild changed one, the change is named.
The single writer
Reserved pipeline. state has exactly one writer: .claude/scripts/pipeline-transition.sh. Every other participant reads it, and the driver routes every write through a transition verb.
This is now enforced rather than merely intended. A deterministic hook denies direct --set-metadata and --unset-metadata on the reserved namespace, so the script really is the only writer. A person correcting state by hand can prefix an override environment variable. For most of the rebuild this rule was a convention held by prose, which is precisely the category of control that failed twice before; it is now a floor.
One exception is named in code rather than left implicit: the driver closes unsanctioned children discovered mid-fan-out directly, because those pieces carry no pipeline state at all.
Write authority is partitioned by role. The transition script writes pipeline metadata, waiver labels and log notes, and never stage artifacts. A step's command writes its own artifact and never pipeline state. A reviewer writes verdicts and never the submission under review. A human writes approvals and waiver rulings.
The reviewer may never modify what it reviews. This is the partition that matters most in practice and the one a past incident crossed, when a review session edited the documents it was reviewing and then reconciled them with each other. A verdict that can rewrite its subject is not a verdict.
Guards, floors, and gates
Three mechanisms, and conflating them is how a safety check becomes a session-ending outage or an ordering check becomes a rubber stamp.
A guard asks: is this action dangerous? It catches a specific confirmed hazard, and on its own fault it fails open and allows, because a harness fault must never brick a working session and the cost of a false block is a stopped person. Silence from a guard means allowed.
A floor asks: can I prove this step's work is done? It is deterministic, it reads the world rather than prose, and on doubt it refuses or escalates. Silence from a floor means nothing; silence is never a pass.
A gate asks: may this step be declared finished? In the manifest that is a human gate or nothing. A human gate is a suspension point, not a check.
The single writer enforces the human gate against a dispatched session (VOX_AFK=1): its complete on a human-gated step is refused unless the node's own recorded autonomy level relaxes that step, recomputed by the writer rather than taken from the caller's flags. Its integrate verb, which records the terminal integrate step that complete cannot leave, applies the same rule through the same helper: a dispatched caller is refused before any floor runs unless the node's dial relaxes integrate, which only deep with an integration branch set does. An attended caller is not yet judged, because telling a person from an agent there needs a trusted approval record.
Earlier documentation used "gate" for what this document calls a floor, and drew a two-way guard-versus-gate distinction. The three-way split is the current vocabulary and the one the manifest uses. The underlying insight is unchanged: opposite failure postures for opposite jobs.
The deny primitive
A hook that runs before a tool call prints a small decision object to standard output and exits zero. Silence means allow. The reason string is the only thing the agent sees, so it carries both the refusal and the correct next action.
.claude/hooks/bd-pipeline-guard.ts implements this and is registered to run before every shell command. It blocks forced closes and cascading deletes unconditionally, blocks direct writes to the reserved metadata namespace as described above, and blocks a set of retired issue statuses outright. It fails open on any parse or spawn error and honours the override environment variable.
That last item is a change from earlier behaviour worth naming. Three custom statuses were once used as the pipeline's own step field, and the hook gated transitions into them on the presence of a licensing artifact. The step field replaced them; the statuses are retired, and the hook now refuses them outright rather than gating them, because the tracker itself accepts any status string and nothing else would keep the retired vocabulary from creeping back.
Channel discipline
Three channels, three meanings, and the distinction between the second and third is the whole point:
| Exit | Channel | Meaning |
|---|---|---|
0 |
structured output on stdout | the verb ran |
1 |
structured output on stdout | a refusal the caller can fix |
2 |
message on stderr | the machinery is wrong |
An engine fault is never an approval. Exit 1 and exit 2 are "I checked and it is wrong" versus "I could not check"; collapsing them destroys the only signal telling a person whether to fix the artifact or fix the harness.
This was designed but unbuilt during the diagnosis and is now built in the driver and the headless runner. Both keep standard output for the structured result and standard error for narration, so a caller that parses output is never confused by progress messages.
Revision-bound approvals
An approval is a statement about a specific version of an artifact, never about the artifact's name. A verdict that does not name what it approved is not evidence.
The original design bound approvals to a revision counter and was never built in that form. A working equivalent now exists, keyed on the commit rather than a counter: the review floor requires the reviewed commit to equal the repository's current head at the moment of review, and the delivery floor consumes that same recorded commit as the subject of its landing proof. The chain from "this code was reviewed" to "this code landed" is therefore anchored on one commit identifier written by code at both ends.
What remains unbuilt is the broader form: content hashing of artifacts so a gate can re-compute and compare, and the idempotency check that catches a silent in-place edit leaving every identifier intact. Both would close the archived-copy trap, where a session competently reviews the wrong document because a path is not an identity.
Evidence packages
A step does not claim completion; it submits evidence and a floor verifies it. The repository's own evidence rule, .claude/rules/evidence-of-completion.md, holds the doctrine: every acceptance criterion is discharged by a committed automated test or a committed evidence artifact, and never by narrative. Self-report is not proof. The rule also insists that outcome adjudication runs in fresh context against committed artifacts rather than against the implementer's account, and it sizes proof to risk so that trivial changes do not acquire ceremony.
The pipeline's floors are the machine-readable encoding of that rule at a step boundary. They add no new obligation. The predicates in force today are file existence, literal content matching, fan-out birth facts, children terminal, integrated acceptance, review verdicts and landing on target.
The named-key evidence schema — declared keys, present-but-falsy counting as missing, a scan for claim language substituting assertion for proof — remains designed and unbuilt. So does one gap in coverage: the implement step still declares no floor at all.
Supersession and rewind
Two directions of one concern, and both remain designed rather than built.
Supersession, forward. When a step produces an artifact that replaces its input, the producer retires the predecessor. The settled instance: the requirements document supersedes the design brief outright, and spec generation reads the requirements document only. The brief is not a second opinion or a thing to reconcile against. Retirement belongs to the producer because the producer is the only participant that knows the replacement is complete. The ruling stands; no code enforces the retirement.
Rewind, backward. When upstream evidence changes, invalidate only dependent verdicts and rewind to the earliest affected boundary. Both halves carry weight. Only dependent, because an upstream change that invalidates unrelated approvals makes every edit cost a full re-run and turns the harness into the ceremony it exists to remove. Earliest affected boundary, because rewinding somewhere convenient leaves an approval standing on evidence that no longer exists.
Together these would make the artifact graph, rather than the filesystem, the unit of truth: a document's authority coming from who produced it, what it superseded and which verdicts bind to it, rather than from its directory or filename.
State and log
Two records, two jobs, and they must not be merged. State answers where we are now: it is single-valued, overwritten, and cheap to read. The log answers how we got here: it is append-only, never overwritten and never summarised in place.