From efb5a62f294171572fa4026d8e1879ca3da2d98f Mon Sep 17 00:00:00 2001 From: thanhnv Date: Sat, 18 Jul 2026 10:04:55 +0700 Subject: [PATCH] fix: keep goal failure reasons gate-specific --- packages/casan-harness/scripts/bash/goal-orchestrator.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/casan-harness/scripts/bash/goal-orchestrator.py b/packages/casan-harness/scripts/bash/goal-orchestrator.py index 09e9590..46863ca 100644 --- a/packages/casan-harness/scripts/bash/goal-orchestrator.py +++ b/packages/casan-harness/scripts/bash/goal-orchestrator.py @@ -802,8 +802,13 @@ def run(job_path: str) -> int: job = load_json(job_path) audit_hash = audit(job, "failed") emit(goal_id, "H5-governance", "pass", "Failed decision anchored", {"audit_hash": audit_hash}) - emit(goal_id, "H6-agentops", "error", "Orchestration failed", {"reason": reason, "latency_ms": int((time.monotonic() - started) * 1000)}) - emit(goal_id, "H7-orchestration", "blocked", "Goal workflow stopped", {"reason": reason}) + # Keep gate semantics distinct. H2 may report a patch-contract failure, + # while H6/H7 must report their own lifecycle state and retain the H2 + # error only as causal evidence. Reusing `reason` here made the UI show + # goal_patch_missing as if telemetry and orchestration independently + # failed the patch contract. + emit(goal_id, "H6-agentops", "error", "goal_orchestration_failed", {"root_reason": reason, "latency_ms": int((time.monotonic() - started) * 1000)}) + emit(goal_id, "H7-orchestration", "blocked", "goal_workflow_stopped", {"root_reason": reason}) update_job(job_path, audit_hash=audit_hash) return 2