From 84a3d20408c98018f39394348fcc780815922173 Mon Sep 17 00:00:00 2001 From: Bo Wu Date: Sun, 30 Aug 2026 06:44:42 -0700 Subject: [PATCH 1/2] Accept blocked external operation receipts --- src/workflow.rs | 4 +++- tests/lifecycle.sh | 22 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/workflow.rs b/src/workflow.rs index 718015d..188aa7d 100644 --- a/src/workflow.rs +++ b/src/workflow.rs @@ -1581,7 +1581,9 @@ pub fn supervisor_complete_external(id: &str) -> Result { .and_then(serde_json::Value::as_str), ) { (Some("succeeded"), Some("succeeded")) => successful_operations += 1, - (Some("failed"), Some("failed")) => failed_operations += 1, + (Some("failed"), Some("failed")) | (Some("blocked"), Some("blocked")) => { + failed_operations += 1 + } _ => { return Err(format!( "external-only completion requires consistently classified terminal receipts; {} has mismatched state and disposition", diff --git a/tests/lifecycle.sh b/tests/lifecycle.sh index 61206c5..2cdb12c 100755 --- a/tests/lifecycle.sh +++ b/tests/lifecycle.sh @@ -506,7 +506,10 @@ cat >"$EXTERNAL_STATE/operations/OP-EXTERNAL/receipt.json" <<'EOF' } } EOF -mkdir -p "$EXTERNAL_STATE/operations/OP-FAILED" "$EXTERNAL_STATE/operations/OP-NONTERMINAL" +mkdir -p \ + "$EXTERNAL_STATE/operations/OP-FAILED" \ + "$EXTERNAL_STATE/operations/OP-BLOCKED" \ + "$EXTERNAL_STATE/operations/OP-NONTERMINAL" cat >"$EXTERNAL_STATE/operations/OP-FAILED/receipt.json" <<'EOF' { "result": { @@ -522,6 +525,21 @@ cat >"$EXTERNAL_STATE/operations/OP-FAILED/receipt.json" <<'EOF' } } EOF +cat >"$EXTERNAL_STATE/operations/OP-BLOCKED/receipt.json" <<'EOF' +{ + "result": { + "structuredContent": { + "state": "blocked", + "outcome": { + "disposition": "blocked", + "terminal": true, + "retryable": false, + "code": "github_repository_inaccessible" + } + } + } +} +EOF cat >"$EXTERNAL_STATE/operations/OP-NONTERMINAL/receipt.json" <<'EOF' { "result": { @@ -570,7 +588,7 @@ assert_contains "$EXTERNAL_STATE/workflows/WF-EXTERNAL/lifecycle/lifecycle.env" assert_contains "$EXTERNAL_STATE/workflows/WF-EXTERNAL/lifecycle/events.log" \ "route=external-only" assert_contains "$EXTERNAL_STATE/workflows/WF-EXTERNAL/lifecycle/events.log" \ - $'operations=1\tfailed_operations=2' + $'operations=1\tfailed_operations=3' assert_contains "$EXTERNAL_STATE/orchestrator-result.md" \ "External operation completed with reviewed evidence." From 8e9526c46fd174996f4d57ffd7aa394581060b40 Mon Sep 17 00:00:00 2001 From: Bo Wu Date: Sun, 30 Aug 2026 06:49:36 -0700 Subject: [PATCH 2/2] Route clarification completion through supervisor --- src/authority.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/authority.rs b/src/authority.rs index 4d9d299..9adbd8d 100644 --- a/src/authority.rs +++ b/src/authority.rs @@ -78,7 +78,10 @@ impl AuthorityRequest { || (args.len() == 4 && matches!( args[1].as_str(), - "--external-only" | "--direct-response" + "--external-only" + | "--direct-response" + | "--clarification" + | "--auto-clarification" ) && args[2] == "--result-file") || (args.len() == 6 @@ -356,6 +359,32 @@ mod tests { ) .expect("direct completion request"); assert!(direct_completion.authorized_for(config::ORCHESTRATOR_UID)); + for route in ["--clarification", "--auto-clarification"] { + let clarification_completion = AuthorityRequest::from_cli( + "orchestrator", + &strings(&[ + "complete", + route, + "--result-file", + "/state/clarification.md", + ]), + ) + .expect("clarification completion request"); + assert!(clarification_completion.authorized_for(config::ORCHESTRATOR_UID)); + assert!(!clarification_completion.authorized_for(config::READER_UID)); + assert_eq!( + clarification_completion.into_cli(), + ( + "orchestrator".to_string(), + strings(&[ + "complete", + route, + "--result-file", + "/state/clarification.md", + ]), + ) + ); + } let read_only_completion = AuthorityRequest::from_cli( "orchestrator", &strings(&[