pleach
Reference

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_MAPThe 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 timesTwo 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_FIELDSA 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 producerYou 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 baselineThe 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 moveYou 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-consumerA 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 bucketA 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

On this page