Repository navigation
[scripts][eval] ローカル LLM を使う live 系の評価スクリプトが、マシン全体の重い処理の枠を自分で取らない #649
Copy link
Copy link
Closed
Description
背景
ローカルの LLM(LM Studio・Ollama)を使う重いテストや評価が重なると、マシンのメモリが足りなくなります。利用者の決定(2026-10-10)で、重い処理はマシン全体で同時に 1 本だけにします。cargo のテストは、各 worktree の cargo の設定(テストのバイナリの runner)で、枠を取るスクリプト(with-heavy-lock)を通るようにしました。ただし、Python の評価スクリプトは cargo を通らないので、今は「with-heavy-lock python3 … で起動する」という決まりに頼っています。
問題
ローカル LLM や実際の provider を使う live 系の評価は、自分では枠を取りません。直接起動すると、ほかの重い処理と重なります。共通の Ollama POST だけを保護しても、評価が子プロセスで起動する実 product の LLM 呼び出しは覆えません。
着手前調査では live 評価の CLI 入口が 5 本見つかりました。LM Studio 専用の Python 評価入口は現行コードにはなく、将来 provider が増えても CLI 境界で保護できる構成にします。
対処の方向(着手前調査に基づく案)
- 枠の取得・解放・待ち時間の記録を、共通の context manager に集約します。次の live CLI の呼び出し全体を、ローカル LLM や実際の provider を呼ぶ前から包みます。
- goal_verify live campaign:旧 runner と v3/v4、および contract で指定した live smoke。
- goal_verify の旧 blind review:実ローカル reviewer の評価。
- goal_verify recovery-v4:実 product を起動する recovery smoke。
- 通常の matrix 評価:dry-run を除く実行全体。cloud-only の実 provider 評価も含めます。
- preflight:明示的な live-provider-smoke を指定した処理だけ。
- 枠の場所は
HEAVY_LOCK_DIRで変えられるようにし、既定は参照に記した wrapper と同じにします。atomic なmkdir、PID と起動情報の記録を同じ形で使います。別方式の lock に置き換えません。 - 正の PID を読み取れ、持ち主のプロセスが消滅したことを確認できた lock を回収します。PID の記録前の隙間、壊れた PID、権限不足を「持ち主がいない」と推定して消しません。取得に失敗したまま live 処理を始めません。
HEAVY_LOCK_HELDが非空なら再取得しません。自分で取得した場合は子へ引き継ぎ、自分が取得した枠だけを解放します。正常終了・例外・中断時の子プロセスと解放順を確認します。- 待った時間を monotonic clock で測り、評価 run の専用メタデータ JSONL に invocation ごとに追記します。通常評価では既存の
extras_jsonにも関連づけます。入れ子の待ち時間はその invocation 自身の待ちであり、外側 wrapper の待ち時間とは区別します。 - 可変の待ち時間を frozen manifest、raw 記録、hash ledger、既存 runtime event に混ぜません。TSV の列や既存 schema_version を変更せず、実行時間・provider timeout・既存 scheduler 待ち時間の計測も維持します。
- 決定的な評価・テスト、dry-run、通常 preflight、モデル一覧の GET には枠を取りません。Ollama 互換の固定応答 server を使う deterministic recovery/confirmatory も対象外です。デモ録画と任意 command の汎用 launch は今回の範囲に含めません。
- CLI の取得呼び出し追加は計 30〜50 行程度を見込みます(既存行の再インデントを除く)。共通実装は 160〜240 行、新規テストは 260〜420 行程度が目安です。
- 既存の frozen source/exact-SHA/証跡の確認は残します。新しいコードで live 採取する際は新しい contract と run を用い、共通実装も source/hash の対象へ含めます。旧契約や歴史的証跡を修正して通しません。
受け入れ条件
- 対象の live 評価を 2 本同時に起動すると、2 本目は 1 本目が終わるまで待ちます。既存 wrapper を使うほかの処理とも同じ枠で排他されます。
- 全世代の live campaign、旧 blind review、recovery smoke、非 dry-run matrix、明示的 provider smoke の入口で取得することをテストで固定します。実 product の子プロセス経由の LLM 呼び出しも取得範囲に含めます。
- 消滅した持ち主の回収、生存/不明な持ち主の保護、入れ子での取得省略、子への引き継ぎ、自分の枠だけの解放、正常・例外・中断時の扱いをテストで固定します。stale の回収と複数待機者の競合も確認し、未確認の排他保証を成功扱いにしません。
- テストは既存の unittest 形式に合わせ、一時ディレクトリと無害な子プロセス/mock を使います。実 LLM・実 provider・マシン共通の本番枠・秘密ファイルへ依存しません。
- 枠を待った時間と入れ子の区別を評価の記録に残します。再開でも過去の待ち時間記録を上書きせず、既存の manifest/raw/ledger の整合性、TSV header、schema を維持します。
- 決定的な評価・テストには取得処理や枠待ちを足しません。dry-run と通常 preflight も枠を待ちません。既存の実行時間・timeout・採点の意味を変えません。
- 新規 focused test と対象 Python の Ruff を実行し、結果を証跡に残します。既存 CI が新規テストを自動実行するとみなさず、この Issue の検証ゲートに focused test を明示します。
- 既存の検証・受入・証跡・リリースゲートを緩めていません。honest-failure 方針を維持し、歴史的な証跡を書き換えません。
対象ファイル
scripts/eval_lib/heavy_lock.py(新規:共通の枠取得・解放・待ち時間記録)tests/eval/test_heavy_lock.py(新規:排他・互換性・stale・入れ子・入口配線の unittest)scripts/eval-goal-verify-live.py(既存:全 live campaign 世代の入口)scripts/eval-goal-verify-blind.py(既存:実ローカル reviewer の入口)scripts/eval-goal-verify-recovery-v4.py(既存:実 product recovery smoke の入口)scripts/eval-run.py(既存:非 dry-run matrix の取得と既存 extras への関連づけ)scripts/eval-preflight.py(既存:明示的 provider smoke だけの取得)
参照
- 調査基準:develop
9047eb35631ef468a3cdd4dc491e6cf19e166def。fetch 後の origin/develop と一致を確認済み。 - 枠を取るスクリプト:
/Volumes/SSD_NX/tmp/heavy-lock/with-heavy-lock:14、:24、:25、:33、:34、:38。既定の lock は/Volumes/SSD_NX/tmp/heavy-lock/slot.d、内部にpidとcmdを記録します。 - 枠の説明:
/Volumes/SSD_NX/tmp/heavy-lock/README.md:17。 - 決定の記録:
workspace/tmp/1007/wave1/ledger.md(本調査では内容を変更していません)。 - 着手前調査:
workspace/tmp/1007/wave1/results/H-22/report.md。 - 本文更新案:
workspace/tmp/1007/wave1/issue-bodies/649-after1.md。
根拠
- live campaign の入口と schema 分岐:
scripts/eval-goal-verify-live.py:67、:101。Ollama POST:scripts/eval_lib/goal_verify_live.py:226、:262、:597。v3/v4 の provider:scripts/eval_lib/goal_verify_live_v3.py:147、:447とscripts/eval_lib/goal_verify_live_v4.py:114、:440。 - 実 product 経由の LLM:
scripts/eval_lib/goal_verify_baseline_product_v3.py:40、:122。recovery の既定 baseline:scripts/eval_lib/goal_verify_recovery_live_v4.py:77、:118、:668。 - 旧 blind review の実 reviewer:
scripts/eval_lib/goal_verify_blind.py:130、:192。 - 通常評価の dry-run 終了と実行:
scripts/eval-run.py:156、:162、:178、:186、:699。 - preflight の実 smoke と一覧 GET の違い:
scripts/eval-preflight.py:97、:111、:119、:122。実 provider POST:scripts/eval_lib/models.py:143、:172、:184。 - 決定的 recovery と confirmatory:
scripts/eval_lib/goal_verify_recovery_deterministic_smoke.py:385、:992、:1014、scripts/eval_lib/goal_verify_recovery_deterministic_pair.py:825、:858、scripts/eval_lib/goal_verify_recovery_confirmatory.py:230。 - schema を維持できる既存 extras:
scripts/eval_lib/run_summary.py:231、:465、:476、:495(調査基準版)。frozen manifest と raw の検証:scripts/eval_lib/goal_verify_live.py:93、:97、:548。 - 既存テストの形式:
tests/eval/test_goal_verify_live.py:9、:75とtests/eval/test_eval_run_dry.py:13、:64。現行 CI の eval テスト指定:scripts/ci.sh:28〜:30。
関連(参考)
- [ci] 前提の整備が必要な CI チェック 6 件(panic 系 lint・help 突合・ブラックボックス・allow の理由・変異テスト・PTY 夜間) #536
- H-22:読み取り調査のみ。Issue の編集・実装・評価の実行は行っていません。
DONE: H-22 #649 対象 7 ファイル
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
Merge pull request #660 from Kewton/feature/issue-649-scripts-eval-ll…
Kewton commentedon Oct 12, 2026
PR #660 で merge しました(develop 966e351、CI・acceptance success)。