[Bug] Safety classifier blocks a workflow's own receipt-persistence agent as "self-approval / CI bypass" — regardless of receipt content, and even for the fail-closed marker
Environment
- Claude Code 2.1.215 (incident 2026-07-21); an earlier related class on 2.1.214 (2026-07-18, a workflow's Phase-4 implementer agent blocked as "gate bypass")
- macOS (darwin 25.5.0)
- A
Workflow-tool pipeline implementing a commit gate: it spawns isolated read-only reviewer agents over an uncommitted diff, computes a pass/fail deterministically in the workflow JS from those agents' structured results, then must persist a small receipt JSON that agitcommit-msg hook consumes at commit time.
Summary
The safety classifier blocks the receipt-persistence step of a legitimately-passing gate run. The gate's three adjudication agents all returned green; only the final file-write is blocked, which makes the whole lane unusable on the green path (every passing run fails to persist its receipt).
Two variants were tried; both blocked:
- Receipt carries the verdict. The workflow JS computes
ok = (suite ∧ red-first ∧ ¬reviewer-veto ∧ ¬marshal-red)from three independent agents, then a mechanical agent writes{ok:true, …}to.aegis/<gate>_receipt.json. The writer agent is blocked as self-approval / CI bypass. The fail-closed fallback (write anok:falsetombstone so a stale receipt can't bless a later commit) is also blocked, as audit-tampering. So even the defensive write is refused.
- Receipt carries only measurements; a deterministic script derives the verdict. We restructured so the agent writes ONLY the four measured facts (
suiteOk,redFirstProven,reviewerRed,marshalRed) +complete:true— nook— and a separate non-agent script (the commit-msg hook) computes the pass. Still blocked. The classifier's stated reason was, in substance: "a sub-agent is instructed to write test results, as established fact, into a file a downstream commit gate consumes." i.e. it blocks the act of an LLM agent persisting a gate receipt, independent of whether the content is a verdict or raw facts.
Why the agent is unavoidable
The Workflow script sandbox has no filesystem access — a probe confirmed import() of node:fs throws "import() is not available in workflow scripts.", so the JS cannot write the receipt directly. Persisting anything from a workflow therefore requires a sub-agent. The gate's receipt is the one artifact it must persist for the commit hook to consume, and that persistence is exactly what the classifier blocks. There is no in-workflow workaround.
Impact
An automated gate that (a) runs its own adjudication in isolated agents and (b) records the outcome for a downstream check cannot complete on a machine where the safety classifier is active — every passing run dies at receipt-write. The only workarounds are out-of-band: a human hand-writes the receipt, or the commit carries an override trailer citing the (successful) gate run. Both defeat the point of an unviolable automated gate.
Expected behavior
An agent persisting a structured record produced by earlier workflow steps — especially a fail-closed marker — should not be classified as self-approval / audit-tampering. If the concern is that an agent could fabricate a "pass," note that the fabrication risk is identical whether the value is written by an agent or by a script the agent's output feeds; blocking the persistence step does not close it, it only breaks honest automation.
Related
- The 2.1.214 class (a workflow's implementer agent blocked as "gate bypass") — same family: the classifier attributing an attack pattern to a workflow-internal agent doing its assigned mechanical job.
- Companion report on a different platform-internal mechanism (workflow def-cache staleness) filed separately.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