Repository navigation
Coco verifies its own work.
Twenty-two findings from two monitored /coco:loop runs turned out to be one defect wearing different clothes: the workflow made a claim and never checked it. It ran close and never read it back. It read max_review_iterations and never counted. Its import checklist asserted every task had an issue_key when none did. Its reviewer reported measurements it hadn't taken. Its own fixes shipped correct, merged, and inert.
Every one was found by a human watching — which is precisely the condition coco exists to remove. A workflow that cannot check its own work isn't autonomous; it's unsupervised, and the difference only shows up when nobody is looking.
So: every claim — about state, evidence, budget or delivery — is verified at the point of claiming, and the loop stops when it cannot verify.
Fixes
State. close, update and epic-close re-read after writing and exit non-zero if the record isn't what was written. _coco_write_record refuses to write to an unparseable file and checks its rewrite before the mv — one malformed line previously made the update-vs-append probe read as "record absent", appended a duplicate, printed success and exited 0. epic-close refuses over unfinished tasks (--force overrides): an epic closed over an in_progress task makes it unreachable, since ready selects only pending.
Recovery. New coco-tracker reconcile [--fix] finds tasks left in_progress by an interrupted run, epics closed over unfinished work, and orphaned tasks. The Pre-Loop Gate runs it, so a loop killed by a usage limit, crash or Ctrl-C is recoverable instead of permanently stuck reporting "all remaining tasks are blocked" with nothing blocked.
Bounds. New coco-tracker round <key> --bump counts review rounds in .coco/state/. max_review_iterations was read from config and never compared to anything, because the count lived in the model's head. A new Review Exhausted exit condition stops when a PR can't converge, rather than logging a warning and carrying on.
One stopping rule replaces two opposite bugs: stop when continuing cannot change the outcome without a human, and never otherwise. That covers both stopping to narrate ("Holding for the review verdict" — every clause true, still wrong, because the reviewer returns to the loop) and failing to stop when a PR had burned its budget.
Evidence. Every code-reviewer finding states how it's known — observed with the command run, or inferred. A reviewer may not report output from a command it didn't run. Verification harnesses must prove themselves with a control (a null change must report SURVIVED) and a clean baseline. Two new TestValue triggers, including a test that derives its expected value by reimplementing the behaviour under test rather than calling it.
Budgets. ## Test Strategy carries an Expected count per FR, a Ceiling, and a Feature-review allowance. Constitution principles carry a Bounds line beside MUST and Rationale — without it a principle can require and never limit, so principles accumulate as ratchets.
Speed. The loop starts the next non-overlapping task while a review runs, instead of blocking 7–19 minutes per review. Four preconditions, including a clean reconcile — pipelining over unverified state corrupts twice as fast. Re-reviews are scoped to the incremental diff.
Corrections to 0.5.0
pause_on_error: falsewas documented as skipping a failed task. It also stranded it, because nothing resetin_progress. Fixed byreconcile.- "The orchestrator cannot bound its wait on a dispatched agent; markdown cannot express a timeout" was wrong.
TaskOutputtakesblockandtimeout, and a timeout returnsstatus: runningplus partial output. Corrected everywhere, with an explicit instruction not to add an abandon-deadline.
What is measured, and what is not
The test-budget ceiling has a control: unbudgeted produced 1,726 test lines against 388 of source with a core mechanic untested; a stated ceiling produced 44 against 40 with the overage self-reported. Treat that as known.
The speed claim does not. It has arithmetic but no run against its 123-minute baseline, and CLAUDE.md labels it a hypothesis until one exists.
New config
issue_tracker.per_task_issues, pr.review.tiers, and a path-glob map form for testing.test_command. All default to previous behaviour.
Tests
84 tracker (was 46), 9 hooks, 26 setup-config (was 0). Every mechanical change is unit-tested and mutation-tested.
Upgrade
/plugin
Then update coco, and confirm the path contains /0.6.0/:
which coco-trackerThen in each existing project:
/coco:setup migrate
.coco/config.yaml is copied once at setup and never re-read, so the new keys and defaults reach an existing project only through migrate — which now commits the change, or says plainly that it hasn't.
Full Changelog: v0.5.0...v0.6.0