diff --git a/app/harness/store.py b/app/harness/store.py index 87fba07..8caad53 100644 --- a/app/harness/store.py +++ b/app/harness/store.py @@ -190,6 +190,9 @@ def init_seed( baseline_run_id: str, parent: str | None, description: str, + *, + pools_json: Path | None = None, + split_manifest: Path | None = None, ) -> Path: """在 store/seeds/ 写一个种子:权重 + baseline.db + seed.json。 @@ -202,6 +205,10 @@ def init_seed( baseline_run_id: 全量记录的 run_id,fresh 时注入 build_pools。 parent: 来源(initial 为 None)。 description: 人类可读说明。 + pools_json: 可选,冻结切分 pools.json 源路径;提供时拷入 seed 目录, + 供 fresh 训练时携带冻结切分进 workspace(见 init_workspace_from_seed)。 + split_manifest: 可选,冻结切分 split_manifest.json 源路径;提供时拷入 seed + 目录,供加载时校验 pools.json 内容指纹(pools_sha256)。 返回: 种子目录路径。 @@ -216,6 +223,10 @@ def init_seed( shutil.copytree(skills_dir, seed_dir / "skills") shutil.copytree(prompts_dir, seed_dir / "prompts") shutil.copy2(baseline_db, seed_dir / "baseline.db") + if pools_json is not None: + shutil.copy2(pools_json, seed_dir / "pools.json") + if split_manifest is not None: + shutil.copy2(split_manifest, seed_dir / "split_manifest.json") (seed_dir / "seed.json").write_text( json.dumps( { diff --git a/app/harness/workspace.py b/app/harness/workspace.py index 6c13452..3598b2b 100644 --- a/app/harness/workspace.py +++ b/app/harness/workspace.py @@ -196,6 +196,13 @@ def init_workspace_from_seed( shutil.copytree(seed_dir / "prompts", workspace_dir / "prompts" / "v1") shutil.copy2(seed_dir / "baseline.db", workspace_dir / "harness.db") + seed_pools = seed_dir / "pools.json" + if seed_pools.exists(): + shutil.copy2(seed_pools, workspace_dir / "pools.json") + seed_manifest = seed_dir / "split_manifest.json" + if seed_manifest.exists(): + shutil.copy2(seed_manifest, workspace_dir / "split_manifest.json") + logger.info("Workspace 从种子 '{}' 初始化完成: {}", seed_name, workspace_dir) return meta["baseline_run_id"] diff --git a/tests/unit/test_harness_store.py b/tests/unit/test_harness_store.py index 721366b..92dc5cf 100644 --- a/tests/unit/test_harness_store.py +++ b/tests/unit/test_harness_store.py @@ -243,6 +243,24 @@ class TestInitSeed: with pytest.raises(FileExistsError, match="种子已存在"): init_seed(store, "dup", skills_dir, prompts_dir, baseline_db, "r1", None, "second") + def test_init_seed_carries_pools(self, tmp_path): + """提供 pools_json/split_manifest 时拷入 seed 目录。""" + from app.harness.store import init_seed + + store = tmp_path / "store" + skills = tmp_path / "sk"; skills.mkdir(); (skills / "s.md").write_text("x") + prompts = tmp_path / "pr"; prompts.mkdir(); (prompts / "p.md").write_text("y") + db = tmp_path / "b.db"; db.write_text("db") + pools = tmp_path / "pools.json"; pools.write_text('{"split_mode":"global"}') + manifest = tmp_path / "split_manifest.json"; manifest.write_text('{"pools_sha256":"a"}') + + seed_dir = init_seed( + store, "s1", skills, prompts, db, "infer_adhoc", None, "d", + pools_json=pools, split_manifest=manifest, + ) + assert (seed_dir / "pools.json").exists() + assert (seed_dir / "split_manifest.json").exists() + class TestListSeeds: """list_seeds 列出所有种子。""" diff --git a/tests/unit/test_harness_workspace.py b/tests/unit/test_harness_workspace.py index f11fb6d..f0fa2a2 100644 --- a/tests/unit/test_harness_workspace.py +++ b/tests/unit/test_harness_workspace.py @@ -183,6 +183,23 @@ def test_init_workspace_from_seed_missing_questions(store_dir: Path, workspace_d assert not workspace_dir.exists() +def test_init_workspace_from_seed_carries_pools(store_dir: Path, workspace_dir: Path) -> None: + """seed 目录含 pools.json/split_manifest.json 时拷入 workspace。""" + # store_dir fixture 已构造 seed "initial";补冻结产物到 seed 目录再初始化 workspace。 + seed_dir = store_dir / "seeds" / "initial" + (seed_dir / "pools.json").write_text('{"split_mode":"global"}') + (seed_dir / "split_manifest.json").write_text('{"pools_sha256":"a"}') + + init_workspace_from_seed( + workspace_dir, + store_dir, + seed_name="initial", + questions="benchmarks/Video-MME", + ) + assert (workspace_dir / "pools.json").exists() + assert (workspace_dir / "split_manifest.json").exists() + + # --------------------------------------------------------------------------- # load_manifest # ---------------------------------------------------------------------------