fix(stage1-part2): stop R0 hard-crashing on fragile LLM-echoed checks

Task_C_BO_R0_seed_reducer_exception_planner raised RuntimeError (exit 1)
whenever status became BLOCKED, and BLOCKED was triggered by validation
findings that are inherently fragile because they require an LLM (Stage B
workers) to echo values verbatim or stay perfectly in scope:
  - slice_digest_sha256 echo mismatch (all 5 domains)
  - run_fingerprint echo mismatch
  - source meeting-clause refs outside slice/global (B5, 42 findings)

A decrypted postb_seed_ledger.json from the 2026-07-20 run confirmed all
47 blocking failures came from exactly these three check classes (no BLOCK
severity reviews / no budget overflow). Downgrade them from fatal
`failures` to non-fatal `reviews` (candidates preserved, routed to human
review). Genuine contract violations (schema/domain mismatch, worker
FAILED, candidate_ref sequence, forbidden keys, invalid enum) and the
deterministic A0-artifact integrity raises are kept fatal.

Gate simulation on the confirmed inputs: BLOCKED/exit-1 -> READY_WITH_REVIEW,
fan-out restored so R1 exception adjudication can run.

Note: this unblocks the pipeline and flags the issues; the upstream root
cause (Stage B tool-content truncated 66-78K -> 50K tokens) still needs a
slice-compaction fix for output quality.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-21 19:43:01 +09:00
co-authored by Claude Opus 4.8
parent e82c9e2848
commit d96d6edfd1
@@ -2767,9 +2767,8 @@ Agent:
or delta.get(\"domain_id\") != domain:\n failures.append(f\"{domain}:delta or delta.get(\"domain_id\") != domain:\n failures.append(f\"{domain}:delta
schema/domain mismatch\")\n continue\n if delta.get(\"status\") schema/domain mismatch\")\n continue\n if delta.get(\"status\")
== \"FAILED\":\n failures.append(f\"{domain}:worker FAILED\")\n if == \"FAILED\":\n failures.append(f\"{domain}:worker FAILED\")\n if
delta.get(\"run_fingerprint\") != manifest.get(\"run_fingerprint\"):\n failures.append(f\"{domain}:run delta.get(\"run_fingerprint\") != manifest.get(\"run_fingerprint\"):\n reviews.append({\"review_id\": f\"R0:{domain}:RUN_FINGERPRINT\", \"severity\": \"SOFT_WARNING\", \"issue_type\": \"run_fingerprint_echo_mismatch\", \"candidate_refs\": [], \"downstream_owner\": \"human_review\", \"source_domain\": domain})\n if delta.get(\"slice_digest_sha256\") != manifest.get(\"domain_slice_digests_sha256\",
fingerprint mismatch\")\n if delta.get(\"slice_digest_sha256\") != manifest.get(\"domain_slice_digests_sha256\", {}).get(domain):\n reviews.append({\"review_id\": f\"R0:{domain}:SLICE_DIGEST\", \"severity\": \"SOFT_WARNING\", \"issue_type\": \"slice_digest_echo_mismatch\", \"candidate_refs\": [], \"downstream_owner\": \"human_review\", \"source_domain\": domain})\n
{}).get(domain):\n failures.append(f\"{domain}:slice digest mismatch\")\n
\ candidates = _as_list(delta.get(\"bo_seed_candidates\"))\n prefix \ candidates = _as_list(delta.get(\"bo_seed_candidates\"))\n prefix
= domain.split(\"_\", 1)[0]\n expected_refs = [f\"{prefix}:{index:03d}\" = domain.split(\"_\", 1)[0]\n expected_refs = [f\"{prefix}:{index:03d}\"
for index in range(1, len(candidates) + 1)]\n actual_refs = [str(_as_dict(candidate).get(\"candidate_ref\") for index in range(1, len(candidates) + 1)]\n actual_refs = [str(_as_dict(candidate).get(\"candidate_ref\")
@@ -2785,8 +2784,7 @@ Agent:
candidate.get(\"BOType\") not in {\"event\", \"state\"} or candidate.get(\"ActionType\") candidate.get(\"BOType\") not in {\"event\", \"state\"} or candidate.get(\"ActionType\")
not in ACTION_TYPES or not str(candidate.get(\"Action\") or \"\").strip():\n not in ACTION_TYPES or not str(candidate.get(\"Action\") or \"\").strip():\n
\ failures.append(f\"{candidate.get('candidate_ref')}:required \ failures.append(f\"{candidate.get('candidate_ref')}:required
enum/action invalid\")\n continue\n failures.extend(_validate_refs(candidate, enum/action invalid\")\n continue\n for _rf in _validate_refs(candidate, domain, manifest):\n reviews.append({\"review_id\": f\"R0:{candidate.get(\x27candidate_ref\x27)}:REF_SCOPE\", \"severity\": \"HARD_WARNING\", \"issue_type\": \"source_ref_out_of_scope\", \"candidate_refs\": [candidate.get(\"candidate_ref\")], \"detail\": _rf, \"downstream_owner\": \"human_review\", \"source_domain\": domain})\n seed = _expand_candidate(candidate, domain,
domain, manifest))\n seed = _expand_candidate(candidate, domain,
manifest)\n expanded.append(seed)\n ledger_candidates.append({\"candidate_ref\": manifest)\n expanded.append(seed)\n ledger_candidates.append({\"candidate_ref\":
seed[\"candidate_ref\"], \"source_domain\": domain, \"seed\": seed})\n reviews.extend([dict(item, seed[\"candidate_ref\"], \"source_domain\": domain, \"seed\": seed})\n reviews.extend([dict(item,
source_domain=domain) for item in _as_list(delta.get(\"domain_review_queue\")) source_domain=domain) for item in _as_list(delta.get(\"domain_review_queue\"))