{"record":{"id":"75035539cda40d23","repo":"Hmbown/CodeWhale","slug":"repeated-coordination-interrupt","errorCode":null,"errorMessage":"repeated coordination interrupt","messagePattern":"repeated coordination interrupt","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/tests.rs","lineNumber":6708,"sourceCode":"                .interrupt_child(&agent_id, Some(caller), \"forbidden\".into())\n                .is_err()\n        );\n    }\n    manager.record_worker_event(\n        &agent_id,\n        AgentWorkerStatus::RunningTool,\n        Some(\"step 2/8: running tool 'read_file'\".to_string()),\n        Some(2),\n        Some(\"read_file\".to_string()),\n    );\n\n    let reason = \"parent rerouted this lane\".to_string();\n    let (prior, first) = manager\n        .interrupt_child(&agent_id, Some(\"agent_parent\"), reason.clone())\n        .expect(\"first coordination interrupt\");\n    let (_, second) = manager\n        .interrupt_child(&agent_id, Some(\"agent_parent\"), reason.clone())\n        .expect(\"repeated coordination interrupt\");\n    assert_eq!(prior.status, SubAgentStatus::Running);\n    assert!(matches!(\n        first.status,\n        SubAgentStatus::Interrupted(ref actual) if actual == &reason\n    ));\n    assert_eq!(second.status, first.status);\n    assert_eq!(\n        first\n            .checkpoint\n            .as_ref()\n            .map(|checkpoint| (checkpoint.reason.as_str(), checkpoint.steps_taken)),\n        Some((\"test_checkpoint\", 2))\n    );\n\n    let completion = completion_rx\n        .try_recv()\n        .expect(\"parent interruption fan-in\");\n    assert!(completion.payload.contains(r#\"\"status\":\"interrupted\"\"#));","sourceCodeStart":6690,"sourceCodeEnd":6726,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/subagent/tests.rs#L6690-L6726","documentation":"This is a test panic from `Option::expect`/`Result::expect`: `interrupt_child` returned None/Err on the second call, so the test asserting that repeated coordination interrupts from the same parent succeed never got a value. The library throws expect panics like this when an internal manager API that the test contract requires to succeed does not.","triggerScenarios":"Calling `SubAgentManager::interrupt_child(&agent_id, Some(\"agent_parent\"), reason)` a second time for an already-interrupted or non-existent agent, when the implementation fails to treat a repeated interrupt as idempotent.","commonSituations":"Regression in the subagent manager's interrupt path after refactoring terminal-state transitions; running the subagent test suite in crates/tui/src/tools/subagent/tests.rs after changing status handling so the second interrupt errors instead of returning the same Interrupted checkpoint.","solutions":["Ensure `interrupt_child` is idempotent: a repeated interrupt on an already-Interrupted agent returns the same checkpoint rather than failing.","Check that the agent_id was inserted into `manager.agents` before the first interrupt and was not removed by the first interrupt.","Run the failing test to inspect which call returned None/Err and diff against recent changes in the interrupt implementation."],"exampleFix":"// before: second call errors on already-interrupted agent\n// after: idempotent interrupt in manager\nif matches!(self.agents.get(id).map(|a| &a.status), Some(SubAgentStatus::Interrupted(_))) {\n    return self.last_interrupt_checkpoint(id).ok_or_else(|| anyhow!(\"unknown agent\"));\n}","handlingStrategy":"try-catch","validationCode":"// before calling\nassert!(manager.agents.contains_key(&agent_id), \"agent must exist before interrupt\");","typeGuard":"fn is_interrupted(s: &SubAgentStatus) -> bool { matches!(s, SubAgentStatus::Interrupted(_)) }","tryCatchPattern":"match manager.interrupt_child(&agent_id, Some(\"agent_parent\"), reason.clone()) {\n    Ok(cp) => cp,\n    Err(e) => panic!(\"repeated coordination interrupt failed: {e:#}\"),\n}","preventionTips":["Design interrupt_child to be idempotent for repeated interrupts from the same parent","Add a unit test for the double-interrupt path whenever status transitions change","Never remove an agent from the registry as a side effect of interrupt"],"tags":["test-assertion","subagent","idempotency","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}