fix(TASK-018): harden verdict_gate fault routing and widen default_lanes fallback

Adversary finding 1: verdict_gate treated any lane report CONTAINING
'PIPELINE-FAULT:' as a lane fault, so a real review quoting the marker
silently bypassed red-finding counting and sentinel parsing. Lane-fault
detection is now precise — only a report that IS the lane_fault.py
marker (starts with it) routes to the fault rule. Adds the missing
regression tests: reds block despite MERGE-READY, NEEDS-HUMAN without
reds passes with attention, probe INCONCLUSIVE blocks with the
environment note, a gate crash fails closed, and a quoting report is
routed to the red rule, not the fault rule.

Adversary finding 2: default_lanes overwrote caller-forced lanes and
dropped the security lane the deterministic signals guaranteed. The
fallback now unions its defaults with caller-forced lanes (canonicalized
via the same aliases build_items uses) and forces security on
auth/deps/exec signals or hardened posture — selection degrades wider,
never narrower, and stays deterministic via a fixed lane order. Tests
cover forced-lane survival, alias canonicalization, unknown-name
tolerance, each security signal, and determinism.
This commit is contained in:
Dark-Alex-17 committed 2026-09-14 10:50:33 -06:00
1 parent 80c20afcdd
commit ebb9e9af62
4 files changed
+246 -14

No files matched your search

@@ -5,9 +5,11 @@ 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;
- a PIPELINE-FAULT lane result (the lane's agent died after retries;
detected only when the report IS the lane_fault.py marker, i.e. it
STARTS with it — a real review merely quoting the marker flows to the
normal rules) 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;
@@ -49,6 +51,13 @@ def main():
)
return line.strip()[:200]
def is_lane_fault(report):
# A genuine lane fault is the ENTIRE report emitted by lane_fault.py,
# which always begins with the marker. Matching the marker anywhere
# would let a real review that merely QUOTES "PIPELINE-FAULT:" bypass
# 🔴 counting and sentinel parsing.
return report.strip().startswith("PIPELINE-FAULT:")
def lane_fault_blocker(lane, report):
blockers.append(
f"{lane}: PIPELINE-FAULT — the lane failed after retries and produced "
@@ -60,7 +69,7 @@ def main():
cr = lane_report("code_review_results")
if cr is None:
record("code-review", "SKIPPED", "not selected")
elif "PIPELINE-FAULT:" in cr:
elif is_lane_fault(cr):
lane_fault_blocker("code-review", cr)
reports.append(("code-review", cr))
else:
@@ -91,7 +100,7 @@ def main():
adv = lane_report("adversary_results")
if adv is None:
record("adversary", "SKIPPED", "not selected")
elif "PIPELINE-FAULT:" in adv:
elif is_lane_fault(adv):
lane_fault_blocker("adversary", adv)
reports.append(("adversary", adv))
else:
@@ -114,7 +123,7 @@ def main():
sec = lane_report("security_results")
if sec is None:
record("security", "SKIPPED", "not selected")
elif "PIPELINE-FAULT:" in sec:
elif is_lane_fault(sec):
lane_fault_blocker("security", sec)
reports.append(("security", sec))
else:
@@ -135,7 +144,7 @@ def main():
pb = lane_report("probe_results")
if pb is None:
record("probe", "SKIPPED", "not selected")
elif "PIPELINE-FAULT:" in pb:
elif is_lane_fault(pb):
lane_fault_blocker("probe", pb)
reports.append(("probe", pb))
else: