Give the board agent real write authority, behind a flag, governed by the gates - #19
Merged
Merged
Conversation
… the gates PRD §5 says the board agent holds "authority to write". Production means that literally — its board agent runs a create command and a guard layer decides whether the command lands. This repo shipped a board agent that could not write at all, and AGENTS.md justified that by claiming production's agent only proposed. That claim was wrong, and it was the sentence holding the divergence in place. BOARD_AGENT_WRITES (off by default) is the production shape. On, the board agent gets write tools behind governedTracker, which rebuilds every write it originates into a manifest item and re-runs the full deterministic gate set over it — a write the gates refuse becomes a hold, not a card. Off, none of that code is in the process and Pass 2c writes as before. Off by default on purpose. Nothing in this layer has governed a real board the way the pipeline has, and defaulting a model into the write path of a repo people clone and point at their own tracker is not a claim this repo has earned. The injection guarantee differs per mode and SECURITY.md now states both rather than stating the stronger one twice: "cannot author a write" by default, and "cannot author a write the gates would not already have approved" with the flag on. The second is smaller. Saying so is the point. Evidence is stricter here than on the pipeline path. The gate wants comment history cited; on the pipeline that citation is the model's own claim parsed out of prose, and here it is a fact — readComments reports whether the agent actually called get_task_comments on that card. Two bugs found while building it, both kept fixed: - a subtask create hardcoded tier2Cited: false, so no agent-originated subtask could ever cite the parent it had just read, and every one was unwritable - the write loop swallowed a thrown error, so a missing cassette produced a tidy "0 created" and left Pass 2d to infer the problem from four mismatches. A loop that wrote nothing now rethrows; one that wrote something reports what landed Default paths are byte-identical: 1018 tests pass, and all five demo modes replay with zero cassette drift. The tool list is part of the prompt fingerprint, so that zero is what proves the flag is not leaking into the default path.
4 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
PRD §5 says the board agent holds "authority to write". Production means that literally — its board
agent runs a create command and a guard layer decides whether the command lands.
This repo shipped a board agent that could not write at all, and
AGENTS.mdjustified that byclaiming production's board agent only proposed and never performed writes. That claim was
wrong, and it was the sentence holding the divergence in place. Both are fixed here.
What
BOARD_AGENT_WRITES, off by default. On, the board agent gets write tools behind a newgovernedTracker, which rebuilds every write it originates into aCategorizationItemand re-runsthe same
applyGatesthe pipeline's own answer faced. A write the gates refuse becomes a hold,not a card. Off, none of that code is in the process and Pass 2c writes exactly as before.
Off by default on purpose: nothing in this layer has governed a real board the way the pipeline has,
and defaulting a model into the write path of a repo people clone and point at their own tracker is
not a claim this repo has earned.
The security claim, stated honestly
The injection guarantee genuinely differs per mode, so
SECURITY.mdnow states both instead ofstating the stronger one twice:
The second is smaller. Saying so plainly is the point.
Evidence is stricter here than on the pipeline path
The evidence gate wants comment history cited. On the pipeline path that citation is the model's own
claim, parsed out of its prose. Here it is a fact:
readCommentsreports whether the agent actuallycalled
get_task_commentson that card. A model that says it checked but did not gets held.Two bugs found while building it
tier2Cited: false, so no agent-originated subtask could ever cite theparent it had just read — every one was unwritable. Would have read as "the gate is strict" rather
than as the bug it was.
0 createdand leftPass 2d to infer the problem from four mismatches. That is exactly the quiet-wrong-number failure
the cassette client refuses to ship. A loop that wrote nothing now rethrows; one that wrote
something reports what actually landed.
Verification
npx tsc --noEmitcleannpm run lintcleannpm test— 1018 passing (1000 before, 18 new)npm run evalcleanCONTRIBUTING.md:44-49— removingapplyGatesfrom thegoverned path fails 7 tests
The tool list is part of the prompt fingerprint, so zero drift is the proof the flag is not leaking
into the default path — that was the one failure mode this design existed to prevent.
Not included
No cassettes for the new mode. Recording them needs live keys against both providers, so the mode is
proven by unit tests with scripted models and
npm run demo -- --agents --board-writesfails loudlyon a missing cassette, which is the correct behaviour rather than a silent green run.