# 依頼 v12：画面なしの実行ファイルと夜の実行係を作り、最初の夜（60回）を回せるようにする（2026-10-25）

v11 で ServiceSim を新しいプロジェクト（`/Users/shimazueiichi/Robotics_UX/ServiceSim/`）に分け、同じ結果が出るのを確かめたあとに進める。全体の設計は同じフォルダの `night_runs_design_v0.md`。

目的：エディタを開かずに、段階Bと同じ回し方の1回を何本も同時に走らせ、夜のあいだに並べた回を全部回し、朝には判定まで済んでいる状態にする。

## 変えないもの

- 店の回し方・ロボットと人の動き・記録の中身（v11 で確かめた状態）。今回は回し方の入れ物を作るだけ
- 1コマ0.05秒で回すこと（段階Bと同じ時間の進め方）
- 台帳の列。今までの行
- Robotics_UX_New には触らない

## 1. 画面なしの実行ファイルを作る

- エディタのスクリプト（例：`Assets/ServiceSim/Editor/BuildHeadless.cs`）で作る。メニューからも、コマンド（`-batchmode -executeMethod`）からも作れるようにする
- 入れるシーンは、ビルドのコードの中で直接指定する（`BuildPipeline.BuildPlayer` に渡すシーンの一覧）
- 出力：`Builds/headless/`（VCS に入れない）。そばに `build_info.json`（作った日時・ServiceSim/cs 番号・エディタのバージョン）を置く
- macOS 向けの普通の実行ファイルで、`-batchmode -nographics` で起動して回す。Dedicated Server 向けのほうが向いていれば、理由を書いてそちらでもよい

## 2. 実行ファイルの1回の回し方

1本の実行ファイル = 1条件 × 1種 を1回回して終わる。

- 引数（例）：`-ssCondition fam_p1_s4_r1_a42 -ssSeed 3 -ssLabel night -ssNight 20261026`
- 条件は、段階Bと同じ所（serving-robot-params.json の unity_conditions・店の形）から引く。段階Bの Run All と同じコードを通る形にする（回し方を2通りに分けない）
- 画面に関わるもの（カメラ・録画・キッチンの屋根のモニター・字幕・スクリーンショット）は、画面なしのときは切る。数字に効かないことを確かめる（3-B）
- 出力フォルダ：`service_sim/unity/{日付}_{ラベル}_{ServiceSim の cs}_{条件}_s{種}/`（例：`20261026_night_ss12_fam_p1_r1_s3`）。中身のファイルは段階Bと同じ
- run_info.json に足す：`runner`（headless）・`build_id`・`night`・`parallel`（同時に何本走っていたか）・`seed`
- 終わり方：最後まで回った = 終了コード0、途中で止まった = 2、失敗 = 1
- 書き出す前に KIOXIA がつながっているかを確かめる。つながっていなければ何も書かずに終了コード1で終わる（Mac の中に書かない）

## 3. 台帳に同時に書かない

何本も同時に台帳 unity_ledger_v1.csv に1行足すので、鍵をかける。

- 鍵ファイル：`service_sim/unity/unity_ledger_v1.lock`（排他で開けたら書き、閉じる。開けなければ少し待って何度か試す）
- 今の追記のガード（実体のヘッダとコードの列の並びが違えば書かない）は残す
- `unity_cs` は `ServiceSim/cs:N` の形（v11 と同じ）

## 4. 夜の実行係（新しいプロジェクトの `tools/`・Python の標準ライブラリだけ）

### make_queue.py：並べる
- 条件 × 種の一覧を `queue.json` に書く
- 最初の夜：段階Bと同じ6条件（③⑦ × ロボット0・1・2台・スタッフ4・普通の混み具合・上げ膳だけ・1往復で3卓）× 種0〜9 ＝ 60回

