fix: gate INFRA isolation edge cases (all-INFRA fail-loud, parse_error in guard)

This commit is contained in:
2026-07-16 05:54:02 -04:00
parent b307f51340
commit 03337af8f8
3 changed files with 159 additions and 9 deletions
+19 -8
View File
@@ -332,7 +332,9 @@ async def _resolve_baseline_block(
if miss_units:
miss_questions = flatten_units(miss_units)
r_b = await run_inference(miss_questions, run_id=run_id, skills_dir=base_skills_dir)
errors_inc = r_b.stop_reason_counts.get("error", 0)
# 护栏错误计数与 INFRA 判定口径一致:error + parse_error 都计入,
# 使 parse_error 风暴同样能触发 gate_guard_err 熔断(不被绕过)。
errors_inc = sum(r_b.stop_reason_counts.get(reason, 0) for reason in _INFRA_STOP_REASONS)
denom_inc = r_b.total
infra_qids = _infra_question_ids_from_db(log, r_b.run_id, miss_questions)
fresh_per_q = _candidate_correctness_from_db(log, r_b.run_id, miss_questions)
@@ -380,7 +382,9 @@ async def _run_candidate_block(
questions = flatten_units(units)
r_c = await run_inference(questions, run_id=run_id, skills_dir=cand_dir)
c_per_q = _candidate_correctness_from_db(log, r_c.run_id, questions)
return c_per_q, r_c.stop_reason_counts.get("error", 0), r_c.total
# 护栏错误计数与 INFRA 判定口径一致:error + parse_error 都计入。
errors_inc = sum(r_c.stop_reason_counts.get(reason, 0) for reason in _INFRA_STOP_REASONS)
return c_per_q, errors_inc, r_c.total
def _build_evidence_rows(
@@ -624,6 +628,15 @@ async def _run_local_validation(
log=log,
run_id=f"{gate_run_prefix}_b{block_idx}_base",
)
# 本块全 INFRA:无有效单元可配对——候选无需空跑,仅把基线侧错误计入护栏后
# 累计剔除数进入下一块(护栏仍能在整轮 INFRA 错误率超阈值时熔断)。
n_excluded += len(unit_chunk) - len(valid_chunk)
if not valid_chunk:
errors += err_b
infra_denom += den_b
_check_infra_guard(errors, infra_denom, gate_guard_err)
continue
# 候选侧只跑基线侧判定有效(非 INFRA)的单元,保证配对 unit_ids 两侧一致
c_per_q, err_c, den_c = await _run_candidate_block(
units=valid_chunk,
@@ -639,11 +652,6 @@ async def _run_local_validation(
infra_denom += den_b + den_c
_check_infra_guard(errors, infra_denom, gate_guard_err)
# 本块全 INFRA:无有效单元可配对,累计剔除数后跳过判定进入下一块
n_excluded += len(unit_chunk) - len(valid_chunk)
if not valid_chunk:
continue
# Phase 3: 折叠成单元视图 + 配对 + 证据行 + 块间判定(均用有效单元)
c_units = unit_correctness_view(valid_chunk, c_per_q)
candidate_per_q.update(c_per_q)
@@ -668,8 +676,11 @@ async def _run_local_validation(
if verdict.decision != "continue":
break
# verdict 仍为 None ⟺ 全部单元被 INFRA 排除(空 ladder 已在入口拒绝)。
# 明确失败,避免落到误导性的"空阶梯"断言而无法定位为 INFRA 原因。
if verdict is None:
raise RuntimeError("gate 阶梯所有 unit 被判为 INFRA 排除,无法验证(检查推理基础设施)")
# 最后一块判定即终态(n_remaining=0 → provisional/inertia
assert verdict is not None, "空阶梯应已在 validate_skill_local 入口拒绝"
return _finalize_outcome(
verdict=verdict,
w=w,