feat(TASK-019): code-reviewer fail-closed review pipeline
Every llm/agent stage that can die persistently now falls back to a machine-readable PIPELINE-FAULT sentinel instead of killing the graph: - review_domain -> branch-local domain_fault marker (banner-prefixed domain_report the map collects; completeness_gate precedent) - verify -> verdict (verifier fault renders findings unverified + a PIPELINE-FAULT attention line) - parse -> parse_fault -> render (complete NEEDS-HUMAN verdict_out; render's no-changes stub is bypassed for fault verdicts) - refine_groups -> cover_gate (deterministic-proposal fallback absorbs the failure; degradation noted in groups_note) - aux_lanes -> aux_fault -> synthesize (aux_note fault marker; visible, never blocking - aux is enrichment) - synthesize -> verdict (synth_failure marker; keyed off the failure prefix + non-empty diff, never findings==[], so clean zero-finding reviews stay MERGE-READY) verdict.py gains unified fault accounting (R2): any PIPELINE-FAULT in domain_reports / verifier_output / state fault keys forces NEEDS-HUMAN, prefix-anchored so a report merely quoting the marker mid-text never trips it; old 'PIPELINE FAULT' spelling migrated. Faults are prepended to attention so the [:5] cap can never hide one. Dedicated *_failure state keys capture engine failure text on every fallback+output_schema node, keeping the bundled warning baseline at zero. 15 python3-guarded R5 tests: fault paths, quoted-marker precedence, happy-path byte-compat regression, marker normalization, crash-path fail-closed (verdict/cover_gate/domain_fault), verifier-fault-on-empty- diff render, and the no-changes stub regression.
This commit is contained in:
8 files changed
+687
-4
No files matched your search
@@ -24,7 +24,14 @@ def main():
|
||||
changed = state.get("changed_files") or []
|
||||
rigor = state.get("resolved_rigor") or "production"
|
||||
|
||||
if not changed:
|
||||
# A fault can leave changed_files empty (a parse fault dies before the
|
||||
# diff is resolved; a verifier fault fires even on an empty diff) — a
|
||||
# fault-degraded verdict must still render as a full report. parse_fault
|
||||
# puts the marker in the reason; verdict.py prepends it to attention.
|
||||
faulted = str(v.get("reason") or "").startswith("PIPELINE-FAULT:") or any(
|
||||
isinstance(a, str) and a.startswith("PIPELINE-FAULT:") for a in v.get("attention") or []
|
||||
)
|
||||
if not changed and not faulted:
|
||||
print(json.dumps({"final_report": "# Code Review Summary\n\nNo changes to review."}))
|
||||
return
|
||||
|
||||
|
||||
Reference in new issue
Block a user