fix(question_gen): resolve pipeline integration issues from final review

1. Apply postprocess shuffle result (pp.options, pp.answer) to final
   GeneratedQuestion output instead of using original candidate values.

2. Record dedup rejection in store via new mark_item_rejected() method,
   preventing items from staying as 'accepted' after dedup rejects them.

3. Add .flatten() to embed_fn outputs in _is_duplicate and embed_pool
   append to handle 2D (1,D) arrays from embedding implementations.

4. Validate exactly 4 options in _validate_parsed_fields (was >= 2),
   matching the A-D answer constraint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-12 00:14:12 -04:00
parent eecb86e27a
commit 4fb7a61f8b
4 changed files with 86 additions and 14 deletions
+48 -3
View File
@@ -247,9 +247,7 @@ class TestQuestionGenStore:
"""对不存在的 run_id 调用 record_run_end 应报错。"""
stats = RunStats(total_slots=10, accepted=5, rejected=3, heavy_sampled=2)
with pytest.raises(ValueError, match="run_id"):
store.record_run_end(
run_id="ghost-run", status="completed", stats=stats
)
store.record_run_end(run_id="ghost-run", status="completed", stats=stats)
def test_update_gates_missing_item_raises(self, store: QuestionGenStore) -> None:
"""对不存在的 item_id 调用 update_gates 应报错。"""
@@ -262,6 +260,53 @@ class TestQuestionGenStore:
with pytest.raises(ValueError, match="item_id"):
store.update_gates(item_id="ghost-item", report=report)
def test_mark_item_rejected(self, store: QuestionGenStore) -> None:
"""mark_item_rejected 将 final_status 设为 rejected 并记录原因。"""
run_id = "run-mark-rej"
store.record_run_start(run_id=run_id, git_sha="ddd444", config_snapshot="{}")
item_id = "item-mark-rej-1"
store.record_item(
item_id=item_id,
run_id=run_id,
slot_id="slot-mark",
video_id="v005",
family="retrieval",
task_type="Action Recognition",
skill_target="M1",
attempt=1,
question_text="这是什么?",
)
# 先模拟门控通过(将 final_status 设为 accepted
report_pass = _MockGateReport(
key_verify=_GateResult(_Verdict.PASS, "ok"),
blind_answer=_GateResult(_Verdict.PASS, "ok"),
multi_true=_GateResult(_Verdict.PASS, "ok"),
leak_test=_GateResult(_Verdict.PASS, "ok"),
)
store.update_gates(item_id=item_id, report=report_pass)
# 然后因去重被拒绝
store.mark_item_rejected(item_id, "duplicate detected by embedding similarity")
import sqlite3
conn = sqlite3.connect(str(store._db_path))
conn.row_factory = sqlite3.Row
row = conn.execute(
"SELECT final_status, gate_reject_reason FROM question_gen_items WHERE item_id=?",
(item_id,),
).fetchone()
conn.close()
assert row["final_status"] == "rejected"
assert row["gate_reject_reason"] == "duplicate detected by embedding similarity"
def test_mark_item_rejected_missing_item_raises(self, store: QuestionGenStore) -> None:
"""对不存在的 item_id 调用 mark_item_rejected 应报错。"""
with pytest.raises(ValueError, match="item_id"):
store.mark_item_rejected(item_id="ghost-item", reason="duplicate")
def test_update_difficulty_missing_item_raises(self, store: QuestionGenStore) -> None:
"""对不存在的 item_id 调用 update_difficulty 应报错。"""
with pytest.raises(ValueError, match="item_id"):