You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up from #6380 (PR #6395). The fix for #6380 adds a post-hoc Completed -> Failed correction for spawn-dispatched orchestration tasks whose tool calls all failed (DagScheduler::correct_completed_to_failed_if_all_tool_calls_failed, crates/zeph-orchestration/src/scheduler/tick/mod.rs). This correction is deliberately status-only: it flips TaskStatus and annotates TaskResult::output, but does not call dag::propagate_failure, does not touch cascade_detector/lineage_chains, and does not recompute overall graph status.
This is a legitimate, deliberate tradeoff (avoids double-counting CascadeDetector::RegionHealth, since the task was already recorded as a success moments earlier via record_outcome(true) and downstream tasks were already unblocked to Ready). It is not a regression — pre-fix, the same all-failed spawn task was Completed with the same downstream behavior; post-fix, only the task's own status row improved.
However, this creates a real behavioral divergence: two functionally-identical "all tool calls failed" tasks produce different plan-level outcomes depending purely on dispatch path:
RunInline path: total failure routes through handle_failed_outcome, which calls propagate_failure (cancels downstream dependents) and can drive graph.status = GraphStatus::Failed.
Spawn path (the more common real-world path — .zeph/agents/*.md sub-agents): downstream dependents that were already unblocked before the correction lands continue to run and consume the failed task's (empty) output; GraphStatus can stay Completed even though a constituent task is Failed.
Expected Behavior
Spawn-path total-failure correction should have the option to also propagate to dependents (cancel or otherwise handle them) and/or be reflected in overall GraphStatus, giving parity with the RunInline path — or, if full propagation is judged not worth the RegionHealth double-counting risk, the divergence should be a deliberate, documented product decision rather than an accidental side effect of how the fix was staged.
Observe: any downstream task depending on it still ran (was unblocked to Ready before the correction), and /status's overall plan summary can still report success (GraphStatus::Completed).
See PR #6395's impl-critic review (.local/handoff/2026-07-17T15-51-55-critic.md, finding S1) and the reviewer's confirmation (.local/handoff/2026-07-17T16-26-35-review.md). Independently reproduced at the integration-test level in the same PR's tester handoff (.local/handoff/2026-07-17T16-04-02-testing.md) — a test's initial (wrong) assertion expected GraphStatus::Failed and had to be corrected to document the actual (accepted) behavior.
Description
Follow-up from #6380 (PR #6395). The fix for #6380 adds a post-hoc
Completed -> Failedcorrection for spawn-dispatched orchestration tasks whose tool calls all failed (DagScheduler::correct_completed_to_failed_if_all_tool_calls_failed,crates/zeph-orchestration/src/scheduler/tick/mod.rs). This correction is deliberately status-only: it flipsTaskStatusand annotatesTaskResult::output, but does not calldag::propagate_failure, does not touchcascade_detector/lineage_chains, and does not recompute overall graph status.This is a legitimate, deliberate tradeoff (avoids double-counting
CascadeDetector::RegionHealth, since the task was already recorded as a success moments earlier viarecord_outcome(true)and downstream tasks were already unblocked toReady). It is not a regression — pre-fix, the same all-failed spawn task wasCompletedwith the same downstream behavior; post-fix, only the task's own status row improved.However, this creates a real behavioral divergence: two functionally-identical "all tool calls failed" tasks produce different plan-level outcomes depending purely on dispatch path:
RunInlinepath: total failure routes throughhandle_failed_outcome, which callspropagate_failure(cancels downstream dependents) and can drivegraph.status = GraphStatus::Failed..zeph/agents/*.mdsub-agents): downstream dependents that were already unblocked before the correction lands continue to run and consume the failed task's (empty) output;GraphStatuscan stayCompletedeven though a constituent task isFailed.Expected Behavior
Spawn-path total-failure correction should have the option to also propagate to dependents (cancel or otherwise handle them) and/or be reflected in overall
GraphStatus, giving parity with theRunInlinepath — or, if full propagation is judged not worth theRegionHealthdouble-counting risk, the divergence should be a deliberate, documented product decision rather than an accidental side effect of how the fix was staged.Reproduction Steps
[orchestration] enabled = true, defaultverify_completeness = false.Failed(post-orchestration /plan task marked completed despite policy-blocked tool failures (silent, no verification) #6380 fix).Readybefore the correction), and/status's overall plan summary can still report success (GraphStatus::Completed).Environment
Logs / Evidence
See PR #6395's impl-critic review (
.local/handoff/2026-07-17T15-51-55-critic.md, finding S1) and the reviewer's confirmation (.local/handoff/2026-07-17T16-26-35-review.md). Independently reproduced at the integration-test level in the same PR's tester handoff (.local/handoff/2026-07-17T16-04-02-testing.md) — a test's initial (wrong) assertion expectedGraphStatus::Failedand had to be corrected to document the actual (accepted) behavior.