feat(harness): pools.json 序列化 pair 四字段防孤儿 single

_q_to_dict 写出 pair_id/question_role/flip_axis/unit_id,_dict_to_q 用 .get
兼容旧 workspace 的 pools.json 读回并回填(unit_id 缺省交 __post_init__)。
pools.json 是训练主回路读回题目处,此前漏写会让孪生对解冻后退化成孤儿
single、配对指标失真。categories 块沿用 per-qid 记录,Task 3 的 unit 原子
切分已保证两 pair 成员同池同 key,序列化不破坏该原子性。
This commit is contained in:
2026-07-15 08:05:15 -04:00
parent 273984674b
commit bd1f7a22a2
2 changed files with 189 additions and 0 deletions
+17
View File
@@ -242,6 +242,10 @@ def _q_to_dict(q: GeneratedQuestion) -> dict:
返回:
包含全部字段的字典(options/source_nodes 从 tuple 转为 list)。
关键实现细节:
pair 四字段(pair_id/question_role/flip_axis/unit_id)必须写出——pools.json
是训练主回路读回题目的地方,漏写会让孪生对解冻后退化成孤儿 single。
"""
return {
"question_id": q.question_id,
@@ -255,6 +259,10 @@ def _q_to_dict(q: GeneratedQuestion) -> dict:
"family": q.family,
"skill_target": q.skill_target,
"difficulty_steps": q.difficulty_steps,
"pair_id": q.pair_id,
"question_role": q.question_role,
"flip_axis": q.flip_axis,
"unit_id": q.unit_id,
}
@@ -266,6 +274,11 @@ def _dict_to_q(d: dict) -> GeneratedQuestion:
返回:
恢复的 GeneratedQuestion 实例(options/source_nodes 恢复为 tuple)。
关键实现细节:
pair 四字段用 .get 兼容旧 workspace 的 pools.json(无这些字段不崩,默认退化
为 single)——断点续跑铁律。unit_id 缺省时传 "",交给 GeneratedQuestion
的 __post_init__ 回填为 pair_id 或 question_id,避免孤儿 single。
"""
return GeneratedQuestion(
question_id=d["question_id"],
@@ -279,6 +292,10 @@ def _dict_to_q(d: dict) -> GeneratedQuestion:
family=d.get("family"),
skill_target=d.get("skill_target"),
difficulty_steps=d.get("difficulty_steps"),
pair_id=d.get("pair_id"),
question_role=d.get("question_role", "single"),
flip_axis=d.get("flip_axis"),
unit_id=d.get("unit_id", ""),
)