Summary
A critic dispatch made before or during a task, whose prompt text contains a single plan task id, is recorded as a required critic gate on that task. The next accepted coder mutation clears the gate proof but keeps the requirement, and no later step ever re-records it. The task can then never reach complete, even on an otherwise perfect run.
The common trigger is the default plan critic (critic_pre_plan: true): the architect pastes the plan text into the critic prompt, the plan contains 1.1, and the review of the plan becomes a per-task gate on task 1.1.
Version
opencode-swarm@7.179.1 on OpenCode 1.18.21, Windows 11. The relevant source files are byte-identical on the 7.180.0 release branch (diffed 2026-09-13), so this is expected to reproduce there too.
Reproduction
- One-task plan (task
1.1). Leave critic_pre_plan at its default (true).
- Architect dispatches
critic for the plan review and inlines the plan text (which contains the string 1.1) in the prompt, without an explicit task_id.
- The critic returns
APPROVED.
.swarm/evidence/task-gate-requirements/1.1.jsonl now holds a gate_recorded row for critic.
- Coder implements task 1.1; the mutation is accepted.
check_gate_status for 1.1 now lists critic in required_gates with no proof. Nothing the architect can call re-records it: a second critic dispatch during the open task records again and is cleared again by the next mutation, and approve_plan_critic is scoped to the plan gate, not the per-task gate.
update_task_status to complete is refused for the missing critic gate.
Reproduced twice in live runs and once with an offline replay against the 7.179.1 reducer (script available on request).
Observed
ci --json on such a run:
"task 1.1 gates": "missing gate evidence: critic, reviewer, test_engineer; workflow state rework_required is not terminal"
Where it happens
src/hooks/task-id-resolver.ts (around lines 54-56 and 255-271): the plan policy resolves a task id from free text in the dispatch prompt.
src/hooks/delegation-gate.ts (around lines 6204-6259): every gate agent, including critic and critic_sounding_board, is recorded through recordGateEvidence against the resolved task id.
src/hooks/gate-evidence.ts: clearWorkflowGateProof (around 520-531) drops the critic proof on accepted_mutation (around 869-871), while maybeExpandRequiredGates (around 474-486) keeps the requirement.
Expected
Either a plan-level critic review is not attributed to a task at all (it reviews the plan, not the task), or an attributed critic gate that was already satisfied survives an accepted mutation, or the architect has a tool to re-satisfy it. Any of the three would remove the dead end.
Impact
A one-task plan with the default gate profile can wedge at completion after correct, reviewed, tested work. The only workaround we found is critic_pre_plan: false plus a rule that the architect never dispatches critic or critic_sounding_board while a task is open, which removes the plan review entirely.
Related: #2703 (a critic verdict that has nowhere to be persisted; that one now has approve_retry_sounding_board, but it does not cover this gate).
Summary
A
criticdispatch made before or during a task, whose prompt text contains a single plan task id, is recorded as a requiredcriticgate on that task. The next accepted coder mutation clears the gate proof but keeps the requirement, and no later step ever re-records it. The task can then never reachcomplete, even on an otherwise perfect run.The common trigger is the default plan critic (
critic_pre_plan: true): the architect pastes the plan text into the critic prompt, the plan contains1.1, and the review of the plan becomes a per-task gate on task 1.1.Version
opencode-swarm@7.179.1on OpenCode 1.18.21, Windows 11. The relevant source files are byte-identical on the 7.180.0 release branch (diffed 2026-09-13), so this is expected to reproduce there too.Reproduction
1.1). Leavecritic_pre_planat its default (true).criticfor the plan review and inlines the plan text (which contains the string1.1) in the prompt, without an explicittask_id.APPROVED..swarm/evidence/task-gate-requirements/1.1.jsonlnow holds agate_recordedrow forcritic.check_gate_statusfor 1.1 now listscriticinrequired_gateswith no proof. Nothing the architect can call re-records it: a second critic dispatch during the open task records again and is cleared again by the next mutation, andapprove_plan_criticis scoped to the plan gate, not the per-task gate.update_task_statustocompleteis refused for the missingcriticgate.Reproduced twice in live runs and once with an offline replay against the 7.179.1 reducer (script available on request).
Observed
ci --jsonon such a run:Where it happens
src/hooks/task-id-resolver.ts(around lines 54-56 and 255-271): the plan policy resolves a task id from free text in the dispatch prompt.src/hooks/delegation-gate.ts(around lines 6204-6259): every gate agent, includingcriticandcritic_sounding_board, is recorded throughrecordGateEvidenceagainst the resolved task id.src/hooks/gate-evidence.ts:clearWorkflowGateProof(around 520-531) drops the critic proof onaccepted_mutation(around 869-871), whilemaybeExpandRequiredGates(around 474-486) keeps the requirement.Expected
Either a plan-level critic review is not attributed to a task at all (it reviews the plan, not the task), or an attributed critic gate that was already satisfied survives an accepted mutation, or the architect has a tool to re-satisfy it. Any of the three would remove the dead end.
Impact
A one-task plan with the default gate profile can wedge at completion after correct, reviewed, tested work. The only workaround we found is
critic_pre_plan: falseplus a rule that the architect never dispatchescriticorcritic_sounding_boardwhile a task is open, which removes the plan review entirely.Related: #2703 (a critic verdict that has nowhere to be persisted; that one now has
approve_retry_sounding_board, but it does not cover this gate).