diff --git a/plugins/omo/components/ultrawork/directive.md b/plugins/omo/components/ultrawork/directive.md index 4f2afff..a7b2a02 100644 --- a/plugins/omo/components/ultrawork/directive.md +++ b/plugins/omo/components/ultrawork/directive.md @@ -254,6 +254,32 @@ silent or ack-only, record the result as inconclusive, do not count it as approval/pass, close it if safe, and respawn a smaller `fork_turns: "none"` task with the missing deliverable. + +# Subagent-dependent transition barrier + +BEFORE advancing any state that depends on a spawned child agent, verify +the child has returned a substantive result or been recorded as +inconclusive. Moving dependent work forward without collecting child +output is a defect. + +a) **Before marking a dependent plan step complete** via `update_plan`, +verify that any spawned child agent owning evidence for that step has +returned a substantive result or been recorded as inconclusive. If a +child is still active, do NOT mark the step complete. + +b) **Before generating or verifying a plan**, wait for all spawned +research/metis/explorer agents to return. Use short `wait_agent` cycles +(<=30s each), not a single long blocking wait. + +c) **Before final answer**, check that no child agents are still active. +If any are running, close them (recording the result as inconclusive if +no output received) or wait for them. + +d) **Short-poll enforcement**: Always use short `wait_agent` cycles. +Never use a single long blocking wait. After two silent waits, send a +targeted `TASK STILL ACTIVE` follow-up. After two more silent waits, +close the child as inconclusive and respawn a smaller task if needed. + # Verification gate (TRIGGERED, NOT OPTIONAL) Trigger when ANY apply: diff --git a/plugins/omo/test/subagent-guidance.test.mjs b/plugins/omo/test/subagent-guidance.test.mjs index d602d4d..0d57876 100644 --- a/plugins/omo/test/subagent-guidance.test.mjs +++ b/plugins/omo/test/subagent-guidance.test.mjs @@ -63,6 +63,11 @@ test("#given ultrawork directive #when inspected #then reviewer fallback keeps a assert.match(text, /timeout only means no new mailbox update arrived/i); assert.match(text, /WORKING:/); assert.match(text, /single `list_agents`/); + assert.match(text, /Subagent-dependent transition barrier/); + assert.match(text, /dependent plan step complete.*update_plan/s); + assert.match(text, /short `wait_agent` cycles.*<=30s/s); + assert.match(text, /single long blocking wait.*short `wait_agent`/s); + assert.match(text, /inconclusive.*close.*child/s); }); test("#given ulw-loop workflow #when inspected #then stale review refresh keeps policy changes narrow", async () => {