Summary
Two linked problems in the test_engineer path.
- When
test_runner is called with scope: "convention" and no files, its error text recommends scope: "all". But scope: "all" is blocked unless SWARM_ALLOW_FULL_SUITE is set, and the test_engineer prompt itself forbids it. An agent that follows the tool's own advice cannot succeed, and a model that keeps omitting files loops until the repetition breaker fires.
- The verdict the agent then reports,
[TESTED] ... SKIPPED, is treated as stage_b_failed. That clears the reviewer's APPROVED proof and moves the task to rework_required. A tool-argument problem is scored as a code failure and forces a coder rework of code that is correct.
Version
opencode-swarm@7.179.1 on OpenCode 1.18.21, Windows 11. The relevant files are byte-identical on the 7.180.0 release branch.
Reproduction
- Python project with
requirements.txt naming pytest, one passing test file test_calc.py.
- Dispatch
test_engineer with a normal Stage B delegation that names the test file but does not spell out tool arguments.
- With one model (Kimi K2.7 Code in our runs) the agent calls
test_runner with scope: "convention" and no files, 10 to 11 times, until the breaker stops it. Each call returns:
scope "convention" and "graph" require explicit files or targets array - omitting both causes unsafe full-project discovery
with a hint to use scope: "all".
- The agent reports
VERDICT: FAIL [0/0 tests run] or SKIPPED.
- The task moves to
rework_required and the reviewer's approval is deleted, although python -m pytest passes.
Two other models (DeepSeek V4.1 Flash, GLM-5.3 Flash) made one correct call with files: ["test_calc.py"] from the identical prompt, so the loop is model-dependent, but the two plugin behaviors above turn a recoverable argument mistake into a workflow dead end.
Where it happens
src/tools/test-runner.ts: the guard that blocks scope: "all" without SWARM_ALLOW_FULL_SUITE (around line 3150) and the error text that recommends "all" (around line 3169).
src/agents/test-engineer.ts (around lines 91, 100, 215): the prompt marks scope: "all" as prohibited.
src/hooks/delegation-gate.ts (around lines 5952-5966): any non-PASS TESTED verdict is handled as stage_b_failed.
src/hooks/gate-evidence.ts (around lines 611-628): stage_b_failed clears the reviewer proof and sets rework_required.
Expected
- The error text for a missing
files array should say to pass files, not recommend a scope that is blocked.
SKIPPED (tests not run) should be distinguished from FAIL (tests ran and failed). A not-run result should leave the task in a retryable Stage B state without deleting the reviewer approval, so the architect can re-dispatch the test gate instead of a coder.
Impact
Correct, reviewed code is sent back for rework, and (with issue #2755 below) the task cannot recover from that state without a human command.
Related: #2174 (SKIPPED for named test targets, a different cause with the same symptom).
Summary
Two linked problems in the
test_engineerpath.test_runneris called withscope: "convention"and nofiles, its error text recommendsscope: "all". Butscope: "all"is blocked unlessSWARM_ALLOW_FULL_SUITEis set, and thetest_engineerprompt itself forbids it. An agent that follows the tool's own advice cannot succeed, and a model that keeps omittingfilesloops until the repetition breaker fires.[TESTED] ... SKIPPED, is treated asstage_b_failed. That clears the reviewer'sAPPROVEDproof and moves the task torework_required. A tool-argument problem is scored as a code failure and forces a coder rework of code that is correct.Version
opencode-swarm@7.179.1on OpenCode 1.18.21, Windows 11. The relevant files are byte-identical on the 7.180.0 release branch.Reproduction
requirements.txtnaming pytest, one passing test filetest_calc.py.test_engineerwith a normal Stage B delegation that names the test file but does not spell out tool arguments.test_runnerwithscope: "convention"and nofiles, 10 to 11 times, until the breaker stops it. Each call returns:with a hint to use
scope: "all".VERDICT: FAIL [0/0 tests run]orSKIPPED.rework_requiredand the reviewer's approval is deleted, althoughpython -m pytestpasses.Two other models (DeepSeek V4.1 Flash, GLM-5.3 Flash) made one correct call with
files: ["test_calc.py"]from the identical prompt, so the loop is model-dependent, but the two plugin behaviors above turn a recoverable argument mistake into a workflow dead end.Where it happens
src/tools/test-runner.ts: the guard that blocksscope: "all"withoutSWARM_ALLOW_FULL_SUITE(around line 3150) and the error text that recommends"all"(around line 3169).src/agents/test-engineer.ts(around lines 91, 100, 215): the prompt marksscope: "all"as prohibited.src/hooks/delegation-gate.ts(around lines 5952-5966): any non-PASSTESTED verdict is handled asstage_b_failed.src/hooks/gate-evidence.ts(around lines 611-628):stage_b_failedclears the reviewer proof and setsrework_required.Expected
filesarray should say to passfiles, not recommend a scope that is blocked.SKIPPED(tests not run) should be distinguished fromFAIL(tests ran and failed). A not-run result should leave the task in a retryable Stage B state without deleting the reviewer approval, so the architect can re-dispatch the test gate instead of a coder.Impact
Correct, reviewed code is sent back for rework, and (with issue #2755 below) the task cannot recover from that state without a human command.
Related: #2174 (SKIPPED for named test targets, a different cause with the same symptom).