### night_runner.py：回す
- `python3 tools/night_runner.py --queue queue.json --parallel N --night 20261026`
- 始める前に KIOXIA がつながっているか、実行ファイルがあるかを確かめる。どちらかがなければ始めない
- `caffeinate` で Mac がスリープしないようにする（実行係が終わったら解ける形）
- N 本まで同時に実行ファイルを起動する。1本終わったら次を起動する
- 台帳で、同じ night・同じ条件・同じ種がすでに completed の回は飛ばす（途中で止まっても続きから回せる）
- 1回の時間の上限（例：90分。3-C の実測で決める）を超えたら止め、実行係が status = stopped の行を台帳に1行書く（鍵をかけて）。落ちた回は failed の行を書く
- 途中で KIOXIA が外れたら、新しい回を始めずに待ち、走っている回が終わったら止まる
- 時刻では止めない（並べた回が全部終わるまで回す。エイイチの決定）
- 記録：`service_sim/unity/night/{night}/runner_log.txt`（いつ・どの回を・何本目で始めて、どう終わったか・実時間）
- 止まった・落ちた回は、その夜のうちに1度だけやり直す。やり直しの出力フォルダは名前の後ろに `_try2` を付ける（台帳は「同じ出力フォルダの行を2度書かない」決まりなので、同じ名前を使わない）
- 全部終わったら判定を呼ぶ：`python3 tools/judge_night.py --runs '{night}_night_*' --out night/{night}`（service_sim/unity/ で。同じ日のほかの回を混ぜないよう、ラベルまで含めて指定する）

### judge_night.py：判定
- 同じフォルダの `judge_night_v0.py` を `tools/judge_night.py` として入れる（中身は Claude が書いた。変えずに入れる。直したほうがよい所があれば報告に書く）
- 出力フォルダの名前の付け方が変わるので、`--runs` の glob が新しい名前に合うかだけ確かめる

## 5. 確かめ

**A. Claude Code が見る**
- 実行ファイルが作れる。build_info.json が出る
- 店の中の時間30分で止める短い1回（③1台・種1）が、画面なしで最後まで回り、段階Bと同じファイルが全部出る
- 2本同時に短い回を走らせて、台帳に2行がきちんと入る（行が混ざらない・ヘッダが壊れない）

**B. 画面なしでも同じ結果か（エイイチが押す・Claude Code が比べる）**
- ③1台・種1 を、画面なしで最後まで1回回す
- v11 で回したエディタの同じ回と並べる（v11 で同じ種なら同じ数字が出ると分かっていれば、数字が全部同じになるはず）
- 違えば、どこから違うかを報告して止める

**C. 何本同時に回せるか（実測して決める）**
- 同じ条件（③2台・種0〜2）を、1本ずつ・2本同時・3本同時で回し、1回あたりの実時間と、1時間に終わる回の数を並べる
- そのときの CPU とメモリの使い方（アクティビティモニタ や `top` の値でよい）
- 1時間に終わる回の数がいちばん多く、メモリが足りている本数を N にする。60回にかかる見込みの時間も書く
- 3本同時で1回が遅くなりすぎる・メモリが足りないなど、困る所があればそれも書く

**D. 最初の夜の前に**
- 台帳に書く所（3の鍵と、実行係が stopped / failed の行を書く所）は、台帳を壊すと戻しにくいので、codex にレビューをかける（code_review_request_template.md の形で。依頼文は Claude が作る）
- 最初の夜を始める前に、台帳を `archive/unity_ledger_v1_prenight_{night}/` に写しておく（コピーのみ）

**E. 最初の夜（エイイチが1つのコマンドで始める）**
- 報告に、エイイチが打つコマンドを1行で書く（make_queue.py と night_runner.py）
- 60回が終わったら、判定の judge.md を Claude が読んで、基準データ v3 にするかをエイイチに相談する

## 報告

- 作った・直したファイルと、変えた所の説明
- 確かめ A〜C の結果（C は表で）。D のレビューは、報告を見てから Claude が依頼文を作る
- 決めた N と、60回の見込みの時間
- 最初の夜のコマンド
- check-in の番号
- この依頼どおりにすると困る所があれば、直す前に書いて止める

報告は `unity/claude_code_reports/` に、今までと同じ形の名前で置く。
