Commit 43c3f0503b1bca667ee96f4912bcf7384ed13597
1 parent
25ee708e
Give test_script verify failures their own blocked_reason
ConsistencyCheckFailedError is now raised by both the PRD-consistency check and the test_script mechanical compile-check (07a0a27), but scheduler._blocked_reason_for still labeled every instance 'prd_consistency_check_failed', misleadingly blaming the PRD for test_script node failures. Distinguishes by node_id substring match (see docstring for the ponytail ceiling/upgrade path). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Showing
2 changed files
with
33 additions
and
0 deletions
src/scheduler.py
| ... | ... | @@ -89,6 +89,25 @@ _ROUTABLE_EXCEPTIONS = tuple(exc for exc, _ in _BLOCKED_REASON_FOR_EXCEPTION) |
| 89 | 89 | |
| 90 | 90 | |
| 91 | 91 | def _blocked_reason_for(exc): |
| 92 | + """2026-08-07: `ConsistencyCheckFailedError` used to be raised only by | |
| 93 | + the PRD-internal-contradiction check, but commit 07a0a27 (2026-08-06) | |
| 94 | + generalized the same exception/retry machinery to the test_script | |
| 95 | + mechanical compile-check too -- without this, both show up in the | |
| 96 | + console as the same misleading 'prd_consistency_check_failed' label | |
| 97 | + (see docs/todo/validator-test-script-narrative-output-issue.md), even | |
| 98 | + when the real failure has nothing to do with the PRD. | |
| 99 | + ponytail: distinguishes by substring-matching the failing node's LLM- | |
| 100 | + chosen node_id (e.g. 'n_test_script'/'validator_test_script') rather | |
| 101 | + than a real typed discriminator threaded through verify_fn -- good | |
| 102 | + enough because every real graph_manifest observed so far names its | |
| 103 | + test_script node descriptively; ceiling is a node named ambiguously | |
| 104 | + silently falling back to the PRD label. Upgrade path if that's ever | |
| 105 | + wrong in practice: have verify_fn return a third 'kind' value instead | |
| 106 | + of inferring from node_id text.""" | |
| 107 | + if isinstance(exc, work_graph_orchestrate.ConsistencyCheckFailedError): | |
| 108 | + if "test_script" in (exc.node_id or ""): | |
| 109 | + return "test_script_verification_failed" | |
| 110 | + return "prd_consistency_check_failed" | |
| 92 | 111 | for exc_type, reason in _BLOCKED_REASON_FOR_EXCEPTION: |
| 93 | 112 | if isinstance(exc, exc_type): |
| 94 | 113 | return reason | ... | ... |
src/test_scheduler.py
| ... | ... | @@ -349,6 +349,20 @@ class ConsistencyCheckFailedRoutingTest(RoutableExceptionTestBase): |
| 349 | 349 | self.assertEqual(result["blocked_reason"], "prd_consistency_check_failed") |
| 350 | 350 | self._assert_task_blocked(result["task_id"], "prd_consistency_check_failed") |
| 351 | 351 | |
| 352 | + def test_test_script_node_gets_its_own_reason_not_the_prd_one(self): | |
| 353 | + # 2026-08-07: same exception class, but raised by the test_script | |
| 354 | + # mechanical compile-check (docs/todo/validator-test-script- | |
| 355 | + # narrative-output-issue.md), not the PRD-consistency check -- the | |
| 356 | + # console must not blame the PRD for an unrelated failure. | |
| 357 | + result = self._run_with_raising_lifecycle( | |
| 358 | + scheduler.work_graph_orchestrate.ConsistencyCheckFailedError( | |
| 359 | + "boom", node_id="validator_test_script" | |
| 360 | + ) | |
| 361 | + ) | |
| 362 | + self.assertEqual(result["final_status"], "blocked_pending_human") | |
| 363 | + self.assertEqual(result["blocked_reason"], "test_script_verification_failed") | |
| 364 | + self._assert_task_blocked(result["task_id"], "test_script_verification_failed") | |
| 365 | + | |
| 352 | 366 | |
| 353 | 367 | class UnroutedExceptionStillBlocksTaskTest(RoutableExceptionTestBase): |
| 354 | 368 | def test_other_exceptions_block_the_task_instead_of_leaving_it_stuck(self): | ... | ... |