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
@@ -91,6 +91,10 @@ initial_state:
|
||||
final_report: ''
|
||||
gate_feedback: ''
|
||||
gate_attempts: 0
|
||||
parse_failure: ''
|
||||
refine_failure: ''
|
||||
aux_failure: ''
|
||||
synth_failure: ''
|
||||
|
||||
start: parse
|
||||
|
||||
@@ -139,8 +143,19 @@ nodes:
|
||||
required: [diff_spec, intent, rigor_in, surfaces_in, project_dir_in, extra_context]
|
||||
max_iterations: 3
|
||||
max_attempts: 2
|
||||
state_updates:
|
||||
parse_failure: '{{output}}'
|
||||
fallback: parse_fault
|
||||
next: facts
|
||||
|
||||
parse_fault:
|
||||
id: parse_fault
|
||||
type: script
|
||||
description: Fail-closed marker for a dead parse stage (reached only via parse's fallback) — emits a complete PIPELINE-FAULT verdict_out and jumps straight to render; a review that could not parse its request never reads as MERGE-READY.
|
||||
script: scripts/parse_fault.py
|
||||
timeout: 30
|
||||
next: render
|
||||
|
||||
facts:
|
||||
id: facts
|
||||
type: script
|
||||
@@ -209,6 +224,9 @@ nodes:
|
||||
required: [groups]
|
||||
max_iterations: 3
|
||||
max_attempts: 2
|
||||
state_updates:
|
||||
refine_failure: '{{output}}'
|
||||
fallback: cover_gate
|
||||
next: cover_gate
|
||||
|
||||
cover_gate:
|
||||
@@ -275,6 +293,7 @@ nodes:
|
||||
max_attempts: 2
|
||||
state_updates:
|
||||
domain_report: '{{output}}'
|
||||
fallback: domain_fault
|
||||
next: completeness_gate
|
||||
|
||||
completeness_gate:
|
||||
@@ -284,6 +303,13 @@ nodes:
|
||||
script: scripts/completeness_gate.py
|
||||
timeout: 30
|
||||
|
||||
domain_fault:
|
||||
id: domain_fault
|
||||
type: script
|
||||
description: Fail-closed domain lane fault marker (reached only via review_domain's fallback route inside the map branch). Normalizes the engine's "Agent node failed" text in domain_report into a > ⚠️ PIPELINE-FAULT banner the map collects; verdict.py counts any faulted lane and forces NEEDS-HUMAN — a dead domain lane never reads as a clean slice.
|
||||
script: scripts/domain_fault.py
|
||||
timeout: 30
|
||||
|
||||
aux_lanes:
|
||||
id: aux_lanes
|
||||
type: llm
|
||||
@@ -339,6 +365,17 @@ nodes:
|
||||
max_iterations: 10
|
||||
max_attempts: 2
|
||||
timeout: 3600
|
||||
state_updates:
|
||||
aux_failure: '{{output}}'
|
||||
fallback: aux_fault
|
||||
next: synthesize
|
||||
|
||||
aux_fault:
|
||||
id: aux_fault
|
||||
type: script
|
||||
description: Fail-closed marker for dead aux context lanes (reached only via aux_lanes' fallback) — records the failure as a PIPELINE-FAULT in aux_note, which synthesize surfaces as a lane skip. Aux lanes are enrichment; the degradation is visible but never blocks.
|
||||
script: scripts/aux_fault.py
|
||||
timeout: 30
|
||||
next: synthesize
|
||||
|
||||
downstream_sweep:
|
||||
@@ -457,6 +494,9 @@ nodes:
|
||||
required: [walkthrough, changes_rows, findings, cross_file, operational_history, org_context_section, attention_flags, placement_notes]
|
||||
max_iterations: 6
|
||||
max_attempts: 2
|
||||
state_updates:
|
||||
synth_failure: '{{output}}'
|
||||
fallback: verdict
|
||||
next: verify
|
||||
|
||||
verify:
|
||||
@@ -476,6 +516,7 @@ nodes:
|
||||
max_attempts: 2
|
||||
state_updates:
|
||||
verifier_output: '{{output}}'
|
||||
fallback: verdict
|
||||
next: verdict
|
||||
|
||||
verdict:
|
||||
|
||||
Reference in new issue
Block a user