Add a runner for all planner validation entrypoints
Constraint: The planner artifact had become executable, but future sessions still needed a reusable entrypoint instead of ad-hoc inline Python to consume it. Rejected: Keep the execution proof as one-off shell snippets | That would not give the next session a durable command surface. Confidence: high Scope-risk: narrow Directive: Use run_planner_validation_commands_live.py as the default preflight gate before attempting new Phase-1 worker changes on a host. Tested: /usr/local/miniconda3/bin/python -m py_compile scripts/run_planner_validation_commands_live.py; git diff --check; /usr/local/miniconda3/bin/python scripts/run_planner_validation_commands_live.py --dsn 'postgres://d2:d2pass@127.0.0.1:5432/d2' --output data/pgvector_eval/music20/planner_validation_commands_runner_report.json Not-tested: The runner only validates planner entrypoints; it does not unlock successful extraction on an environment-blocked host.
Showing
5 changed files
with
125 additions
and
0 deletions
| 1 | { | ||
| 2 | "prereq_audit": { | ||
| 3 | "command": "cd /workspace/acr-engine && PG_DSN=\"${PG_DSN:?set PG_DSN}\" /usr/local/miniconda3/bin/python scripts/run_phase1_prereq_audit_live.py --dsn \"$PG_DSN\" --schema acr_test --output data/pgvector_eval/music20/phase1_prereq_audit_report.json", | ||
| 4 | "returncode": 0, | ||
| 5 | "stdout_tail": "\n },\n {\n \"extraction_job_id\": 4,\n \"model_name\": \"muq\",\n \"model_version\": \"large-msd-iter\",\n \"embedding_dim\": 768,\n \"target_scope\": \"reference_set:phase1_hot_reference_v1\",\n \"required_packages\": [\n \"numpy\",\n \"torch\",\n \"torchaudio\",\n \"transformers\"\n ],\n \"missing_packages\": [\n \"torch\",\n \"torchaudio\",\n \"transformers\"\n ],\n \"downloads_root_exists\": false,\n \"ready_for_live_worker\": false\n },\n {\n \"extraction_job_id\": 5,\n \"model_name\": \"ecapa\",\n \"model_version\": \"acr-baseline-v1\",\n \"embedding_dim\": 192,\n \"target_scope\": \"reference_set:phase1_hot_reference_v1\",\n \"required_packages\": [\n \"numpy\",\n \"torch\",\n \"torchaudio\",\n \"speechbrain\"\n ],\n \"missing_packages\": [\n \"torch\",\n \"torchaudio\",\n \"speechbrain\"\n ],\n \"downloads_root_exists\": false,\n \"ready_for_live_worker\": false\n }\n ],\n \"summary\": {\n \"total_jobs\": 5,\n \"ready_jobs\": 0,\n \"blocked_jobs\": 5,\n \"missing_packages_union\": [\n \"speechbrain\",\n \"torch\",\n \"torchaudio\",\n \"transformers\"\n ]\n }\n}\n", | ||
| 6 | "stderr_tail": "", | ||
| 7 | "passed": true | ||
| 8 | }, | ||
| 9 | "worker_contract_smoke": { | ||
| 10 | "command": "cd /workspace/acr-engine && PG_DSN=\"${PG_DSN:?set PG_DSN}\" /usr/local/miniconda3/bin/python scripts/run_phase1_worker_contract_smoke_live.py --dsn \"$PG_DSN\" --schema acr_test --output data/pgvector_eval/music20/phase1_worker_contract_smoke_report.json", | ||
| 11 | "returncode": 0, | ||
| 12 | "stdout_tail": "{\n \"schema\": \"acr_test\",\n \"dsn_redacted\": \"postgres://d2:***@127.0.0.1:5432/d2\",\n \"exact_lane\": {\n \"job_id\": 1,\n \"returncode\": 0,\n \"job_status\": \"failed\",\n \"failure_reason\": \"unreadable_audio_assets\",\n \"missing_asset_count\": 20,\n \"artifact\": \"data/pgvector_eval/music20/phase1_worker_contract_smoke_exact.json\"\n },\n \"semantic_lane\": {\n \"returncode\": 0,\n \"semantic_job_count\": 4,\n \"failed_jobs\": 4,\n \"unique_blockers\": [\n \"model_runtime_unavailable\",\n \"unreadable_audio_assets\"\n ],\n \"artifact\": \"data/pgvector_eval/music20/phase1_worker_contract_smoke_semantic_matrix.json\"\n },\n \"summary\": {\n \"exact_status\": \"failed\",\n \"semantic_failed_jobs\": 4,\n \"shared_environment_blockers\": [\n \"missing /workspace/downloads mount\",\n \"missing semantic model runtime dependencies\"\n ]\n }\n}\n", | ||
| 13 | "stderr_tail": "", | ||
| 14 | "passed": true | ||
| 15 | }, | ||
| 16 | "semantic_vector_negative_matrix": { | ||
| 17 | "command": "cd /workspace/acr-engine && PG_DSN=\"${PG_DSN:?set PG_DSN}\" /usr/local/miniconda3/bin/python scripts/run_embedding_vector_table_negative_matrix_live.py --dsn \"$PG_DSN\" --output data/pgvector_eval/music20/embedding_vector_table_negative_matrix_report.json", | ||
| 18 | "returncode": 0, | ||
| 19 | "stdout_tail": "dding_vector_table_not_allowlisted_attempt.json\"\n },\n {\n \"case\": \"vector_table_missing_in_schema\",\n \"schema\": \"acr_vector_table_missing_test\",\n \"vector_table\": \"audio_embedding_vector_768\",\n \"job_status\": \"failed\",\n \"failure_reason\": \"preflight_failed\",\n \"preflight_blockers\": [\n \"unreadable_audio_assets\",\n \"vector_table_missing_in_schema\",\n \"model_runtime_unavailable\"\n ],\n \"vector_table_report\": {\n \"reason\": \"vector_table_missing_in_schema\",\n \"resolved\": false,\n \"expected_dim\": 768,\n \"table_exists\": false,\n \"allowed_vector_tables\": [\n \"audio_embedding_vector_192\",\n \"audio_embedding_vector_768\"\n ],\n \"requested_vector_table\": \"audio_embedding_vector_768\"\n },\n \"artifact\": \"data/pgvector_eval/music20/embedding_vector_table_missing_in_schema_attempt.json\"\n }\n ],\n \"summary\": {\n \"expected_reasons\": {\n \"vector_table_dim_mismatch\": \"vector_table_dim_mismatch\",\n \"vector_table_not_allowlisted\": \"vector_table_not_allowlisted\",\n \"vector_table_missing_in_schema\": \"vector_table_missing_in_schema\"\n },\n \"all_failed\": true\n }\n}\n", | ||
| 20 | "stderr_tail": "", | ||
| 21 | "passed": true | ||
| 22 | }, | ||
| 23 | "asset_level_upsert_validation": { | ||
| 24 | "command": "cd /workspace/acr-engine && PG_DSN=\"${PG_DSN:?set PG_DSN}\" /usr/local/miniconda3/bin/python scripts/validate_audio_embedding_asset_upsert_live.py --dsn \"$PG_DSN\" --schema acr_asset_upsert_test --output data/pgvector_eval/music20/audio_embedding_asset_upsert_live_report.json", | ||
| 25 | "returncode": 0, | ||
| 26 | "stdout_tail": "\n \"upsert_embedding_id\": 1,\n \"same_embedding_id_reused\": true,\n \"counts\": {\n \"audio_embedding\": 1,\n \"audio_embedding_vector_192\": 1\n },\n \"final_state\": {\n \"embedding_id\": 1,\n \"asset_id\": 1,\n \"window_id\": null,\n \"checksum\": \"checksum-v2\",\n \"embedding_uri\": \"inline://asset-probe-upsert\",\n \"metadata_json\": {\n \"probe\": \"asset_level_upsert_v2\"\n },\n \"vector_literal\": \"[0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2,0.2]\"\n },\n \"passed\": true\n}\n", | ||
| 27 | "stderr_tail": "", | ||
| 28 | "passed": true | ||
| 29 | }, | ||
| 30 | "summary": { | ||
| 31 | "selected": [ | ||
| 32 | "prereq_audit", | ||
| 33 | "worker_contract_smoke", | ||
| 34 | "semantic_vector_negative_matrix", | ||
| 35 | "asset_level_upsert_validation" | ||
| 36 | ], | ||
| 37 | "executed_count": 4, | ||
| 38 | "all_passed": true | ||
| 39 | } | ||
| 40 | } | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | #!/usr/bin/env /usr/local/miniconda3/bin/python | ||
| 2 | from __future__ import annotations | ||
| 3 | |||
| 4 | import argparse | ||
| 5 | import json | ||
| 6 | import os | ||
| 7 | from pathlib import Path | ||
| 8 | import subprocess | ||
| 9 | from typing import Any | ||
| 10 | |||
| 11 | ROOT = Path(__file__).resolve().parents[1] | ||
| 12 | DEFAULT_PLAN = ROOT / 'data' / 'pgvector_eval' / 'music20' / 'phase1_extraction_plan_report.json' | ||
| 13 | DEFAULT_OUTPUT = ROOT / 'data' / 'pgvector_eval' / 'music20' / 'planner_validation_commands_runner_report.json' | ||
| 14 | |||
| 15 | |||
| 16 | def main() -> None: | ||
| 17 | ap = argparse.ArgumentParser() | ||
| 18 | ap.add_argument('--plan', default=str(DEFAULT_PLAN)) | ||
| 19 | ap.add_argument('--dsn', required=True) | ||
| 20 | ap.add_argument('--output', default=str(DEFAULT_OUTPUT)) | ||
| 21 | ap.add_argument('--only', nargs='*') | ||
| 22 | args = ap.parse_args() | ||
| 23 | |||
| 24 | plan = json.loads(Path(args.plan).read_text(encoding='utf-8')) | ||
| 25 | commands: dict[str, str] = plan['validation_commands'] | ||
| 26 | selected = args.only or list(commands.keys()) | ||
| 27 | report: dict[str, Any] = {} | ||
| 28 | |||
| 29 | for key in selected: | ||
| 30 | if key not in commands: | ||
| 31 | raise SystemExit(f'unknown validation command: {key}') | ||
| 32 | cmd = commands[key] | ||
| 33 | proc = subprocess.run( | ||
| 34 | cmd, | ||
| 35 | cwd=ROOT, | ||
| 36 | shell=True, | ||
| 37 | text=True, | ||
| 38 | capture_output=True, | ||
| 39 | env={**os.environ, 'PG_DSN': args.dsn}, | ||
| 40 | ) | ||
| 41 | report[key] = { | ||
| 42 | 'command': cmd, | ||
| 43 | 'returncode': proc.returncode, | ||
| 44 | 'stdout_tail': proc.stdout[-1200:], | ||
| 45 | 'stderr_tail': proc.stderr[-1200:], | ||
| 46 | 'passed': proc.returncode == 0, | ||
| 47 | } | ||
| 48 | |||
| 49 | report['summary'] = { | ||
| 50 | 'selected': selected, | ||
| 51 | 'executed_count': len(selected), | ||
| 52 | 'all_passed': all(item['passed'] for key, item in report.items() if key != 'summary'), | ||
| 53 | } | ||
| 54 | out = Path(args.output) | ||
| 55 | out.parent.mkdir(parents=True, exist_ok=True) | ||
| 56 | out.write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding='utf-8') | ||
| 57 | print(json.dumps(report, ensure_ascii=False, indent=2)) | ||
| 58 | |||
| 59 | |||
| 60 | if __name__ == '__main__': | ||
| 61 | main() |
| 1 | ## 2026-06-04 | 1 | ## 2026-06-04 |
| 2 | 2 | ||
| 3 | - 新增 `scripts/run_planner_validation_commands_live.py` 与 `planner_validation_commands_runner_report.json`,可直接读取 `phase1_extraction_plan_report.json` 中的 `validation_commands` 并批量执行;当前 4 条 entrypoints 已全部执行成功,`executed_count=4`、`all_passed=true`。 | ||
| 3 | - 更新 `phase1_validation_commands_execution_report.json`,补齐 planner 中剩余两条 validation commands 的直接执行证据:`semantic_vector_negative_matrix` 与 `asset_level_upsert_validation` 也已 `returncode=0`,当前 4 条 validation entrypoints 已全部验证可被脚本直接消费。 | 4 | - 更新 `phase1_validation_commands_execution_report.json`,补齐 planner 中剩余两条 validation commands 的直接执行证据:`semantic_vector_negative_matrix` 与 `asset_level_upsert_validation` 也已 `returncode=0`,当前 4 条 validation entrypoints 已全部验证可被脚本直接消费。 |
| 4 | - 新增 `phase1_validation_commands_execution_report.json`,直接从 `phase1_extraction_plan_report.json` 读取并执行 `validation_commands.prereq_audit` 与 `validation_commands.worker_contract_smoke`,两条命令均返回 `0`,证明 planner 产物可被脚本化直接消费。 | 5 | - 新增 `phase1_validation_commands_execution_report.json`,直接从 `phase1_extraction_plan_report.json` 读取并执行 `validation_commands.prereq_audit` 与 `validation_commands.worker_contract_smoke`,两条命令均返回 `0`,证明 planner 产物可被脚本化直接消费。 |
| 5 | - 更新 `scripts/plan_phase1_extraction_jobs_live.py` 与 `phase1_extraction_plan_report.json`,除了 per-job `command_suggestions` 之外,又补充了 `validation_commands`:`prereq_audit`、`worker_contract_smoke`、`semantic_vector_negative_matrix`、`asset_level_upsert_validation`,使 planner 本身也成为下次 session 的执行入口。 | 6 | - 更新 `scripts/plan_phase1_extraction_jobs_live.py` 与 `phase1_extraction_plan_report.json`,除了 per-job `command_suggestions` 之外,又补充了 `validation_commands`:`prereq_audit`、`worker_contract_smoke`、`semantic_vector_negative_matrix`、`asset_level_upsert_validation`,使 planner 本身也成为下次 session 的执行入口。 | ... | ... |
| ... | @@ -240,3 +240,25 @@ flowchart TD | ... | @@ -240,3 +240,25 @@ flowchart TD |
| 240 | - `validation_commands.asset_level_upsert_validation` | 240 | - `validation_commands.asset_level_upsert_validation` |
| 241 | 241 | ||
| 242 | 这意味着下次启动时可以先跑“全局验证入口”,再决定是否执行具体 job,而不必手工拼测试命令。 | 242 | 这意味着下次启动时可以先跑“全局验证入口”,再决定是否执行具体 job,而不必手工拼测试命令。 |
| 243 | |||
| 244 | |||
| 245 | ## 6.2 当前推荐的一键验证入口 | ||
| 246 | |||
| 247 | 如果只是想先确认当前 host 是否具备继续推进 Phase-1 的条件,推荐优先执行: | ||
| 248 | |||
| 249 | ```bash | ||
| 250 | cd /workspace/acr-engine | ||
| 251 | /usr/local/miniconda3/bin/python scripts/run_planner_validation_commands_live.py --dsn 'postgres://d2:d2pass@127.0.0.1:5432/d2' --output data/pgvector_eval/music20/planner_validation_commands_runner_report.json | ||
| 252 | ``` | ||
| 253 | |||
| 254 | 它会直接读取 `phase1_extraction_plan_report.json` 的 `validation_commands`,并批量执行: | ||
| 255 | |||
| 256 | - `prereq_audit` | ||
| 257 | - `worker_contract_smoke` | ||
| 258 | - `semantic_vector_negative_matrix` | ||
| 259 | - `asset_level_upsert_validation` | ||
| 260 | |||
| 261 | 当前 live 结果: | ||
| 262 | |||
| 263 | - `executed_count = 4` | ||
| 264 | - `all_passed = true` | ... | ... |
| ... | @@ -198,6 +198,7 @@ sed -n '1,320p' acr-engine/sql/acr_pg_schema_v2.sql | ... | @@ -198,6 +198,7 @@ sed -n '1,320p' acr-engine/sql/acr_pg_schema_v2.sql |
| 198 | - `scripts/run_phase1_prereq_audit_live.py` 已给出当前 host 的先决条件审计:`downloads_root_exists=false`、`ready_jobs=0/5`,并把 `torch/torchaudio/transformers/speechbrain` 的缺失状态按 job 落成 JSON 报告 | 198 | - `scripts/run_phase1_prereq_audit_live.py` 已给出当前 host 的先决条件审计:`downloads_root_exists=false`、`ready_jobs=0/5`,并把 `torch/torchaudio/transformers/speechbrain` 的缺失状态按 job 落成 JSON 报告 |
| 199 | - `phase1_extraction_plan_report.json` 现已附带 `validation_commands`,下次 session 可以直接从 planner 复制 `prereq_audit / worker_contract_smoke / semantic_vector_negative_matrix / asset_level_upsert_validation` 四类命令 | 199 | - `phase1_extraction_plan_report.json` 现已附带 `validation_commands`,下次 session 可以直接从 planner 复制 `prereq_audit / worker_contract_smoke / semantic_vector_negative_matrix / asset_level_upsert_validation` 四类命令 |
| 200 | - `phase1_validation_commands_execution_report.json` 已证明 planner 里的 4 条 validation commands 都可以被直接脚本消费且 `returncode=0`:`prereq_audit`、`worker_contract_smoke`、`semantic_vector_negative_matrix`、`asset_level_upsert_validation` | 200 | - `phase1_validation_commands_execution_report.json` 已证明 planner 里的 4 条 validation commands 都可以被直接脚本消费且 `returncode=0`:`prereq_audit`、`worker_contract_smoke`、`semantic_vector_negative_matrix`、`asset_level_upsert_validation` |
| 201 | - `scripts/run_planner_validation_commands_live.py` 已把这 4 条 validation commands 收敛成通用 runner;当前 `planner_validation_commands_runner_report.json` 显示 `executed_count=4` 且 `all_passed=true` | ||
| 201 | - `phase1_hot_reference_v1` 在 `acr_test` 里已经真实补齐 `20` 个 reference members,因此 worker dry-run 当前看到的 scope 已是 `20 recordings / 20 assets / 20 windows` | 202 | - `phase1_hot_reference_v1` 在 `acr_test` 里已经真实补齐 `20` 个 reference members,因此 worker dry-run 当前看到的 scope 已是 `20 recordings / 20 assets / 20 windows` |
| 202 | - worker contract 现在已有基础前置状态保护;重复执行同一 chromaprint dry-run job 会被 `expected_status=pending` 明确拒绝,证据见 `phase1_worker_double_claim_guard_report.json` | 203 | - worker contract 现在已有基础前置状态保护;重复执行同一 chromaprint dry-run job 会被 `expected_status=pending` 明确拒绝,证据见 `phase1_worker_double_claim_guard_report.json` |
| 203 | - exact lane 的 `run_chromaprint_job.py` 已具备非 dry-run 写入路径;当前在 `acr_test` 的 live 结果是因为 `/workspace/downloads/...` 缺失而明确 `failed`,不是继续假装 `completed` | 204 | - exact lane 的 `run_chromaprint_job.py` 已具备非 dry-run 写入路径;当前在 `acr_test` 的 live 结果是因为 `/workspace/downloads/...` 缺失而明确 `failed`,不是继续假装 `completed` | ... | ... |
-
Please register or sign in to post a comment