feat(TASK-018): review-gauntlet lane degradation + verification passthrough
- lane_fault.py + fallback on all four run_* lane nodes: an agent-node failure is normalized into a PIPELINE-FAULT lane result instead of killing the graph - verdict_gate.py: PIPELINE-FAULT lane results block distinctly from SKIPPED and missing-sentinel; a PIPELINE-FAULT in signals_error blocks at the gauntlet level - build_items.py: restructured into main() + fail-closed guard (crash emits empty lanes + PIPELINE-FAULT) and folds lanes_degraded into lanes_summary - parse: state_updates/fallback -> parse_fault.py, which records the fault in signals_error and jumps to the verdict gate - select_lanes: state_updates/fallback -> default_lanes.py, a deterministic wider-never-narrower lane fallback - verification_commands threaded through parse into run_adversary's prompt (declared-only, never invented) - run_probe prompt gains the aborted-attempt reconcile line - 8 gauntlet_* R5 tests in src/config/request_context.rs (script harness + graph interpolation)
This commit is contained in:
7 files changed
+603
-80
No files matched your search
@@ -5,6 +5,9 @@ Parses each configured lane's verdict SENTINEL with a regex — no LLM
|
||||
re-reads, no judgment. The gate's hard rules:
|
||||
|
||||
- a missing sentinel is a LANE FAILURE and blocks — never a pass;
|
||||
- a PIPELINE-FAULT lane result (the lane's agent died after retries) or a
|
||||
PIPELINE-FAULT in signals_error (builder/parse fault) blocks — a
|
||||
degraded pipeline is never a pass;
|
||||
- any 🔴 finding in the code-review report blocks regardless of the
|
||||
lane's own verdict line;
|
||||
- NEEDS-HUMAN without 🔴 passes but is surfaced as attention required;
|
||||
@@ -40,10 +43,26 @@ def main():
|
||||
def record(lane, status, detail=""):
|
||||
lane_lines.append(f"| {lane} | {status} | {detail} |")
|
||||
|
||||
def fault_excerpt(report):
|
||||
line = next(
|
||||
(ln for ln in report.splitlines() if "PIPELINE-FAULT:" in ln), report
|
||||
)
|
||||
return line.strip()[:200]
|
||||
|
||||
def lane_fault_blocker(lane, report):
|
||||
blockers.append(
|
||||
f"{lane}: PIPELINE-FAULT — the lane failed after retries and produced "
|
||||
f"no verdict; a degraded lane is never a pass ({fault_excerpt(report)})"
|
||||
)
|
||||
record(lane, "BLOCKED", "PIPELINE-FAULT (lane failed)")
|
||||
|
||||
# --- code-review ------------------------------------------------------
|
||||
cr = lane_report("code_review_results")
|
||||
if cr is None:
|
||||
record("code-review", "SKIPPED", "not selected")
|
||||
elif "PIPELINE-FAULT:" in cr:
|
||||
lane_fault_blocker("code-review", cr)
|
||||
reports.append(("code-review", cr))
|
||||
else:
|
||||
reports.append(("code-review", cr))
|
||||
m = re.search(r"Verdict:\**\s*\**\s*(MERGE-READY|NEEDS-HUMAN)", cr)
|
||||
@@ -72,6 +91,9 @@ def main():
|
||||
adv = lane_report("adversary_results")
|
||||
if adv is None:
|
||||
record("adversary", "SKIPPED", "not selected")
|
||||
elif "PIPELINE-FAULT:" in adv:
|
||||
lane_fault_blocker("adversary", adv)
|
||||
reports.append(("adversary", adv))
|
||||
else:
|
||||
reports.append(("adversary", adv))
|
||||
m = re.search(r"ADVERSARIAL_REVIEW:\s*(CONFORMS|DIVERGES)", adv)
|
||||
@@ -92,6 +114,9 @@ def main():
|
||||
sec = lane_report("security_results")
|
||||
if sec is None:
|
||||
record("security", "SKIPPED", "not selected")
|
||||
elif "PIPELINE-FAULT:" in sec:
|
||||
lane_fault_blocker("security", sec)
|
||||
reports.append(("security", sec))
|
||||
else:
|
||||
reports.append(("security", sec))
|
||||
m = re.search(r"SECURITY_REVIEW:\s*(PASS|FAIL)", sec)
|
||||
@@ -110,6 +135,9 @@ def main():
|
||||
pb = lane_report("probe_results")
|
||||
if pb is None:
|
||||
record("probe", "SKIPPED", "not selected")
|
||||
elif "PIPELINE-FAULT:" in pb:
|
||||
lane_fault_blocker("probe", pb)
|
||||
reports.append(("probe", pb))
|
||||
else:
|
||||
reports.append(("probe", pb))
|
||||
m = re.search(r"USAGE_PROBE:\s*(PASS|FAIL|INCONCLUSIVE)", pb)
|
||||
@@ -131,6 +159,12 @@ def main():
|
||||
)
|
||||
record("probe", "BLOCKED", "missing verdict sentinel")
|
||||
|
||||
# A gauntlet-level fault (build_items crash, dead parse stage) means the
|
||||
# lanes above were never built — SKIPPED rows alone must not read as PASS.
|
||||
signals_error = state.get("signals_error")
|
||||
if isinstance(signals_error, str) and "PIPELINE-FAULT:" in signals_error:
|
||||
blockers.append(f"pipeline: {signals_error}")
|
||||
|
||||
verdict = "BLOCKED" if blockers else "PASS"
|
||||
|
||||
md = "\n".join(
|
||||
|
||||
Reference in new issue
Block a user