Gate failures → fixes
Each audit gate's verbatim failure string mapped to what it means and the doc that explains the fix — the lookup an agent reads straight from red CI output to the change.
When an audit gate goes red it names the file, the symbol, and the missing fact in its output. This page maps each gate's failure string to what it means and the fix, so an agent — or a human — reading CI output can go from the red line to the change without re-deriving it.
Every gate exits 0 clean, 1 on a contract failure, 2 on a
config or IO error, and prints a bracketed, greppable prefix. Grep the
prefix; match the row. This is the companion to
Audit gates (the catalog by subsystem) and
CI enforcement (the catalog by contract
clause) — this page is indexed by the string you actually see.
You added a graph node
| Failure string (grep this) | What it means → fix |
|---|---|
[graph-stages] Node "<name>" missing stageId in NODE_STAGE_MAP | The node has no lattice stage. Declare stageId in the node metadata (plugin path), or add a NODE_STAGE_MAP entry in topology.ts (upstream path). See Extending Pleach and the new-node checklist. |
[graph-stages] FORBIDDEN edge <from> (<stage>) → <to> (<stage>) | An edge crosses the lattice outside the nine allowed patterns. Don't route directly — write a state field the next stage's nodes subscribe to. See the lattice gate. |
[graph-stages] Singleton violated: "synthesizer" registered N times | Two nodes occupy the synthesize stage; it's a singleton. Move recovery or post-synthesis shaping to a post-turn stream filter, not a graph node. |
The gate also prints a summary line — [graph-stages] FAIL — N forbidden, N unstaged of N nodes / N edges — so the count in the
failure tells you how many sites to fix.
You added an event type or a writer
| Failure string (grep this) | What it means → fix |
|---|---|
[audit:c8-event-type-allowlist-coverage] FAIL — N event type(s) missing from SCRUBBABLE_FIELDS | A new event type has no redaction decision. Add an entry to scrub/allowlist.ts — [] is valid and documents "no fields to redact." See Event-type allowlist coverage. |
[C8:unscrubbed-event-type] | The runtime fail-closed marker for the same gap — an event type reached the writer with no allowlist entry. Same fix: register the type in scrub/allowlist.ts. (This is emitted at write time, not by the gate's stdout.) |
[audit:c8-union-member-has-producer] FAIL — N union member(s) with no producer | You declared an EventLogInput member that nothing writes. Add a producer that calls writer.write({ type: "<type>", ... }), or add a documented baseline entry. See Event log. |
You changed the audit row
| Failure string (grep this) | What it means → fix |
|---|---|
[auditable-call-shape] FAIL — shape diverged from baseline | The AuditableCall TS wire shape changed. If intentional, run the gate with --update-fingerprint and bump AuditRecordVersion if any field's meaning moved. See the AuditableCall row. |
[auditable-call-version] FAIL rule 3: fingerprint advanced ... but AuditRecordVersion did not move | You changed the row shape without versioning it — the silent-breaking-change the gate exists to catch. Bump export type AuditRecordVersion. If you were trying to add a column, don't: use the pluginPayloads slot instead — see the locked row. |
You added or changed a plugin hook
These fire on the substrate's own hook set and on sibling @pleach/*
SKUs — the upstream surface, not a host plugin that merely uses
hooks.
| Failure string (grep this) | What it means → fix |
|---|---|
[audit:plugin-contract-completeness] FAIL — N missing-collector, N novel awaiting-consumer | A contributeX hook has no paired PluginManager.collectX accessor, or a collector with no consumer. Add both, or baseline an intentional bypass. The run also emits the probe [UXParity:audit-plugin-contract-completeness:run:drift]. See Plugin contract. |
[audit:plugin-hook-category-assigned] FAIL — N hook(s) declared on HarnessPlugin but NOT classified into any namespace bucket | A new hook belongs to none of the nine namespaces. Add it to a bucket in plugins/namespaces.ts. See contribution namespaces. |
Reading the loop
The failure string is the correction signal. An agent extending the runtime runs the gate, reads the named fact (a stage, a producer, an allowlist entry, a version bump), applies it, and re-runs — green means the addition preserved the ledger contract. That loop is the point of agent-driven self-extension: the gate output is legible enough to act on without a human in the middle.
Where to go next
CI enforcement of the audit contract
The named audit gates that make the auditability and replayability contract load-bearing in CI — what each clause promises, the gate that fails the build when it breaks, and where the gates run.
First-publish packaging contract
Dual ESM/CJS emit, types-first exports ordering, tsup dir-style entries, tsc-built DTS, sourcemap-free tarballs, peer-dep tightening — the package-build conventions every @pleach/* SKU follows at 1.0.