From 6911c83d66a8a6c5e53f827dcef8e46adcb9be6d Mon Sep 17 00:00:00 2001 From: iomgaa Date: Thu, 16 Jul 2026 07:18:14 -0400 Subject: [PATCH] refactor: share INFRA stop-reason set from core.evolution --- app/harness/validate.py | 12 ++++++------ core/evolution/__init__.py | 3 ++- core/evolution/diagnose.py | 6 +++--- tests/unit/test_harness_validate.py | 9 +++++++++ 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/harness/validate.py b/app/harness/validate.py index c55e9be..3e37756 100644 --- a/app/harness/validate.py +++ b/app/harness/validate.py @@ -27,6 +27,7 @@ from loguru import logger from app.harness.gate_ladder import BaselineCache, skill_hash from app.harness.question_units import build_units, flatten_units, unit_correctness_view from core.evolution import ( + INFRA_STOP_REASONS, GateParams, GateVerdict, RejectedEdit, @@ -35,6 +36,10 @@ from core.evolution import ( pair_block, ) +# INFRA_STOP_REASONS 复用 core.evolution.diagnose 的单一定义(M-2):INFRA 故障 +# stop_reason(推理侧基础设施错误,非模型答错)在诊断与 gate 两处必须同口径, +# 避免各自维护副本致未来漂移。 + if TYPE_CHECKING: from app.harness.inference import InferenceResult from app.harness.log import HarnessLog @@ -231,11 +236,6 @@ def _load_run_rows( return normalized -# INFRA 故障 stop_reason(推理侧基础设施错误,非模型答错):这些题的对错无信号意义, -# 基线臂遇到时不得写入 BaselineCache(否则一次瞬时故障永久污染基线快照)。 -_INFRA_STOP_REASONS = frozenset({"error", "parse_error"}) - - def _infra_question_ids_from_db( log: HarnessLog, run_id: str, @@ -255,7 +255,7 @@ def _infra_question_ids_from_db( return { q.question_id for q in chunk - if rows.get(q.question_id, {}).get("stop_reason") in _INFRA_STOP_REASONS + if rows.get(q.question_id, {}).get("stop_reason") in INFRA_STOP_REASONS } diff --git a/core/evolution/__init__.py b/core/evolution/__init__.py index b9e0b8c..9308f61 100644 --- a/core/evolution/__init__.py +++ b/core/evolution/__init__.py @@ -4,7 +4,7 @@ 只依赖 Protocol 接口和标准库,可搬到无 adapters 的环境用假实现原样运行。 """ -from core.evolution.diagnose import run_diagnosis +from core.evolution.diagnose import INFRA_STOP_REASONS, run_diagnosis from core.evolution.evolve import ( edit_budget_at, evolve_single_skill, @@ -44,6 +44,7 @@ from core.evolution.types import ( from core.evolution.validate import classify_quadrants, compute_accuracy, pair_block __all__ = [ + "INFRA_STOP_REASONS", "CaseSample", "DiagnosePrompts", "DiagnosisResult", diff --git a/core/evolution/diagnose.py b/core/evolution/diagnose.py index d100aae..2d045e4 100644 --- a/core/evolution/diagnose.py +++ b/core/evolution/diagnose.py @@ -53,7 +53,7 @@ if TYPE_CHECKING: _SPAN_EVAL_TOOLS: frozenset[str] = frozenset({"view_node", "search_similar", "observe_frame"}) """span 级评估涵盖的工具集合。""" -_INFRA_STOP_REASONS: frozenset[str] = frozenset({"error", "parse_error"}) +INFRA_STOP_REASONS: frozenset[str] = frozenset({"error", "parse_error"}) """执行/解析层失败导致排除的 stop_reason 集合。""" @@ -2007,7 +2007,7 @@ def _count_infra_excluded( qids = [ row["question_id"] for row in prediction_rows - if row.get("stop_reason") in _INFRA_STOP_REASONS + if row.get("stop_reason") in INFRA_STOP_REASONS ] return len(qids), qids @@ -2083,7 +2083,7 @@ async def run_diagnosis( for row in all_predictions: stop_reason = row.get("stop_reason") - if stop_reason in _INFRA_STOP_REASONS: + if stop_reason in INFRA_STOP_REASONS: continue if task_type_filter and row.get("task_type") not in task_type_filter: continue diff --git a/tests/unit/test_harness_validate.py b/tests/unit/test_harness_validate.py index 7680d67..97fd936 100644 --- a/tests/unit/test_harness_validate.py +++ b/tests/unit/test_harness_validate.py @@ -199,6 +199,15 @@ def _make_all_infra_mock(log: HarnessLog, stop_reason: str): return mock_fn, call_log +def test_infra_stop_reasons_single_source() -> None: + """app 侧 INFRA_STOP_REASONS 复用 core 常量(同一对象),杜绝未来漂移(M-2)。""" + from app.harness import validate + from core.evolution import diagnose + + assert validate.INFRA_STOP_REASONS is diagnose.INFRA_STOP_REASONS + assert frozenset({"error", "parse_error"}) == diagnose.INFRA_STOP_REASONS + + # =========================================================================== # 数据类型测试 # ===========================================================================