fix: dedup three-bucket projection + honest C3 error-handling note
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
"""离线诊断编排集成测试(LLM 类:MD 产出到 tests/outputs/)。
|
||||
|
||||
用 fake run_diagnosis + fake deps 覆盖编排契约,不实际调 LLM/VLM:
|
||||
1. 续跑幂等 —— 已落盘题跳过,第二次无剩余则 run_diagnosis 收到空列表。
|
||||
1. 续跑幂等 —— 已落盘题跳过;第二次 remaining 为空则直接早返回、不调用
|
||||
run_diagnosis。
|
||||
2. 投影正确 —— defect→T2、lapse→T1,evolution_target 由 error_type 派生。
|
||||
3. 三桶去重 —— 同题同时在 degraded 与 attributions 时按 degraded>infra>
|
||||
attribution 优先级只落 1 行、tier=uncertain。
|
||||
|
||||
测试结束把编排过程(remaining、各 tier 计数、投影样例)写入
|
||||
tests/outputs/test_baseline_diagnosis/<test>_<固定 ts>.md(CLAUDE.md §4.6)。
|
||||
@@ -262,3 +265,90 @@ async def test_infra_and_degraded_projection(tmp_path, monkeypatch):
|
||||
)
|
||||
assert md_path.exists()
|
||||
store.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_degraded_overrides_attribution(tmp_path, monkeypatch):
|
||||
"""三桶去重:同题同时在 degraded 与 attributions 时只落 1 行且 tier=uncertain。
|
||||
|
||||
judge 解析失败会生成 degraded metrics,若仍是错题还会建 attribution,
|
||||
故同一 question_id 可同时出现在两桶。按 degraded>infra>attribution 优先级,
|
||||
该题必须只落 1 行、tier=uncertain(degraded 置位),attribution 行被跳过。
|
||||
"""
|
||||
calls: list[tuple[str, ...]] = []
|
||||
|
||||
async def fake_run_diagnosis(
|
||||
run_id,
|
||||
questions,
|
||||
tree_data,
|
||||
llm,
|
||||
run_log,
|
||||
skill_store,
|
||||
prompts,
|
||||
*,
|
||||
concurrency,
|
||||
question_ids=None,
|
||||
task_types=None,
|
||||
only_incorrect=False,
|
||||
):
|
||||
calls.append(tuple(question_ids or []))
|
||||
from core.evolution.types import DiagnosisResult, ErrorAttribution
|
||||
|
||||
# q5 同时出现在 attributions(judge 解析失败仍建归因)与 degraded_question_ids。
|
||||
return DiagnosisResult(
|
||||
run_id=run_id,
|
||||
error_attributions=[ErrorAttribution("q5", "reasoning_failure", None, "defect")],
|
||||
infra_question_ids=[],
|
||||
degraded_question_ids=["q5"],
|
||||
)
|
||||
|
||||
monkeypatch.setattr("app.harness.baseline_diagnosis.run_diagnosis", fake_run_diagnosis)
|
||||
deps = DiagnosisDeps(
|
||||
run_log=_FakeRunLog(),
|
||||
llm=_FakeLLM(),
|
||||
skill_store=_FakeSkillStore(),
|
||||
prompts=object(),
|
||||
tree_data={},
|
||||
concurrency=2,
|
||||
)
|
||||
store = SqliteDiagnosisSignalStore(str(tmp_path / "h.db"))
|
||||
q_by_id = {"q5": _mk_q("q5")}
|
||||
|
||||
await run_baseline_diagnosis(
|
||||
baseline_run_id="infer_adhoc",
|
||||
diag_fingerprint="fp",
|
||||
wrong_ids=["q5"],
|
||||
questions=q_by_id,
|
||||
store=store,
|
||||
deps=deps,
|
||||
)
|
||||
|
||||
all_rows = store.load("infer_adhoc", "fp")
|
||||
assert len(all_rows) == 1 # 只落 1 行(无同 PK 双写)
|
||||
row = all_rows[0]
|
||||
assert row.question_id == "q5"
|
||||
assert row.tier == "uncertain" # degraded 优先级最高
|
||||
assert row.degraded is True
|
||||
assert row.error_type is None # 走 degraded 投影而非 attribution
|
||||
assert row.evolution_target is None
|
||||
|
||||
md_path = _write_md(
|
||||
"test_degraded_overrides_attribution",
|
||||
[
|
||||
"# 离线诊断编排:三桶优先级去重",
|
||||
"",
|
||||
"## 任务描述",
|
||||
"q5 同时出现在 error_attributions(defect)与 degraded_question_ids,"
|
||||
"验证按 degraded>infra>attribution 优先级只落 1 行。",
|
||||
"",
|
||||
"## 落库结果",
|
||||
"| question_id | 落库行数 | tier | degraded | error_type |",
|
||||
"|---|---|---|---|---|",
|
||||
f"| q5 | {len(all_rows)} | {row.tier} | {row.degraded} | {row.error_type} |",
|
||||
"",
|
||||
"## 结论",
|
||||
"degraded 优先级最高,attribution 行被跳过 → 每题恰写一行、counts 恰计一次。",
|
||||
],
|
||||
)
|
||||
assert md_path.exists()
|
||||
store.close()
|
||||
|
||||
Reference in New Issue
Block a user