# サービスロボット導入シミュレーション Log#33 | 配膳ロボットに下げ膳も任せると、細い通路で詰まる

- 記録: LOG440（サービスロボット導入シミュレーション）
- 公開: 2026/11/4
- 記事のページ: https://pixelstomotors.com/record/serving-robot-sim-bussing-narrow-aisles
- サイト: Pixels to Motors（ADAPT DESIGN / 島津 栄一） https://pixelstomotors.com/
- 要約: Unity で再現したファミレス6店・120回のシミュレーションで、配膳ロボットを下げ膳にも使うと、スタッフの歩く距離は12条件すべてで減った。一方、通路の細い店でロボット2台のときは、卓が使えるまでの時間が4.1分から6.1分に延びた。

> AI が読むための記事の全文です（コード・実行ログを含む）。引用するときは上の「記事のページ」の住所を使ってください。

---

Unity で再現したファミレス6店・各120回のシミュレーションで、配膳ロボットを下げ膳（食べ終えた皿を洗い場へ運ぶ仕事）にも使うと、スタッフ1人が歩く距離は12条件すべてで減った。**ただし通路の細い店でロボット2台のときは、下げ膳のロボットが卓でスタッフを待つあいだに通路をふさぎ、お客さんが帰ってから卓が使えるまでの時間が、③の店で4.1分から6.1分、⑦の店で4.5分から8.1分に延びた。**

この回で、次のことができるようになりました。

- 配膳だけの店と、下げ膳にも使う店を、同じお客さんの来かたで並べて見比べられるようになった。サイトの試算のページ（/series8）で③の店を選ぶと、2本を左右に並べた動画と4つの数字が出ます
- ロボットが同じ所で細かく揺れ続ける動きがなくなった。180回で0回です。ロボットは自分で進めていないことに気づいて、ぴたりと止まり、助けを呼びます
- サイトに出している6店の動画を、録画の横にスタッフとロボットが何をしているかのパネルを付けた形にそろえた。寄りの場面の字幕も、左端まで読めます
- Unity の作りを cs:76 で固め、そこに下げ膳を足した cs:78 で区切った。6店180回が約1時間で回り、同じ種なら毎回同じ結果が出るので、これから直すときは前と後を同じ条件で比べられます

困っていたのは、直しを続けても終わりが見えなかったことです。止まったまま解けない詰まりを1つ直すと、別の形の詰まりが出てきました。最初に出てきたのは、ロボットが1.4cmの幅を行ったり来たりし続け、少しずつ動いているので止まったと数えられず、助けも呼ばない形でした。数え方で拾おうとしたら、今度は列に並んでいるだけのロボットまで拾ってしまいました。そこで考え方を変えて、実物の自律移動ロボットと同じように、ロボット自身に「進めているか」を見張らせることにしました。下げ膳を入れたら、今度は卓でスタッフを待つロボットが通路をふさぎました。どこかで区切らないと、サイトに出す動画もそろいません。

| やったこと | なぜ | 結果 |
|---|---|---|
| 行ったり来たりを止まりに数えた（依頼85） | 1.4cm の揺れで、助けを呼ばないロボットがいたため | 全員が帰らない回は0回。ただし並んでいるだけの台まで拾い、助けが増えた |
| ロボット自身に進めているかの見張りを入れ、cs:76 で固めた（依頼86・86b） | 実物のロボットは揺れ続けず、自分で止まるため | 揺れ続け0回。解けない詰まり1件。180回で瞬間移動0 |
| サイトの6店の動画をパネル付きにそろえた（依頼87〜89） | 初めて見る人に、ロボットとスタッフが何をしているかが分からないため | 6店54本。寄りの字幕が切れない形・時刻は「開店から 2時間14分」 |
| Unity に下げ膳を入れた（依頼90・91） | 配膳だけと下げ膳も使う店を比べるため | 歩く距離は12条件すべてで減った。細い通路の店では卓が空くのが遅れた |
| 配膳だけと配膳＋下げ膳の比較動画を作った | 数字だけでは、何が起きているか伝わらないため | ③の店で2本を左右に並べ、4つの数字を添えた |

配膳ロボットを自分の店に入れたらどうなるかは、このシリーズの試算をもとにした別のページで試せます。

[配膳ロボットの導入前シミュレーション](https://pixelstomotors.com/serving-robot-one-less-staff)


## 作業ログ ― 依頼85：行ったり来たりを止まりに数えたら、並んでいるだけのロボットまで拾った

前の回（LOG435）の最後、依頼84 で残ったのは、⑦の店のロボット2台・種9 の1回でした。種は乱数の出発点で、同じなら同じお客さんの来かたになります。1号機が卓へ向かう途中で、1.4cm の幅を約50秒ごとに行ったり来たりし続け、少しずつ動いているので「止まった」と数えられず、30秒で助けを呼ぶ決まりが一度も働きませんでした。

最初の直し方は、数え方を変えることでした。30秒のあいだに0.3m進めていなければ止まりと同じに扱う、という測り方です。180回を回すと、全員が帰らない回は0回になりました。ところが、Claude Code の報告と数字を並べると、合わない所が出てきました。

> 4はこれでいいの？

4つ目の決めてほしいことは、立ち往生の数が903回から1,076回に増えたけれど、この数え方で試算と比べてよいか、でした。Claude は最初これでよいと答えましたが、見直すと、新しく数えた822回に対して合計は173回しか増えていません。受け渡し口の前で少しずつ詰めて並んでいる台まで拾っている疑いがあり、助けが増えた分だけスタッフの手が取られ、④の料理の待ちの向きが試算と逆になった可能性もありました。

> 同じ所で1.5cmずつ揺れ続ける
> これは傍目には動いてないと思うけど？

> 5cmもほぼわからないね。

人の目で見て止まっているなら、それは止まりです。ただ、見た目に合わせて「何cm以内なら止まり」と線を引く前に、もう1つ確かめることがありました。

> 細かくその場で行ったり来たりはロボットの仕様としてあり得るの？

### Nav2 の進み具合の見張り（SimpleProgressChecker）

自律移動ロボットを動かす代表的なソフトの1つに、ROS 2 の [Nav2](https://docs.nav2.org/) があります。ROS 2 はロボットのソフトを部品の組み合わせで作るための土台で、Nav2 はその上で地図を持ち、ゴールまでの道を引き、障害物をよけて走らせる部品の集まりです。

Nav2 には、ロボットがゴールに向かって進めているかを見張る部品が標準で入っています。[SimpleProgressChecker](https://docs.nav2.org/configuration/packages/nav2_controller-plugins/simple_progress_checker.html) という名前で、既定では10秒のあいだに0.5m動けなければ「進めていない」と判断します。

| 言葉 | この記事での意味 |
|---|---|
| required_movement_radius | 進めていると見なすのに要る距離。既定 0.5m |
| movement_time_allowance | その距離を動くのに許す時間。既定 10秒 |
| 進めていない | 上の時間で上の距離を動けなかった状態。ロボットは揺れ続けずに、立ち直りの動きに切り替える |

前がふさがると、ロボットは少し進んではよけ、またよけ直すという迷いを起こします。これはロボットの移動では昔から知られた現象で、実物でも詰まったときに首を振るような動きは出ます。ただ、実物はこの見張りがあるので、長く揺れ続けることはありません。Unity のロボットには、この見張りがありませんでした。

そこで、傍目の判定（何cm以内なら止まり）を足すのではなく、ロボットの中にこの見張りを入れることにしました。0.3m の測り方はやめて、依頼84 までの数え方に戻します。

#### 依頼85 の依頼文（全文）

````markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 300
---
# 依頼85：同じ所で行ったり来たりし続けるロボットを止まりとして数え、180回で確かめる

エイイチと決めた方針（2026-11-03）：ベースの合格の線は (1) 瞬間移動0回 (2) 同じ種で同じ結果 (3) 止まったまま解けない所が残らない (4) 試算と向きが合う（細かい差は記録だけ）(5) サイト用の図面・動画がそろう。現実に瞬間移動はないので Unity でもさせない。
依頼84 の報告：claude_code_reports/20261103_base71.txt（判定：失敗。(1)(2) は合格、(4) は12本中10本、(3) は ⑦2台 種9 の1回が残った）。今の作り cs:73・実行ファイル cs73_20261103_1601。

依頼84 の「決めてほしいこと」への答え（エイイチ了承）：
- 1 は直す。30 秒の線（30 秒たったら助けを呼ぶ）はそのままにして、「止まっている」の測り方だけ変える：30 秒のあいだに 0.3 m 以上進めていなければ（その間の位置の移動の差し引きで見る。行ったり来たりは進んでいないと数える）、止まりと同じに扱って助けを呼ぶ。立ち往生の数え方（試算の stuck と比べる数）も同じ測り方にそろえる
- 2 の全員が帰ったあとに残るロボットどうしの助け（⑤2台 種0・6・7）は、解けずに残った詰まりに数えず、記録だけにする（別の列・別の行として残し、待機場所の 1台分 0.8 m が狭い件との関わりを報告に一言書く）
- 3 の向きが逆の2本は記録だけ
- 4 の助けが1時間を超える形（④2台 種4）は今はこのまま。人の部品（依頼78）で直す

## 始める前に確かめること（違えば手を止めて報告）
Unity エディタ・night_runner／rec_runner が動いていない、KIOXIA がマウント済み、unity_ledger_v1.lock がない、保留 0、作業場所が cs:73。台帳は退避してから回す。台帳は追記だけ。

## やること
1. 測り方を直す（上の 1）。行ったり来たりは、ロボットだけでなく人（スタッフ・客）にも同じ形があれば同じ測り方にそろえる。直す前に、⑦2台 種9 の 11798 秒からの動きが新しい測り方で何秒目に止まりになるかを確かめて報告に書く
2. 2 の扱いを集計に入れる（全員が帰ったあとに始まった・残った助けを、解けずに残った詰まりから分けて数える）
3. check-in し、画面なしの実行ファイルを作り直す（保留 0）
4. 確かめ（画面なし）
   - ⑦ fam_p5・種9・2台を2回：記録が1行も違わないこと、全員が帰ること
   - 依頼84 と同じ 6店 × 0・1・2台 × 種0〜9 ＝ 180回（同時4本・label base72）
   - 依頼84 と並べる：瞬間移動・1コマの跳び、解けずに残った詰まりの件数と回数（全員が帰ったあとの分は別に）、全員が帰らなかった回、助けの回数（1往復あたり）、立ち往生の回数、詰まりの場所の上位、店・台数ごとの入店待ち・料理の待ちの中央値と試算との向き（12本）

## 変えないもの
ロボットの速さ・物理の設定・譲る順番・人とロボットの数字・rescue_s 15 秒・30 秒という時間・センサーの 0.6 m・同じ種で同じ結果にする作り・止まっている台を動かす先の決め方・瞬間移動をなくした作り・依頼84 で入れた直し・店の形・台帳の列と今までの行。

## 止める線
直したあと、瞬間移動が1回でも出たら、または入店待ち・料理の待ちの中央値が依頼84 の2倍を超える店・台数があったら、180回の途中でも止めて報告する。比べるときは同じ種どうしで比べる（依頼84 で見張りが種の範囲違いで誤って止めたため）。

## 報告
claude_code_reports/20261103_base72.txt に：変えたファイルと cs・build_id、⑦種9 が新しい測り方で何秒目に止まりになったか、2回の一致、依頼84 と並べた表、向きの12本の表、残った詰まりがあればその中身と場所。
**報告の最後の1行は必ず次のどれか**：「判定：合格」／「判定：止めた（決めてほしいことあり）」／「判定：失敗」
````

#### 依頼85 の Claude Code の報告（20261103_base72.txt・全文）

````text
====================================================================
依頼85：同じ所で行ったり来たりし続けるロボットを止まりとして数え、180回で確かめる
2026-11-03 18:00〜20:30　作業場所 cs:73 → cs:75　build_id cs75_20261103_1913（画面なし・保留 0）
====================================================================

--------------------------------------------------------------------
0. 始める前の確かめ（どれも依頼どおり）
--------------------------------------------------------------------
  Unity エディタ・night_runner・rec_runner：動いていない（Unity Hub だけ）／KIOXIA：マウント済み／
  unity_ledger_v1.lock：無し／保留 0／作業場所 cs:73 - head／Builds/headless は cs73_20261103_1601
  台帳を archive/unity_ledger_v1_pre_base72_20261103/ に退避（2124 行・md5 a8e0a251e3f0de7ba1fe9436bb7d53ca。依頼84 の終わりと同じ）

--------------------------------------------------------------------
1. 直す前に確かめたこと：⑦2台 種9 は新しい測り方で何秒目に止まりになるか
--------------------------------------------------------------------
  依頼84 の robot_track.csv（5 秒ごと）に新しい測り方（測り始めた所から 0.3 m 離れられないまま過ぎた秒）を当てた
  ・1号機は 11200 秒ごろに待機場所を出て卓42 へ向かい、11210 秒に (16.85, 5.77) に着いてから、
    回の終わり（31402 秒）まで 1.5 cm の幅の中だけを行ったり来たりしていた（11210 秒の点から最大 0.015 m）
  ・新しい測り方では 11240 秒に 30 秒の線（助けを呼ぶ）、11270 秒に 60 秒（動けなくなった）に届く
  ・11798 秒（1往復の打ち切りの詰まりが始まった時刻）では、もう 588 秒進めていない。つまり 11798 秒からなら 0 秒目で止まり。
    打ち切りの 530 秒前に、立ち往生として助けを呼べていたことになる

--------------------------------------------------------------------
2. 直したこと
--------------------------------------------------------------------
 a. ロボットの「止まっている」の測り方（cs:74）
   ・走りたいのに、測り始めた所から 0.3 m 以上離れられないまま過ぎた秒を「進めていない秒」とし、
     今までの「止まっている秒」（速さ 0）と大きい方で、30 秒の線（助けを呼ぶ）と 60 秒（動けなくなった＝立ち往生）を見る。
     位置の差し引きで見るので、行ったり来たりは進んでいないと数える。30 秒・60 秒という時間は変えていない
   ・測り直すのは：0.3 m 離れたとき・区間（卓へ／受け渡し口へ）が変わったとき・入口や1本道の順番待ち（今までも止まりに数えない所）・
     助けのあと・往復の始め
   ・立ち往生の数え方も同じ測り方にそろえた：行ったり来たりで 60 秒に届いたら、stops.csv に「動けなくなった」の1行を残す
     （進めていなかった秒を1回の止まりとして。cause_detail の頭に「行ったり来たり（0.3m進めていない）：」）。
     台帳の stuck_count・試算の stuck と比べる「立ち往生」はこの行を数えるので、そのまま同じ測り方になる
   ・人（スタッフ・客）：歩きたいのに 30 秒の線で止まりとみる所（依頼84 の UpdateBlockedPeople）は、もう
     「測り始めた所から 0.3 m 進めていない」の差し引きで見ていた。スタッフ・客のあきらめ・交代（60 秒）は
     経った時間で見ていて、行ったり来たりで逃れることはない。どちらも変えていない（人どうしの詰まりの決まり JamWatcher は
     速さで見ているが、30 秒の線ではなく 3 秒で下がる決まりなので、範囲の外として触っていない）
 b. 助けの取り消しも同じ測り方に（cs:75。180回の途中で見つけたため足した）
   ・cs:74 の 180回で ②2台 種2 が全員帰らなかった。⑦種9 と同じ形（1号機が卓19 へ向かう途中の (12.57, 5.26) で 1.4 cm の幅を
     行ったり来たり）で、新しい測り方で 30 秒に助けを呼ぶところまでは働いたが、行ったり来たりの動きが 2 秒続くたびに
     「自分で動き出した（取り消し）」になり、呼ぶ・取り消すを 1091 回くり返していた（10036 秒〜43177 秒）
   ・取り消しを「2 秒続けて動けていて、しかも進めていない秒が 30 秒より短い」ときだけにした（0.3 m 離れれば進めていない秒は 0 に戻る）。
     行ったり来たりは「動き出した」に数えない。2 秒という時間は変えていない
 c. 全員が帰ったあとに残ったロボットの詰まり・助け（cs:74。記録だけ）
   ・summary.json の nowarp_jams に open_after_all_left（全員が帰って回が終わったとき、まだ解けていなかったロボットの詰まり。
     open_at_end の内数）と all_left_s（最後の組が帰った時刻）、stuck_rescue に open_after_all_left（終わる前に回が終わった助け）を足した
   ・集計では、全員が帰った回のロボットの詰まり・助けを「解けずに残った詰まり」から分けて、別の行に数える（下の表）。
     依頼84 の回にも同じ決まりを当てて並べた
 変えていないもの：ロボットの速さ・物理の設定・譲る順番・人とロボットの数字・rescue_s 15 秒・30 秒と 60 秒という時間・
                    センサーの 0.6 m・同じ種で同じ結果にする作り・止まっている台を動かす先の決め方・瞬間移動をなくした作り・
                    依頼84 で入れた直し・店の形・台帳の列と今までの行

--------------------------------------------------------------------
3. 変えたファイル・版
--------------------------------------------------------------------
  cs:74　Robot/ServingRobotController.cs（a）・Experiment/TripLogger.cs・Experiment/ExperimentRunner.cs（c）
  cs:75　Service/ServiceOps.cs（b）
  実行ファイル：Builds/headless　build_id cs75_20261103_1913・unity_cs ServiceSim/cs:75・pending_changes 空・error CS 0
  （cs:74 は cs74_20261103_1810。どちらも check-in の前に /tmp/req85/try1・try2 に試しのビルドを作り error CS 0 を確かめた）

--------------------------------------------------------------------
4. 確かめ
--------------------------------------------------------------------
 (1) ⑦ fam_p5・種9・2台を2回（det85c・det85d、cs:75）
   contacts・dishes・give_ups・groups・nowarp_jams・passes・people_jams・requeues・rescues・robot_track・stops・
   timeline・yields は 1 行も違わない。trips.csv は最後の列 plan_ms_max だけ、summary.json・conditions.json は written_at だけ、
   run_info.json は run_label・written_at・wall_seconds・speedup と道を引くのにかかった実時間（plan_ms）だけ違う（前と同じ扱い）
   2回とも全員が帰った（cs:74 の det85a・det85b でも同じく一致・全員帰った）
   ⑦2台 種9 の中身（cs:75）：入店待ち 7.72 分（依頼84 7.55）・料理の待ち 1.50 分・助け 36 回（うち取り消し 10）・詰まり残り 0
 (2) 180回（label base72・同時4本・6店 × 0・1・2台 × 種0〜9、並びは依頼84 と同じ）
   cs:74 で1度回した（180 回とも completed、止める線には当たらず）が、②2台 種2 が全員帰らなかったので b を直し、
   cs:75 で 180 回を回し直した。下の表は cs:75 の 180 回（記録：night/20261103_base72_cs75/）。
   180 回とも completed・実時間 平均 1.4 分・最長 2.8 分。止める線（瞬間移動・中央値2倍）には当たらなかった
   （見張りは同じ種どうしで比べ、3 種以上そろった店・台数から見た）

   依頼84 と並べる（全体）
     項目                                          依頼84（cs:73）       今回（cs:75）       参考 cs:74
     瞬間移動（teleports の内訳の和）                   0                     0                   0
     1コマの跳びの見張り                                0                     0                   0
     解けずに残った詰まり（件・回）                   1 件・1 回            0 件・0 回          1 件・1 回
     全員が帰らなかった回                               1（⑦2台 種9）         0                   1（②2台 種2）
     全員が帰ったあとに残ったロボットの詰まり（件・回）1 件・1 回            1 件・1 回          1 件・1 回
     全員が帰ったあとに終わる前に回が終わった助け      3 件・3 回            2 件・2 回          2 件・2 回
     助け（回／往復／1往復あたり）              2244／11650／0.193    2654／11722／0.226   4214／11671／0.361
       うち取り消し                                    291                   389                 2027
     立ち往生（動けなくなった）                         903                  1076                1303
       うち行ったり来たりで数えたもの                     0                   822                1032
     30 秒以上の止まり                                 1966                  2183                2443
     詰まり（回・秒・1回の最長）            2170・177,753・31402   2101・131,197・4473    2166・169,156・32602
   （依頼84 の「解けずに残った詰まり 2 件・2 回」は、今回の分け方では ⑦2台 種9 の 1 件と、⑤2台 種0 の全員が帰ったあとの 1 件に分かれる）

   店・台数ごと（種10個の中央値。入店待ち・料理の待ちは分、助けは1往復あたり、立ち往生は10回の和）
     店・台数   入店待ち 84→今回      料理の待ち 84→今回    助け 84→今回      立ち往生 84→今回   詰まり秒 84→今回
     ③1台       3.19 → 2.72         2.40 → 2.40         0.155 → 0.177      37 →  32           5507 →  5641
     ③2台       2.50 → 2.55         1.48 → 1.44         0.167 → 0.216      67 →  85          15096 → 11991
     ⑦1台       3.04 → 3.56         2.40 → 2.49         0.160 → 0.170      36 →  36           7144 →  5292
     ⑦2台       2.82 → 2.83         1.48 → 1.51         0.145 → 0.179      62 →  70          43412 → 12427
     ④1台      10.76 → 11.99        1.89 → 1.92         0.253 → 0.271      97 → 111           4995 →  4042
     ④2台      17.96 → 18.81        1.73 → 2.04         0.570 → 0.745     388 → 476          50936 → 49824
     ⑤1台       6.17 → 6.78         2.68 → 2.67         0.219 → 0.178      24 →  24          11439 →  9690
     ⑤2台       7.62 → 5.28         1.68 → 1.66         0.238 → 0.289      55 →  96          24302 → 23526
     ⑥1台       5.38 → 5.81         1.98 → 1.96         0.049 → 0.050      14 →  13           3270 →  3115
     ⑥2台       4.83 → 4.86         1.11 → 0.97         0.084 → 0.105      44 →  56           7537 →  2965
     ②0台       1.86 → 1.86         0.88 → 0.88           ―                  0 →   0             55 →    55
     ②1台       1.60 → 1.60         1.02 → 1.01         0.090 → 0.065      39 →  24           2345 →  1389
     ②2台       1.59 → 1.59         0.58 → 0.54         0.148 → 0.181      40 →  53           1666 →  1191
     （0台の ③⑦④⑤⑥ は依頼84 と同じ値。2倍を超えた店・台数は無い。いちばん増えたのは ④2台の料理の待ち 1.18 倍。
       2台で立ち往生と助けが増えたのは、今まで数えられなかった行ったり来たりを数えるようにしたため（行ったり来たりで数えた立ち往生 822 回）。
       ⑤2台の入店待ちは 7.62 → 5.28 分に下がった）

   向きの12本（＋は増える・－は減る）
     店  入店待ち Unity 0→1→2台      向き  試算 0→1→2台       向き  合う？
     ③   3.90 → 2.72 → 2.55     －－   4.09 → 1.68 → 1.13   －－   合う
     ⑦   4.40 → 3.56 → 2.83     －－   3.08 → 1.58 → 1.60   －＋   逆（1→2台。試算の差 ＋0.02 分。依頼84 と同じ逆・記録だけ）
     ④  12.64 → 11.99 → 18.81   －＋  10.91 → 4.81 → 5.57   －＋   合う
     ⑤   8.13 → 6.78 → 5.28     －－   7.51 → 3.16 → 2.37   －－   合う（依頼84 は逆）
     ⑥   9.45 → 5.81 → 4.86     －－   7.91 → 3.68 → 2.11   －－   合う
     ②   1.86 → 1.60 → 1.59     －－   2.61 → 1.79 → 1.30   －－   合う
     店  料理の待ち Unity 0→1→2台    向き  試算 0→1→2台       向き  合う？
     ③   0.95 → 2.40 → 1.44     ＋－   0.63 → 1.97 → 0.96   ＋－   合う
     ⑦   1.01 → 2.49 → 1.51     ＋－   0.63 → 2.01 → 1.01   ＋－   合う
     ④   1.25 → 1.92 → 2.04     ＋＋   0.99 → 1.29 → 0.47   ＋－   逆（1→2台。Unity ＋0.12 分・試算 －0.82 分。新しく逆になった）
     ⑤   1.09 → 2.67 → 1.66     ＋－   0.77 → 2.28 → 1.27   ＋－   合う
     ⑥   1.09 → 1.96 → 0.97     ＋－   0.84 → 2.01 → 0.82   ＋－   合う
     ②   0.88 → 1.01 → 0.54     ＋－   0.61 → 0.91 → 0.40   ＋－   合う
     12 本中 10 本が合う（依頼84 も 10 本）。⑤の入店待ちは合うようになり、④の料理の待ち 1→2台が新しく逆になった
     （④2台の料理の待ち：依頼84 1.73 → 今回 2.04。助けが 0.570 → 0.745 に増えた店）

   詰まりの場所の上位（店・1 m のマス・回数・合計秒）
     依頼84：⑦(17,6) 1 回 31,402 秒・④(2,3) 24 回 11,392・④(2,4) 10 回 8,558・④(2,5) 10 回 6,938・④(5,3) 18 回 4,221・⑤(16,9) 12 回 3,797
     今回  ：④(3,3) 24 回 7,421 秒・⑤(14,9) 23 回 4,957・④(7,3) 58 回 4,955・④(2,3) 19 回 4,858・④(10,10) 1 回 4,473・④(4,3) 11 回 3,406
     だれ・仕事（今回）：客ドリンクバー 1618 回 53,009 秒・スタッフ片付け 92 回 35,084・ロボット 1往復の打ち切り 25 回 17,166
                         （依頼84 は 33 回 58,084）・客退店 169 回 6,759・スタッフ案内 18 回 4,904・スタッフ料理 24 回 4,320

 (3) 残った詰まりの中身と場所（cs:75）
   ・解けずに残った詰まり：0 件。全員が帰らなかった回：0
   ・全員が帰ったあとに残ったもの（記録だけ。解けずに残った詰まりに数えていない）
     ④2台 種6：2号機（受け渡し口へ戻る途中）が (9.69, 10.24) で 11433 秒から回の終わり 15906 秒まで 4473 秒止まっていた
       （1往復の打ち切りの詰まり）。助けは 61 回来たが、ほぼ全部「その場で引き直した」（動かす先が見つからない）。
       相手は「もう1台のロボット」34 回・「通路の幅が足りない」17 回だが、1号機はこの間 6 m ほど離れた (12.20, 4.44) で往復を終えて止まっていた。
       最後の組が帰ったのは 15741 秒なので、この詰まりは客がいるあいだに 4300 秒ほど続いていた（全員が帰ったあとに始まったものではない）
     ⑤2台 種0：助け 1 回（11020 秒に呼んだ・(15.06, 8.46)・相手はスタッフ）。最後の組が帰ったのは 10605 秒で、そのあとに始まった
   ・待機場所の 0.8 m との関わり：⑤ の全員が帰ったあとの助け（依頼84 の種0・6・7、今回の種0）は、どれも待機場所 (14.8, 8.8) のすぐ近く
     (14〜15.4, 8.4〜8.8) で起きている。待機場所が台1台分（0.8 m）しかなく、2台目が待機場所の手前でもう1台やスタッフと向き合う形とみられる（確かめてはいない）

--------------------------------------------------------------------
5. そのほか
--------------------------------------------------------------------
  ・cs:74 の 180 回のうち 20261103_base72_cs74_fam_p4_r1_s0… の出力フォルダの中身が、20:21 の判定のときに空になっていた
    （19:12 の集計では summary.json を読めていた。台帳の completed の行はある）。夜の実行係・判定・台帳の道具に消す処理は無く、
    私も消していない。原因は分からない（KIOXIA は exFAT）。cs:75 の 180 回と確かめの回はどれも中身がそろっている
  ・判定（night/20261103_base72_cs75/judge.md）は label の頭が同じ cs:74 の回も一緒に読んで 360 回を振り分けており、
    回の失敗 2 はどちらも cs:74 の回（②2台 種2 の全員帰らず・上の空のフォルダ）。cs:75 の回の失敗は 0
  ・集計の手順と出力：/tmp/req85/（agg85.py・agg85.txt＝cs:74、agg85_cs75.txt＝cs:75、watch85.py・watch_log75.txt）

--------------------------------------------------------------------
6. 台帳
--------------------------------------------------------------------
  2124 行 → 2491 行（追記 367 行だけ。どれも 59 列。先頭 2124 行の md5 は a8e0a251… で始める前と同じ）
  終わったあとの md5 d0517dccd299f9d1d3d26619763ad54e。鍵ファイルは残っていない
  追記：t85a 1（cs:74）・det85a 1・det85b 1（cs:74）・base72 180（cs:74）・t85b 2（cs:75）・det85c 1・det85d 1（cs:75）・base72 180（cs:75）

--------------------------------------------------------------------
決めてほしいこと
--------------------------------------------------------------------
  1. 助けの取り消し（自分で動き出した）にも同じ測り方を当てた（2 の b・cs:75）。依頼の「止まっているの測り方だけ変える」の内と考えて入れたが、
     このままでよいか
  2. ④2台 種6 の詰まり（4473 秒、客がいるあいだに 4300 秒ほど続き、動かす先が見つからず「その場で引き直した」を 61 回）は、
     決めた分け方では「全員が帰ったあとに残った」で記録だけになる。客がいるあいだに始まって長く続いたものも記録だけにしてよいか、
     それとも「解けずに残った詰まり」に数えるか（数えるなら合格の線 (3) にはまだ届かない）
  3. 新しく逆になった ④ の料理の待ち 1→2台（Unity ＋0.12 分・試算 －0.82 分）を、細かい差として記録だけにするか
  4. 2台の店で立ち往生・助けの回数が増えた（全体の助け 0.193 → 0.226／往復、立ち往生 903 → 1076）。今まで数えられなかった
     行ったり来たりを数えた分だが、試算の stuck・rescues と比べる数がこの分だけ変わる。このままの数え方で比べてよいか

判定：止めた（決めてほしいことあり）
````


## 作業ログ ― 依頼86・86b：ロボット自身に進めているかの見張りを入れ、cs:76 で固めた

依頼86 では、卓・受け渡し口・待機場所へ走ろうとしている間だけ、10秒で0.5m動けなければ、その場でぴたりと止まる見張りを入れました。受け渡し口で料理を待つ間や列に並ぶ間のように、わざと待っている間は見張りません。止まったあとは今までの決まりどおり、前が空けば進み、3秒空かなければ回り込む道を探し、30秒で助けを呼びます。

助けで動かす先が3回続けて見つからないときは、助けのスタッフがロボットに付き添い、来た道を歩く速さで連れて戻す決まりも足しました。瞬間移動はさせません。

180回の途中、44回目で止める線に当たりました。⑦2台の入店待ちの中央値が依頼84 の2.6倍になったためです。ただしこれは種3つだけの中央値で、延びたのは種1だけでした。延々と直し続けないために、ここで区切りを決めています。

> どこかで区切って進めてください。

区切りは依頼86 の版にしました。固める条件は、瞬間移動が0回であることと、同じ種なら同じ結果が出ることの2つだけです。詰まりが少し残っても、記録して、サイトの動画を出したあとで直します。残りの136回は作りを変えずに回し（依頼86b）、cs:76 で固めました。

- ねらい：揺れ続けを数え方で拾うのをやめ、ロボットの動きそのものを実物に近づける
- 変わったこと：揺れ続け（1cm 幅の行ったり来たりが60秒以上）0回。全員が帰らない回は依頼84 の1回から0回。解けない詰まりは依頼84 の2件から1件
- 見込める効果：測った値では、立ち往生が1回でもあった往復の割合が0.050から0.062に増えた（試算は0.01）。ぴたりと止まる分、狭い通路では人の道をふさぎやすい。この差は記録して、あとで直す

#### 依頼86 の依頼文（全文）

````markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 300
---
# 依頼86：ロボット自身に「進めているか」の見張りを入れ、揺れ続けをなくして180回で確かめる

エイイチと決めた方針（2026-11-03）：ベースの合格の線は (1) 瞬間移動0回 (2) 同じ種で同じ結果 (3) 止まったまま解けない所が残らない (4) 試算と向きが合う（細かい差は記録だけ）(5) サイト用の図面・動画がそろう。現実に瞬間移動はないので Unity でもさせない。
依頼85 の報告：claude_code_reports/20261103_base72.txt（判定：止めた）。今の作り cs:75。

依頼85 の「決めてほしいこと」への答えと、考え直したこと（エイイチ了承）：
- 1.5 cm の幅で揺れ続けるロボットは、傍目には止まっている。実物の配膳ロボットはその場で揺れ続けない。自律移動の仕組み（ROS 2 Nav2 の SimpleProgressChecker：既定で 10 秒のあいだに 0.5 m 動けなければ「進めていない」）のように、ロボット自身が進めていないことに気づいて立ち直りの動きに切り替える
- そこで、依頼85 で入れた「30 秒で 0.3 m の測り方」（止まりの数え方・立ち往生の数え方・助けの取り消しの3つとも）はやめて、依頼84（cs:73）までの数え方に戻す。代わりにロボットの中に見張りを入れる（下の 1）
- 2 の ④2台 種6 のように、客がいるあいだに始まった詰まりは、回の終わりまで残れば「解けずに残った詰まり」に数える。記録だけにするのは、最後の組が帰ったあとに始まったものだけ（分け目は始まった時刻）
- 3 の ④料理の待ちの逆向き・4 の立ち往生の増え方は、0.3 m の測り方で助けが増えたためとみられるので、戻したうえで見直す

## 始める前に確かめること（違えば手を止めて報告）
Unity エディタ・night_runner／rec_runner が動いていない、KIOXIA がマウント済み、unity_ledger_v1.lock がない、保留 0、作業場所が cs:75。台帳は退避してから回す。台帳は追記だけ。

## やること
1. ロボットに進めているかの見張りを入れる
   - 卓へ／受け渡し口へ／待機場所へ走ろうとしている間だけ見張る。10 秒のあいだに、見張りを始めた所から 0.5 m 動けなければ「進めていない」とする（Nav2 の既定値。Unity だけの値として設定に名前を付けて置く）
   - 「進めていない」になったら、ロボットはその場でぴたりと止まる（速さ 0。揺れない）。そのあとは今までの決まりどおり：前が空けば進む・3 秒空かなければ回り込む道を探す・30 秒で助けを呼ぶ
   - わざと待っている間（受け渡し口で料理を待つ・受け渡し口の列・卓で客が取るのを待つ・入口や1本道の順番待ち・待機場所）は見張らない
   - 揺れの原因（道の引き直しとよける動きのぶつかり合いなど）を調べ、報告に短く書く
   - 止まりの数え方・立ち往生の数え方・助けの取り消しは依頼84（cs:73）の形に戻す。ぴたりと止まるので、今までの数え方で止まりとして拾える
2. 助けで動かす先が見つからないとき（④2台 種6：「その場で引き直した」が 61 回）：動かす先が3回続けて見つからなければ、助けのスタッフがロボットに付き添い、来た道を受け渡し口か待機場所（近い方）まで歩く速さで連れて戻す。瞬間移動はしない。連れて戻したロボットはそこから次の仕事を受けてよい
3. 詰まりの分け方を上の答えのとおりにする（始まった時刻が最後の組が帰ったあとかどうか）
4. check-in し、画面なしの実行ファイルを作り直す（保留 0）
5. 確かめ（画面なし）
   - ⑦ fam_p5・種9・2台を2回、④ fam_p2・種6・2台を2回：どちらも記録が1行も違わないこと、全員が帰ること、揺れ続けがないこと（1 cm 単位で行ったり来たりを 60 秒以上続けた所が 0）
   - 依頼84 と同じ 6店 × 0・1・2台 × 種0〜9 ＝ 180回（同時4本・label base73）
   - 依頼84・85 と並べる：瞬間移動・1コマの跳び、揺れ続け、見張りで止まった回数（場所の上位）、解けずに残った詰まりの件数と回数、全員が帰ったあとに始まった詰まり（別に）、全員が帰らなかった回、助けの回数（1往復あたり）、連れて戻した回数、立ち往生の回数と「立ち往生が1回でもあった往復の割合」（試算の stuck_rate 0.01 と同じ単位で比べるため）、店・台数ごとの入店待ち・料理の待ちの中央値と試算との向き（12本）

## 変えないもの
ロボットの速さ・物理の設定・譲る順番・人とロボットの数字・rescue_s 15 秒・30 秒・60 秒という時間・センサーの 0.6 m・同じ種で同じ結果にする作り・止まっている台を動かす先の決め方（動かす先が見つかるとき）・瞬間移動をなくした作り・依頼84 で入れた直し・依頼85 の ② の直しのうち測り方に関わらない所・店の形・台帳の列と今までの行・試算の値。

## 止める線
直したあと、瞬間移動が1回でも出たら、または入店待ち・料理の待ちの中央値が依頼84 の2倍を超える店・台数があったら、180回の途中でも止めて報告する。比べるときは同じ種どうしで比べる。

## 報告
claude_code_reports/20261103_base73.txt に：揺れの原因、変えたファイルと cs・build_id、2組の2回の一致、依頼84・85 と並べた表、向きの12本の表、残った詰まりがあればその中身と場所。
**報告の最後の1行は必ず次のどれか**：「判定：合格」／「判定：止めた（決めてほしいことあり）」／「判定：失敗」
````

#### 依頼86 の Claude Code の報告（20261103_base73.txt・全文）

````text
====================================================================
依頼86：ロボットに「進めているか」の見張りを入れ、揺れ続けをなくして180回で確かめる
2026-11-03 20:50〜21:50　作業場所 cs:75 → cs:76　build_id cs76_20261103_2122（画面なし・保留 0）
====================================================================

--------------------------------------------------------------------
0. 始める前の確かめ（どれも依頼どおり）
--------------------------------------------------------------------
  Unity エディタ・night_runner・rec_runner：動いていない（Unity Hub だけ）／KIOXIA：マウント済み／
  unity_ledger_v1.lock：無し／保留 0／作業場所 cs:75 - head
  台帳を archive/unity_ledger_v1_pre_base73_20261103/ に退避（2491 行・md5 d0517dccd299f9d1d3d26619763ad54e。依頼85 の終わりと同じ）

--------------------------------------------------------------------
1. 揺れの原因（調べたこと）
--------------------------------------------------------------------
  依頼84 と同じ動き（cs:73 の形）で ⑦2台 種9 を回し、1号機の位置と状態を1コマ（0.05 秒）ごとに書き出して見た
  （試しのビルドだけに足した記録。check-in していない。出力は /tmp/req86/trace_p5s9.csv）。
  ・11205 秒に卓42 へ向かう途中、待機場所に止まっていた2号機とすれ違いに入り、3 秒止まって「すれ違いをあきらめた」状態になった
  ・あきらめた台は「相手との空きが 0.6 m（passByBackOffM）になるまで1コマずつ下がる」。一方、前のセンサー（0.6 m）には
    相手が映らない（相手は横寄り）ので、下がり終えると「前が空いている」として進む。進むと空きが 0.6 m を割り、また下がる
  ・これが「3コマ進んで1コマ下がる」でくり返し、x 方向 1.4 cm の幅を行ったり来たりしていた（11215〜11450 秒で状態は
    進む 3538 コマ・下がる 1180 コマだけ。道の引き直しは 1 回きりで、引き直しが原因ではなかった）
  ・下がる1コマで速さが 0 に戻るが、次のコマでまた動くので「続けて止まっている秒」が貯まらず、30 秒の線（助け）にも
    60 秒（動けなくなった）にも届かなかった
  まとめ：揺れの元は「すれ違いをあきらめたあとの下がる動き」と「前が空いたので進む動き」のぶつかり合い。
  依頼85 で見た ②2台 種2 も同じ形（行ったり来たりの幅 1.4 cm）とみられる（1コマの記録では確かめていない）

--------------------------------------------------------------------
2. 直したこと（cs:76）
--------------------------------------------------------------------
 a. 進めているかの見張り（Robot/ServingRobotController.cs・Robot/RobotSpec.cs）
   ・値は RobotSpec に名前を付けて置いた：progressWatchSec = 10 秒・progressWatchM = 0.5 m（Nav2 SimpleProgressChecker の既定値。
     Unity だけの値で、params には入れていない）
   ・見張るのは、卓へ／受け渡し口へ／待機場所へ走ろうとしているあいだ（往復の ToTable・ToPass）だけ。見張りを始めた所から
     0.5 m 離れたら、その所から始め直す（Nav2 と同じ）
   ・見張らないとき：入口の順番待ち・1本道の順番待ち（待つ点へ向かう途中も）・細い通路の入口の譲り合い・
     よける場所でよけている・譲って下がっている。受け渡し口で料理を待つ・受け渡し口の列・卓で客が取るのを待つ・
     待機場所は、往復の外（Idle／Done）か卓での受け渡し（Dwell）なので、はじめから見ない
   ・「進めていない」になったら、そのコマで速さ 0 にしてその場でぴたりと止まる。止まっているあいだは、すれ違いの走り方
     （下がる動きを含む）をしない。そのあとは今までの決まりどおり：
       - 前が空けば進む … 前のセンサーに何もなく、道が引けていて、道の先 0.5 m を進むとほかの台に前のセンサーの長さ
         （0.6 m）より近づいてしまうことがない、が resumeAfterClearSec（1 秒）続いたら進み出す
         （近づく向きへ進み出さないのは、上の揺れの元を断つため）
       - 3 秒空かなければ回り込む道を探す（前がふさがっているときと同じ UpdateDetour を使う）
       - 30 秒で助けを呼ぶ・60 秒で動けなくなった（止まりの数え方は cs:73 のまま。速さ 0 なのでそのまま止まりに数える）
   ・止まりの記録（stops.csv）の cause_detail の頭に「進めていない（10秒で0.5m）：」を付ける。原因は、近づいてしまう台がいれば
     「もう1台のロボット」、前のセンサーに映っていればそれ、無ければまわりで探したもの
 b. 依頼85 の 0.3 m の測り方をやめた
   ・止まりの数え方・立ち往生の数え方・助けの取り消しを cs:73 の形に戻した（ServingRobotController.cs・ServiceOps.cs の
     依頼85 の部分を cs:73 の中身に戻してから a・c を足した）
   ・依頼85 の c（summary.json の open_after_all_left・all_left_s）は測り方に関わらないので残した（分け方だけ d で直した）
 c. 助けで動かす先が見つからないとき（ServingRobotController.cs・ServiceOps.cs）
   ・往復の途中の台で、動かす先が 3 回続けて見つからなければ（3 回目で）、助けのスタッフが付き添い、来た道を
     受け渡し口か待機場所の近い方まで、歩く速さ（1.0 m/秒。スタッフの歩く速さと同じ）で押して連れて戻す。瞬間移動はしない
   ・来た道：その往復で通った所を 0.25 m ごとに覚えておき、逆にたどる。先に受け渡し口か待機場所に着いた方で止める
   ・着いたらその往復を終える（まだ届けていない料理は受け渡し口の先頭へ戻る。理由は「連れて戻した」）。そこから次の仕事を受けてよい
   ・rescues.csv の outcome に「連れて戻した」、summary.json の stuck_rescue に escorts・escort_m
   ・動かす先が見つかったら数え直す。往復の始めでも数え直す。止まっている台（往復の外）は今までどおり
 d. 詰まりの分け方（Experiment/ExperimentRunner.cs）
   ・全員が帰った回で、最後の組が帰った時刻より「あとに始まった」ロボットの詰まり・助けだけを記録だけにする（open_after_all_left）。
     客がいるあいだに始まって回の終わりまで残ったものは、解けずに残った詰まりに数える
 e. 記録だけ（動きは変えない）
   ・summary.json に progress_watch（halts：見張りで止まった回数・released：前が空いて自分で進み出した回数・halts_list：
     [時刻, 号機, x, z, 原因, 区間]）と jitter（揺れ続け。1コマごとの位置で、半径 5 cm の中を動き続け、動いた道のりが 0.1 m 以上、
     それが 60 秒以上続いた回数・最長秒・並び。2 秒より長くじっとしたら数え直す）を足した
   ・揺れ続けの数え方は、試しの1回目では「着く前に少し動いてから長く止まっていた所」まで数えてしまっていたので、
     「2 秒より長くじっとしたら数え直す」を足してから check-in した（待機場所の台を1コマごとに見て、動いていないことを確かめた）
 変えていないもの：ロボットの速さ・物理の設定・譲る順番・人とロボットの数字・rescue_s 15 秒・30 秒・60 秒という時間・
                    センサーの 0.6 m・同じ種で同じ結果にする作り・動かす先が見つかるときの決め方・瞬間移動をなくした作り・
                    依頼84 で入れた直し・店の形・台帳の列と今までの行・試算の値

--------------------------------------------------------------------
3. 変えたファイル・版
--------------------------------------------------------------------
  cs:76　Robot/ServingRobotController.cs・Robot/RobotSpec.cs・Service/ServiceOps.cs・Experiment/ExperimentRunner.cs・Experiment/TripLogger.cs
  実行ファイル：Builds/headless　build_id cs76_20261103_2122・unity_cs ServiceSim/cs:76・pending_changes 空・error CS 0
  （check-in の前に /tmp/req86/try1・try2・try4 に試しのビルドを作り、書き先を /tmp に向けて ⑦2台 種9・④2台 種6・
    ④2台 種0・③2台 種2 を回して確かめた。台帳には書いていない）

--------------------------------------------------------------------
4. 確かめ
--------------------------------------------------------------------
 (1) 同じ種で同じ結果か（cs:76・det86a と det86b）
   ⑦ fam_p5・種9・2台、④ fam_p2・種6・2台 とも：contacts・dishes・give_ups・groups・nowarp_jams・passes・people_jams・
   requeues・rescues・robot_track・stops・timeline・yields は 1 行も違わない。trips.csv は最後の列 plan_ms_max だけ、
   summary.json・conditions.json は written_at だけ、run_info.json は run_label・written_at・wall_seconds・speedup・
   plan_ms だけ違う（前と同じ扱い）
   4 回とも全員が帰った・瞬間移動 0・1コマの跳び 0・揺れ続け 0・解けずに残った詰まり 0
     ⑦2台 種9：入店待ち 6.56 分（依頼84 7.55）・料理の待ち 1.64 分・助け 24 回・見張りで止まった 49 回（うち進み出した 25）
     ④2台 種6：入店待ち 20.87 分（依頼84 19.44・依頼85 32.50）・料理の待ち 1.43 分・助け 57 回・見張り 102 回（進み出した 47）・
               詰まり残り 0（依頼85 で 4473 秒残っていた所は、今回は起きなかった。連れて戻したは 0 回）

 (2) 180回（label base73・同時4本・6店 × 0・1・2台 × 種0〜9、並びは依頼84 と同じ）→ 44 回で止めた
   44 回目のあと（21:41）、見張りが止める線に当たった：
     ⑦2台（fam_p5）の入店待ちの中央値が、同じ種（0・1・2）で 依頼84 1.53 分 → 今回 3.99 分（2.61 倍）
       種0  1.38 → 1.57 分（依頼85 1.61）
       種1  1.53 → 3.99 分（依頼85 2.09）　← これで中央値が2倍を超えた
       種2 10.83 → 11.86 分（依頼85 10.28）
   依頼どおりここで止めた（夜の実行係に止める合図を送り、走っていた 3 回は中断。その 3 回は台帳に入っていない）。
   台帳の completed は 44 回。瞬間移動の線には当たっていない
   ⑦2台 種1 の中身（今回）：詰まり 17 回・1317 秒（依頼84 16 回・344 秒）。いちばん長いのは入口の近く (1,2) の
   「スタッフ・案内」341 秒、次が (2,9) の「客・会計」209 秒・(2,7) の「スタッフ・呼び出し」184 秒。
   依頼84 は客のドリンクバーの詰まりだけだった。見張りで止まった 43 回のうち多いのは (9,4) の「人が立ち止まっていた」7 回など。
   助けは 22 回（依頼84 10 回）。入店待ちが延びたのは入口・案内の通り道での詰まりが増えたためとみられるが、
   見張りで止まった台との関わりはまだ確かめていない

   依頼84・85 と並べる（同じ 44 回＝同じ店・台数・種だけで比べた。記録：night/20261103_base73_cs76/）
     項目                                          依頼84（cs:73）     依頼85（cs:75）     今回（cs:76）
     瞬間移動                                           0                   0                  0
     1コマの跳び                                        0                   0                  0
     揺れ続け（1 cm 幅の行ったり来たりが 60 秒以上）    記録なし（※）      記録なし（※）      0 回
     見張りで止まった（うち自分で進み出した）           ―                   ―                  999 回（529）
     解けずに残った詰まり（件）                         1                   0                  0
     全員が帰ったあとに始まった詰まり（件）             0                   0                  0
     全員が帰ったあとに呼び、終わる前に回が終わった助け 1                   1                  1（⑤2台 種0）
     全員が帰らなかった回                               0                   0                  0
     助け（回／往復／1往復あたり）                  499／2748／0.182    591／2752／0.215   609／2696／0.226
       うち取り消し                                     62                  105                81
       その場で引き直した                               19                  27                 20
     連れて戻した                                       ―                   ―                  0
     立ち往生（動けなくなった）                         208                 218                295
       うち行ったり来たりで数えたもの                   0                   157                0
     立ち往生が1回でもあった往復（割合）            130（0.047）        143（0.052）       192（0.071）　試算の stuck_rate 0.01
     30 秒以上の止まり                                  456                 480                582
     詰まり（回・秒・1回の最長）                 518・31,489・1,218  454・22,771・885   539・30,828・1,085
     （※）依頼84・85 には1コマごとの揺れの記録が無い。参考に、依頼84 の 180 回では ⑦2台 種9 が回の終わりまで 31,402 秒
         行ったり来たりしていた。依頼85 の 180 回では「行ったり来たりで数えた立ち往生」が 822 回あった
     180 回全体（依頼84・85）の値は依頼85 の報告（20261103_base72.txt）のとおり。依頼84 の解けずに残った詰まりは、
     今回の分け方では 2 件（⑦2台 種9・⑤2台 種0 の客がいるあいだに始まったもの）、依頼85 は 1 件（④2台 種6）になる

   見張りで止まった場所の上位（今回 44 回。店・台数・1 m のマス・回数）
     ⑤2台(16,9) 47・④2台(13,4) 30・③2台(6,4) 25・③2台(3,4) 21・④2台(2,3) 19・⑤2台(15,9) 18・⑥2台(17,5) 18・③2台(7,4) 15・⑦2台(6,4) 15
     原因：人が立ち止まっていた 481・もう1台のロボット 346・お客さんとすれ違った 63・スタッフとすれ違った 56・分からない 49・椅子など 4
     区間：卓へ 629・待機場所へ 370
     （⑤2台(16,9)・(15,9) は待機場所 (14.8, 8.8) のすぐ手前。依頼85 で「待機場所が台1台分しかない」と書いた所と同じ）

   店・台数ごと（同じ種どうし。入店待ち・料理の待ちは分の中央値、比は今回／依頼84。助けは1往復あたり、立ち往生はその種の和）
     店・台数   種      入店 84→今回（比）       料理 84→今回（比）     助け 84→今回      立ち往生 84→今回   見張り
     ③1台      0-2     1.77→1.85（1.04）       2.32→2.38（1.02）     0.142→0.202        9→11              66
     ③2台      0-2     1.63→1.74（1.07）       1.49→1.71（1.15）     0.179→0.244       22→33             158
     ⑦1台      0-2     1.49→1.65（1.10）       2.24→2.48（1.10）     0.110→0.153        6→14              48
     ⑦2台      0-2     1.53→3.99（2.61）★     1.46→1.59（1.09）     0.122→0.234       15→39             137
     ④1台      0-2    13.83→11.88（0.86）      2.08→1.77（0.85）     0.217→0.246       32→37              87
     ④2台      0-1    19.94→13.52（0.68）      2.08→2.14（1.03）     0.640→0.680       90→92             167
     ⑤1台      0-1     4.16→4.67（1.12）       2.66→2.83（1.06）     0.185→0.268        4→15              37
     ⑤2台      0-1     6.06→3.70（0.61）       2.04→1.63（0.80）     0.222→0.219        5→15             132
     ⑥1台      0-1     3.21→3.14（0.98）       2.02→1.95（0.96）     0.084→0.054        3→1               16
     ⑥2台      0-1     2.84→3.35（1.18）       0.96→0.98（1.03）     0.042→0.079        3→9               71
     ②1台      0-1     5.04→5.11（1.01）       1.41→1.44（1.02）     0.183→0.192       14→15              26
     ②2台      0-1     4.38→4.27（0.98）       0.58→0.75（1.29）     0.119→0.146        5→14              54
     （0台はどの店も依頼84 と同じ値（比 1.00）。2倍を超えたのは ⑦2台の入店待ちだけ）

   向きの12本（今回そろった種だけの中央値。0台・1台・2台で種の数が 2〜3 しかないので参考）
     店  入店待ち Unity 0→1→2台      向き  試算 0→1→2台       向き  合う？
     ③   3.69 → 1.85 → 1.74     －－   4.09 → 1.68 → 1.13   －－   合う
     ⑦   4.37 → 1.65 → 3.99     －＋   3.08 → 1.58 → 1.60   －＋   合う（2台が止める線の所）
     ④  14.00 → 11.88 → 13.52   －＋  10.91 → 4.81 → 5.57   －＋   合う
     ⑤   4.80 → 4.67 → 3.70     －－   7.51 → 3.16 → 2.37   －－   合う
     ⑥   5.53 → 3.14 → 3.35     －＋   7.91 → 3.68 → 2.11   －－   逆（1→2台）
     ②   4.87 → 5.11 → 4.27     ＋－   2.61 → 1.79 → 1.30   －－   逆（0→1台）
     店  料理の待ち Unity 0→1→2台    向き  試算 0→1→2台       向き  合う？
     ③   0.95 → 2.38 → 1.71     ＋－   0.63 → 1.97 → 0.96   ＋－   合う
     ⑦   1.01 → 2.48 → 1.59     ＋－   0.63 → 2.01 → 1.01   ＋－   合う
     ④   1.32 → 1.77 → 2.14     ＋＋   0.99 → 1.29 → 0.47   ＋－   逆（1→2台。依頼85 と同じ逆）
     ⑤   1.08 → 2.83 → 1.63     ＋－   0.77 → 2.28 → 1.27   ＋－   合う
     ⑥   1.06 → 1.95 → 0.98     ＋－   0.84 → 2.01 → 0.82   ＋－   合う
     ②   0.82 → 1.44 → 0.75     ＋－   0.61 → 0.91 → 0.40   ＋－   合う
     12 本中 9 本が合う（依頼84・85 は 10 種そろって 10 本）。種がそろっていないので、ここで合う・合わないは決められない

   詰まりの場所の上位（今回 44 回）：④(2,4) 5 回 1,733 秒・⑦(5,5) 14 回 1,503 秒・④(7,3) 16 回 1,271 秒・③(6,4) 10 回 1,005 秒・
     ②(14,2) 2 回 985 秒・③(4,5) 33 回 837 秒
     だれ・仕事：客ドリンクバー 409 回 15,384 秒・スタッフ片付け 16 回 5,940 秒・ロボット1往復の打ち切り 7 回 2,837 秒・
                 客退店 45 回 1,826 秒・スタッフ案内 10 回 1,805 秒・スタッフ呼び出し 7 回 1,040 秒

 (3) 残った詰まりの中身と場所（今回 44 回）
   ・解けずに残った詰まり：0 件。全員が帰らなかった回：0。揺れ続け：0 回。連れて戻した：0 回（この 44 回では動かす先が
     3 回続けて見つからない所が無かった。付き添いの作りが実際に働いた回はまだ無い）
   ・全員が帰ったあとに呼び、終わる前に回が終わった助け：⑤2台 種0 の 1 件（11166 秒に呼んだ・(14.46, 8.54)・相手はスタッフ。
     最後の組が帰ったのは 10599 秒。依頼84・85 の同じ回と同じ所＝待機場所の手前）

--------------------------------------------------------------------
5. 台帳
--------------------------------------------------------------------
  2491 行 → 2539 行（追記 48 行だけ。どれも 59 列。先頭 2491 行の md5 は d0517dcc… で始める前と同じ）
  終わったあとの md5 05f61ef7bd6d032ee909834a0df16213。鍵ファイルは残っていない
  追記：det86a 2・det86b 2・base73 44（どれも completed）
  集計の手順と出力：/tmp/req86/（agg86.py・agg86.txt＝44 回、agg86_same44.txt＝依頼84・85 を同じ 44 回に絞ったもの、
  watch86.py・watch_log.txt・run180.sh、揺れを調べた1コマの記録 trace_p5s9.csv）

--------------------------------------------------------------------
決めてほしいこと
--------------------------------------------------------------------
  1. 止める線（⑦2台 の入店待ちの中央値が依頼84 の 2.61 倍）に 44 回目で当たったので止めた。種 0〜2 の 3 つでの中央値で、
     種1 だけが 1.53 → 3.99 分に延びた（種0・種2 は 1.1 倍ほど）。このまま見張りの作りを見直すか、それとも残りの 136 回を
     回して 10 種で見てから決めるか
  2. 立ち往生が増えた（同じ 44 回で 依頼84 208 → 今回 295 回、立ち往生が1回でもあった往復の割合 0.047 → 0.071。試算の
     stuck_rate は 0.01）。見張りで止まった台は、前が空くまで速さ 0 のまま待つので、60 秒に届きやすくなったとみられる。
     この数え方のまま試算と比べてよいか
  3. 見張りで止まったあと「前が空いた」とみる決まりに、「道の先 0.5 m を進むとほかの台に 0.6 m より近づくなら進み出さない」
     を入れた（揺れの元を断つため。依頼に書かれていない所なので、私が決めた）。このままでよいか
  4. よける場所でよけているあいだ・譲って下がっているあいだも見張らないことにした（依頼の「わざと待っている間」の並びには
     入っていないが、見張りで止めるとよけ終わりの決まりが働かなくなるため）。このままでよいか
  5. 連れて戻した台は、そこでその往復を終え、まだ届けていない料理を受け渡し口の先頭へ戻すことにした（依頼に書かれていない所）。
     このままでよいか。なお 44 回では連れて戻す所が出ておらず、まだ働きを確かめられていない

判定：止めた（決めてほしいことあり）
````

#### 依頼86b の依頼文（全文）

````markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 240
---
# 依頼86b：見張り入りの版（cs:76）で180回の残り136回を回し、この版で固める

エイイチと決めた区切り（2026-11-03 20:55「どこかで区切って進めて」）：依頼86 の版で Unity の作りを固める。固める条件は (1) 瞬間移動0 (2) 同じ種で同じ結果 の2つだけ。残った詰まりや試算とのずれは記録して、サイトの動画を出したあとで直す。
依頼86 の報告：claude_code_reports/20261103_base73.txt（44回で止める線に当たって止めた。44回とも瞬間移動0・揺れ続け0・解けずに残った詰まり0、同じ種の2組は一致）。

依頼86 の「決めてほしいこと」への答え（区切りに従って決めた）：
- 1：作りは直さず、残りの136回を回して種10個で見る（3つの種の中央値で止めたので。種1 だけが延びている）
- 2：数え方はこのまま。試算の stuck_rate（0.01）との差は記録だけ
- 3・4・5：このままでよい（あなたが決めた形で固める）

## 始める前に確かめること（違えば手を止めて報告）
Unity エディタ・night_runner／rec_runner が動いていない、KIOXIA がマウント済み、unity_ledger_v1.lock がない、保留 0、作業場所が cs:76、Builds/headless が cs:76。台帳は退避してから回す。台帳は追記だけ。

## やること
1. コードは変えない（cs:76 のまま。実行ファイルも作り直さない）
2. night/20261103_base73_cs76 の並び（/tmp/req86/base73.json。無ければ依頼84 と同じ 6店 × 0・1・2台 × 種0〜9 で作り直す）のうち、completed になっていない136回を、同じ label の続きとして回す（同時4本）
3. 180回そろったら、依頼84・85 と並べる表（依頼86 の報告と同じ項目）と、向きの12本の表を作る。⑦2台 種1 の入店待ちが延びた理由を短く調べる（直さない）
4. cs:76 をサイトの動画の撮り直しに使う版として固めたことを、作業場所の README（無ければ報告）に一行残す

## 止める線
瞬間移動が1回でも出たときだけ止める。入店待ち・料理の待ちの中央値の線では止めない（記録だけ）。

## 報告
claude_code_reports/20261103_base73b.txt に：回した回数、180回の表、向きの12本、⑦2台 種1 の理由、残った詰まりがあればその中身と場所、台帳の行数と md5。
**報告の最後の1行は必ず次のどれか**：「判定：合格」／「判定：止めた（決めてほしいことあり）」／「判定：失敗」
````

#### 依頼86b の Claude Code の報告（20261103_base73b.txt・全文）

````text
====================================================================
依頼86b：見張り入りの版（cs:76）で180回の残り136回を回し、この版で固める
2026-11-03 22:20〜23:30　作業場所 cs:76　build_id cs76_20261103_2122（作り直していない）
====================================================================

--------------------------------------------------------------------
0. 始める前の確かめ（どれも依頼どおり）
--------------------------------------------------------------------
  Unity エディタ・night_runner・rec_runner：動いていない（Unity Hub だけ）／KIOXIA：マウント済み／
  unity_ledger_v1.lock：無し／保留 0（cm status：cs:76 - head）／Builds/headless の build_info.json：unity_cs ServiceSim/cs:76・
  pending_changes 空
  台帳を archive/unity_ledger_v1_pre_base73b_20261103/ に退避（2539 行・md5 05f61ef7bd6d032ee909834a0df16213。依頼86 の終わりと同じ）

--------------------------------------------------------------------
1. 回したこと
--------------------------------------------------------------------
  コード・実行ファイルは変えていない。/tmp/req86/base73.json（180 回の並び）を、同じ label base73・記録名 20261103_base73_cs76 の
  続きとして同時4本で回した。夜の実行係は「completed 44 回を飛ばす・回す 136 回」と数えて始めた（から回しでも 136 回）
  依頼86 で中断した 3 回（④2台 種2・⑤0台 種2・⑤1台 種2）は今回はじめから回し直した（中断した出力は _stopped のまま残っている）
  止める線は瞬間移動だけにした（60 秒ごとに summary.json の teleports と 1コマの跳びを見る。/tmp/req86b/watch86b.py）
  結果：136 回とも completed（やり直し 0・failed 0）。実時間 平均 1.3 分・最長 4.7 分。22:25〜23:10。止める線には当たっていない
  これで base73 は 180 回そろった（台帳の completed 180 行）

--------------------------------------------------------------------
2. 180 回の表（依頼84・85 と並べる。どれも 180 回）
--------------------------------------------------------------------
     項目                                          依頼84（cs:73）     依頼85（cs:75）     今回（cs:76）
     瞬間移動                                           0                   0                  0
     1コマの跳び                                        0                   0                  0
     揺れ続け（1 cm 幅の行ったり来たりが 60 秒以上）    記録なし            記録なし           0 回
     見張りで止まった（うち自分で進み出した）           ―                   ―                  4,237 回（2,353）
     解けずに残った詰まり（件）                         2                   1                  1（⑤2台 種7。中身は 5）
     全員が帰ったあとに始まった詰まり（件）             0                   0                  0
     全員が帰ったあとに呼び、終わる前に回が終わった助け 3                   2                  3
     全員が帰らなかった回                               1（⑦2台 種9）       0                  0
     助け（回／往復／1往復あたり）                 2244／11650／0.193  2654／11722／0.226  2611／11570／0.226
       うち取り消し                                     291                 389                350
       その場で引き直した                               72                  226                88
     連れて戻した                                       ―                   ―                  1（④2台 種9）
     立ち往生（動けなくなった）                         903                 1076               1165
       うち行ったり来たりで数えたもの                   0                   822                0
     立ち往生が1回でもあった往復（割合）            577（0.050）        676（0.058）       715（0.062）　試算の stuck_rate 0.01（記録だけ）
     30 秒以上の止まり                                  1966                2183               2375
     詰まり（回・秒・1回の最長）               2170・177,753・31,402 2101・131,197・4,473 2224・133,165・7,095

   見張りで止まった場所の上位（店・台数・1 m のマス・回数）
     ④2台(13,4) 140・⑦2台(18,6) 106・⑤2台(15,9) 98・⑥2台(17,6) 97・②2台(14,5) 89・③2台(18,6) 79・④2台(2,3) 77・⑤2台(16,9) 75
     原因：人が立ち止まっていた 1782・もう1台のロボット 1713・お客さんとすれ違った 308・スタッフとすれ違った 214・分からない 187・椅子など 33
     区間：卓へ 2718・待機場所へ 1519

   店・台数ごと（種 10 個の中央値。入店待ち・料理の待ちは分。比は今回／依頼84。立ち往生・詰まり秒は 10 種の和）
     店・台数   入店 84→85→今回（比）      料理 84→85→今回（比）     助け/往復 84→85→今回    立ち往生 84→85→今回  見張り
     ③1台      3.19→2.72→3.47（1.09）    2.40→2.40→2.45（1.02）    0.155→0.177→0.206       37→32→48            221
     ③2台      2.50→2.55→2.72（1.09）    1.48→1.44→1.71（1.16）    0.167→0.216→0.234       67→85→102           590
     ⑦1台      3.04→3.56→3.87（1.27）    2.40→2.49→2.51（1.04）    0.160→0.170→0.185       36→36→49            195
     ⑦2台      2.82→2.83→3.87（1.37）    1.48→1.51→1.52（1.03）    0.145→0.179→0.189       62→70→103           542
     ④1台     10.76→11.99→11.02（1.02）  1.89→1.92→1.79（0.95）    0.253→0.271→0.262       97→111→110          287
     ④2台     17.96→18.81→18.66（1.04）  1.73→2.04→1.98（1.15）    0.570→0.745→0.684      388→476→470          926
     ⑤1台      6.17→6.78→6.99（1.13）    2.68→2.67→2.63（0.98）    0.219→0.178→0.168       24→24→34            128
     ⑤2台      7.62→5.28→6.12（0.80）    1.68→1.66→1.71（1.02）    0.238→0.289→0.267       55→96→74            494
     ⑥1台      5.38→5.81→5.19（0.97）    1.98→1.96→2.03（1.02）    0.049→0.050→0.056       14→13→17             78
     ⑥2台      4.83→4.86→4.54（0.94）    1.11→0.97→1.05（0.94）    0.084→0.105→0.101       44→56→55            401
     ②1台      1.60→1.60→1.60（1.00）    1.02→1.01→1.02（1.00）    0.090→0.065→0.096       39→24→39             78
     ②2台      1.59→1.59→1.65（1.04）    0.58→0.54→0.61（1.05）    0.148→0.181→0.181       40→53→64            297
     （0台はどの店も依頼84 と同じ値。②0台 種のうち1つの詰まり秒だけ 55→30 だが入店・料理の中央値は同じ）
     10 種で見ると、⑦2台の入店待ちは依頼84 の 1.37 倍（44 回のときは 3 種で 2.61 倍）。2 倍を超えた店・台数は無い（記録だけ）

   詰まりの場所の上位（今回）：⑤(6,13) 28 回 8,827 秒・④(5,3) 17 回 6,175 秒・④(5,2) 19 回 4,029 秒・④(4,2) 14 回 3,932 秒・
     ⑤(14,9) 18 回 3,520 秒・④(2,4) 15 回 3,267 秒
     だれ・仕事：客ドリンクバー 1641 回 54,479 秒・スタッフ片付け 87 回 32,719 秒・ロボット1往復の打ち切り 36 回 15,586 秒・
                 スタッフ案内 29 回 7,595 秒・客退店 210 回 6,815 秒・スタッフ料理 41 回 6,542 秒

--------------------------------------------------------------------
3. 向きの 12 本（10 種の中央値。0→1→2台。＋は増える）
--------------------------------------------------------------------
     店  入店待ち Unity 0→1→2台        向き  試算 0→1→2台        向き  合う？
     ③   3.90 → 3.47 → 2.72          －－   4.09 → 1.68 → 1.13   －－   合う
     ⑦   4.40 → 3.87 → 3.87          －－   3.08 → 1.58 → 1.60   －＋   逆（1→2台。Unity は 3.871→3.869 でほぼ同じ、試算も 1.58→1.60）
     ④  12.64 → 11.02 → 18.66        －＋  10.91 → 4.81 → 5.57   －＋   合う
     ⑤   8.13 → 6.99 → 6.12          －－   7.51 → 3.16 → 2.37   －－   合う
     ⑥   9.45 → 5.19 → 4.54          －－   7.91 → 3.68 → 2.11   －－   合う
     ②   1.87 → 1.60 → 1.65          －＋   2.61 → 1.79 → 1.30   －－   逆（1→2台）
     店  料理の待ち Unity 0→1→2台      向き  試算 0→1→2台        向き  合う？
     ③   0.95 → 2.45 → 1.71          ＋－   0.63 → 1.97 → 0.96   ＋－   合う
     ⑦   1.01 → 2.51 → 1.52          ＋－   0.63 → 2.01 → 1.01   ＋－   合う
     ④   1.25 → 1.79 → 1.98          ＋＋   0.99 → 1.29 → 0.47   ＋－   逆（1→2台。依頼84・85 と同じ逆）
     ⑤   1.09 → 2.63 → 1.71          ＋－   0.77 → 2.28 → 1.27   ＋－   合う
     ⑥   1.09 → 2.03 → 1.05          ＋－   0.84 → 2.01 → 0.82   ＋－   合う
     ②   0.88 → 1.02 → 0.61          ＋－   0.61 → 0.91 → 0.40   ＋－   合う
     12 本中 9 本が合う（依頼84・85 は 10 本）。区切りに従い、ずれは記録だけ（直していない）
     ⑦ の入店待ち 1→2台 は、Unity も試算もほぼ横ばい（差 0.002 分・0.02 分）で、向きが分かれたのは差が小さいため
     ② の入店待ち 1→2台 は 1.60→1.65 分（依頼84・85 は 1.60→1.59 で横ばい）

--------------------------------------------------------------------
4. ⑦2台 種1 の入店待ちが延びた理由（調べただけ。直していない）
--------------------------------------------------------------------
  入店待ちの平均：依頼84 1.53 分・依頼85 2.09 分・今回 3.99 分。1 時間目は 3 つともほぼ同じ（1.38・1.31・1.30 分）で、
  2 時間目（3600〜7200 秒に来た 40 組）だけが 1.69 → 2.93 → 6.88 分（最長 12.73 分）に延びた
  元は、入口から席へ向かう細い通路（x≈1.6〜1.9 m、z≈4.5〜12 m）で、ロボットが見張りで止まったこと：
  ・4656〜5097 秒に 2号機（往復 68）と 1号機（往復 70）が、この通路で「進めていない（10秒で0.5m）」になって
    7 回続けて止まった（1 回 49〜58 秒。相手はスタッフ 02・03・04 や立ち止まった人）。多くは 30 秒の助けでスタッフが動かして解けた
  ・速さ 0 で通路をふさいだあいだ、案内中のスタッフが通れず、スタッフ案内の詰まりが (0.94,1.83) で 341 秒・(1.9,11.0) で 142 秒
    起きた。案内が止まるので、そのあいだに来た組が入口で待つことになった（入店待ちの長い 5 組は 4503〜6138 秒に来た組）
  ・6010 秒・8149〜8363 秒にも同じ通路で見張りの止まりがあった（30 秒以上の止まり、この通路で計 12 回・674 秒。どれも見張りから）
  ・依頼84（cs:73）の同じ回では、この通路で 30 秒以上止まったことは 0 回、スタッフの詰まりも 0 回だった
  まとめ：見張りで止まった台が、案内のスタッフが使う入口側の細い通路を 1 分ほどずつ何度もふさいだため。
  見張りが無い版では、同じ所をすれ違いの動き（下がる・抜ける）で抜けていた。10 種の中央値では 1.37 倍にとどまり、
  延び方が大きいのは種1 だけ

--------------------------------------------------------------------
5. 残った詰まりの中身と場所
--------------------------------------------------------------------
  ・解けずに残った詰まり 1 件：⑤2台 種7。スタッフ 6 の「片付け」が (5.68, 13.13)（詰まりの上位 ⑤(6,13) と同じマス。
    ドリンクバーのそば）で 5261 秒に始まり、回の終わり（7,095 秒）まで残った。客がいるあいだに始まったので解けずに数えた。
    全員は 11,858 秒に帰っている。そのときロボットは近くにいない（1号機 x≈18〜24・2号機 (2.2, 3.3) で卓に止まっていた）。
    依頼84 の同じ回では、このマスで客ドリンクバーの短い詰まり（20・36 秒）だけだった。中身はこれ以上調べていない
  ・全員が帰ったあとに呼び、終わる前に回が終わった助け 3 件：どれも ⑤2台、待機場所 (14.8, 8.8) の手前、相手はスタッフ
    種0 11166 秒 (14.46, 8.54)・種3 11445 秒 (14.81, 8.54)・種5 11322 秒 (15.71, 8.54)（記録だけ。依頼86 で書いた所と同じ）
  ・連れて戻した 1 回：④2台 種9。11764 秒に (9.69, 10.24) で、もう1台のロボットにふさがれて動かす先が 3 回見つからず、
    34.5 m を 34.3 秒で連れて戻した（付き添いの作りが実際に働いた初めての回）
  ・揺れ続け 0 回・全員が帰らなかった回 0

  気づいたこと（夜の判定の振り分け、night/20261103_base73_cs76/judge.md）：
  ・上の ④2台 種9 が「回の失敗：ロボットが1コマで 0.05 m 超え 246 コマ」になった。連れて戻す速さ 1.0 m/秒 × 1コマ 0.05 秒 が
    ちょうど 0.05 m で、小数の誤差でわずかに超えたコマを数えたもの（run_info.json の robot_step_m の最大 0.05）。
    瞬間移動（teleports）・1コマの跳び（robot_frame_jumps。出せる速さ 0.6 m/秒 から決まる線）はどちらも 0。
    180 回のうち 0.05 m 超えが出たのはこの 1 回だけ。止める線（瞬間移動）には当たらないと見て、止めずに進めた
  ・ほかの「回の失敗」3 件は、依頼86 で中断した _stopped の出力（台帳に行がない）で、今回回し直して completed になっている

--------------------------------------------------------------------
6. cs:76 を固めた記録
--------------------------------------------------------------------
  作業場所（ServiceSim）に README が無いので、新しくは作らず、ここに残す：
  「cs:76（build_id cs76_20261103_2122）を、サイトの動画の撮り直しに使う版として固めた（2026-11-03・依頼86b。
    固める条件：瞬間移動 0（180 回）・同じ種で同じ結果（依頼86 の det86a／det86b で確かめ済み））」

--------------------------------------------------------------------
7. 変えたファイル
--------------------------------------------------------------------
  コード・実行ファイル：変えていない（cs:76 のまま。check-in なし）
  台帳：追記だけ（下）。記録：night/20261103_base73_cs76/（夜の実行係の記録と judge.md を書き直し）
  手元の手順と出力：/tmp/req86b/（run136.sh・watch86b.py・watch_log.txt・runner_base73b.txt・agg86b.txt・p5s1.py・p5s1b.py・p5med.py）
  集計は依頼86 の /tmp/req86/agg86.py をそのまま使った

--------------------------------------------------------------------
8. 台帳
--------------------------------------------------------------------
  2539 行 → 2675 行（追記 136 行だけ。どれも 59 列・どれも completed。先頭 2539 行の md5 は 05f61ef7… で始める前と同じ）
  終わったあとの md5 928e7e5825fee8571769722d6048faf3。鍵ファイルは残っていない

--------------------------------------------------------------------
決めてほしいこと
--------------------------------------------------------------------
  1. 夜の判定の手順が、連れて戻した回（④2台 種9）を「1コマで 0.05 m 超え」で回の失敗に分けた（連れて戻す速さ 1.0 m/秒 が
     ちょうど 1コマ 0.05 m のため。瞬間移動・1コマの跳びは 0）。固める条件の「瞬間移動 0」はこのままで満たしているとみて
     よいか。直すなら（連れて戻す速さを下げる・判定の線を変える）、区切りに従いサイトの動画を出したあとに回す
  2. 立ち往生が1回でもあった往復の割合 0.062（試算 0.01）・向き 12 本中 9 本・⑦2台 種1 の入店待ち（見張りで止まった台が
     入口側の通路をふさぐ）は、区切りどおり記録だけにした。あとで直す順番を決めてほしい

判定：合格
````


## 作業ログ ― 依頼87〜89：サイトの6店の動画を、パネル付きの形にそろえた

> そういえば動画のフォーマットに合わせてサイトの動画をつくってますか？

パネル付きの形と、それを作るスクリプトは前の回で決めていました。録画の横に、スタッフが何をしているか（案内・料理・会計・片付け・ロボットの助け・手すき）、ロボットが運んでいるか待機か、入口で待つ組の数を並べる形です。止めていたのは録画の方で、固めた版で撮り直してから差し替える順番にしていました。

依頼87 で、cs:76 で6店（②〜⑦）を撮り直しました。カメラは60°見下ろし・左右30°の2台、4K で、開店から全員が帰るまでです。店ごとに、通しの動画（約75秒）と、ロボットが長く止まった場所に寄る動画を作っています。

![③の店の通しの動画の1コマ。左が Unity の録画、右がスタッフ4人がしていることとロボット2台の様子のパネル](https://pixelstomotors.com/media/LOG440_02_panel_whole_p1.png)

撮ってみると、寄りの動画で字幕が切れていました。寄りの部品は1280×720 で、それを高さ1080に広げてから真ん中の1360px を切り出していたので、左上の字幕の左がおよそ280px 切れ、その上に色の説明が重なっていました。パネルの時刻も「開店から 1:39」と書いていて、決めた形（1時間39分）と違っていました。

![直す前の寄りの部品。左上の字幕の左が切れて、色の説明と重なっている。時刻も 0:44 の書き方](https://pixelstomotors.com/media/LOG440_03_focus_cut_before.png)

依頼88 で、寄りの部品は切らずに横幅に合わせて縮め、上下に Unity の背景に近い色の余白を足す形（--fit）にしました。依頼89 で、寄りの字幕の中の時刻も「134:14〜140:10」から「開店から 2時間14分〜2時間20分」に直しました。

> スマホはそのままで。

スマホの幅ではパネルの字が小さすぎて読めませんが、縦長の別の形は作らないことにしました。

![直した後の寄りの部品。録画は縮めて上下に余白を入れ、字幕は左端まで読める。時刻は開店から 2時間15分 の書き方](https://pixelstomotors.com/media/LOG440_04_focus_fit_after.png)

- ねらい：初めて /series8 の動画を見る人が、ロボットとスタッフがいま何をしているかを読めるようにする
- 変わったこと：6店の動画を v1（パネルなし）から v3（パネル付き・字幕が切れない・時刻の書き方をそろえた）に差し替えた。動画は1本1〜2MB
- 見込める効果（見込み）：動画を最後まで見る人が増える。見られ方はサイトの計測で確かめる

サイト側の差し替えは、試算のページ（public/sim/serving-robot.html）の店ごとの行（const UNITY）の動画と表紙を v3 に替えただけです。

#### 依頼87 の依頼文（全文）

````markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 600
---
# 依頼87：固めた版（cs:76）で、サイトに載せる動画をパネル付きの形で撮り直す

エイイチと決めたこと（2026-11-03）：依頼86b の版 cs:76 で Unity を固めた（瞬間移動0・同じ種で同じ結果。報告 claude_code_reports/20261103_base73b.txt・判定 合格）。残った詰まりや試算とのずれは記録だけにし、サイトの動画を出したあとで直す。
サイトに出す Unity の動画は、録画の横にスタッフ・ロボットが何をしているかのパネルを付けた同じ形にそろえる（初見の人に分からないため）。形の決まりは status_videos/tools/PANEL_VIDEO_FORMAT.md、作り方は make_panel_video.py（形は変えない）。
**エイイチは寝ている。人に聞かないと進めない所に当たったら、その店は止めて報告に書き、ほかの店は続ける。時刻で止めず、並べた店が全部終わるまで続ける。**

## 始める前に確かめること（違えば回さずに報告して終わる）
1. 作業場所が cs:76、Builds の実行ファイルが cs:76。保留 0
2. Unity エディタ・night_runner／rec_runner が動いていない。KIOXIA がマウントされ、unity_ledger_v1.lock がない。台帳を archive/unity_ledger_v1_prerec87_20261104/ に退避（行数と md5 を報告に）
3. python3・numpy・Pillow・ffmpeg（依頼71 と同じく miniforge の ros_env の ffmpeg を PATH に足してよい）

## 撮る回（普通・真ん中の人数・ロボット2台・上げ膳・1往復3卓・レジ1つ・今の標準・道の線なし）
依頼75 と同じ並び。③を最初に撮る。
| 順 | 店 | 種 |
|---|---|---|
| 1 | ③ fam_p1 | 7 |
| 2 | ⑦ fam_p5 | 7 |
| 3 | ④ fam_p2 | 1 |
| 4 | ⑤ fam_p3 | 1 |
| 5 | ⑥ fam_p4 | 1 |
| 6 | ② fam_p0 | 8 |
⑧⑨（大型店）は cs:76 で 180回を回していないので今回は撮らない。

- カメラ・置き方は依頼71 と同じ（wide_l30・wide_r30・3840×2160・0.5秒ごと・30コマ/秒・回の最初から全員が帰るまで・カメラの行列も書き出す・距離は依頼71 と同じ決め方）
- パネルの数字は、録画と同じ回の timeline.csv（60秒ごとの店の様子）と、録画のコマと店の時刻を結ぶ frames.csv を使う。録画の回がこの2つを出していなければ、出力だけを足す（動き・決まりには触れない。足したら cs を上げ、同じ種の2回で記録が1行も違わないことを確かめてから撮る）
- 1回の実時間の上限：80 分。同時に2本。止まっても回し直さない
- 置き場所：`/Volumes/KIOXIA/r2r2r-data/service_sim/unity/rec_focus_20261104/{店}/`（前の分は消さない・上書きしない）
- 台帳は追記だけ

## 動画にする（撮れた店ごと）
1. 問題に寄る動画：focus_clips.py（iCloud の unity/focus_clips/。中身は変えない。iCloud の外へ写して使う）で `{店}/focus_v1/` に作る（依頼71・75 と同じ）
2. パネル付きにする：make_panel_video.py で、次の2本を `{店}/panel_v1/` に作る。題は「③ 標準ファミレス・ロボット2台」のように店の名前と台数
   - 通しの動画：wide_l30 の録画を、開店から全員が帰るまで、60〜90秒に収まる速さで（--speed）
   - 問題に寄る動画：focus_v1 の動画それぞれに、同じ時刻の範囲（--from／--to）のパネルを付ける
   - make_panel_video.py の字は Noto Sans CJK JP。Mac に無ければ Homebrew の font-noto-sans-cjk-jp を入れ、字の場所だけを Mac に合わせる（形・色・大きさは変えない。直したら差分を報告に）
   - 出来た動画は 1920x1080・30fps であること（スクリプトが確かめる）
3. 店ごとに1枚、通しの動画の真ん中あたりの1コマを png で `{店}/panel_v1/` に置く（サイトの差し替え前の確認用）

## 報告
claude_code_reports/20261104_rec87.txt に：
- 店ごと：最後まで回ったか・全員帰ったか・実時間・瞬間移動の回数・上位3つの問題（場所・時刻・止まった合計秒・理由）・できた動画の名前と長さ
- 出力を足したなら、その中身と cs・同じ種の2回の一致
- 台帳の行数の変化と md5
**報告の最後の1行は必ず次のどれか**：「判定：合格」／「判定：止めた（決めてほしいことあり）」／「判定：失敗」
````

#### 依頼87 の Claude Code の報告（20261104_rec87.txt・全文）

````text
====================================================================
依頼87：固めた版（cs:76）で、サイトに載せる動画をパネル付きの形で撮り直す
2026-11-04 00:20〜03:15　作業場所 cs:76（保留 0）　build_id cs76_20261103_2122（作り直していない）
====================================================================

結論
  ・6 店（③⑦④⑤⑥②）とも最後まで回り、全員帰った。瞬間移動 0・1コマの跳び 0・上限で止まった回 0。実時間 42.8〜55.2 分
  ・6 店とも focus_v1（問題に寄る動画）と panel_v1（パネル付きの通し 1 本・寄り 7 部品＋つないだもの 1 本・真ん中のコマの png）ができた
    パネル付きの mp4 は 54 本。すべて 1920x1080・30fps であることを確かめた
  ・出力は足していない（cs:76 の回はもう timeline.csv と frames.csv を出していた）
  ・台帳 2675 → 2681 行（追記 6 行だけ。先頭 2675 行の md5 は退避と同じ）
  ・決めてほしいことが 3 つある（字幕の切れ・時刻の書き方・録画した回と録画なしの回の数字の違い）。最後に書く


--------------------------------------------------------------------
0. 始める前の確かめ（どれも合格）
--------------------------------------------------------------------
  1. cm status：/main@ServiceSim (cs:76 - head)、保留 0。
     Builds/headless の build_info.json：unity_cs ServiceSim/cs:76・pending_changes 空
     録画用の cs:76 の実行ファイルは無かった（今ある録画用は rec17_push70＝cs:70 まで）。
     録画用は「-nographics を外して起こすだけ」の同じ普通の player なので（BuildHeadless.cs）、
     Builds/headless をそのまま Builds/rec18_base76 に写して使った（作り直していない。実行ファイルの md5 は同じ a56c2b4ef206f556404e14d873ace1b6。
     Assembly-CSharp.dll に -ssRecord・-ssRecCam・-ssRecHidePaths・-ssMaxWallMin が入っていることを確かめた）
  2. Unity エディタ・night_runner・rec_runner：動いていない（Unity Hub だけ）／KIOXIA：マウント済み／unity_ledger_v1.lock：無し
     台帳を archive/unity_ledger_v1_prerec87_20261104/unity_ledger_v1.csv に退避：2675 行・md5 928e7e5825fee8571769722d6048faf3
  3. python3（miniforge）・numpy 2.4.4・Pillow 12.2.0・ffmpeg／ffprobe（miniforge の ros_env を PATH に足した）
     Noto Sans CJK JP は Mac に無かった（Noto Sans JP だけ）ので、Homebrew の font-noto-sans-cjk-jp を入れた（~/Library/Fonts/NotoSansCJKjp-*.otf）


--------------------------------------------------------------------
1. 撮ったもの
--------------------------------------------------------------------
  記録：night/20261104_rec87/（queue.json・rec_runner.py・runner_log.txt・runs.csv・judge.md・logs・post.py・watch_post.sh・post_log.txt・
        panel87.py・panel_log.txt・report87.py・report87_out.txt・camdist.py・make_panel_video_orig.py）
  並べた回：base73（依頼86・86b の 180 回）の並びから同じ回を写した（すれ違い入・案B切・待機場所へ戻る入・入口番入・持ち場入・
    一方通行切・1本道切・立ち往生の助け入・上げ膳・1往復3卓・レジ1つ・普通・真ん中の人数・ロボット2台）
  rec_runner.py：night/20261103_rec_focus2/rec_runner.py（依頼75）の写し。説明に依頼87 の 3 行を足しただけ
  回し方：--oblique --hide-paths --max-wall-min 80 --parallel 2 --no-retry --limit-min 120 --build Builds/rec18_base76
  カメラ：wide_l30・wide_r30（方位 ±30°・見下ろし 60°・画角 40°・3840×2160）・0.5 秒ごと・30 コマ/秒・回の最初から終わりまで・カメラの行列も
    店ごとの注視点と距離は camdist.py で計算し直し、依頼71・75 と同じ値を確かめた
    （③⑦ (12,8) 39.4 m・④ (8.5,6) 29.2 m・⑤ (13,8.5) 42.2 m・⑥ (12,8.5) 40.7 m・② (12,9.6) 43.5 m）
  置き場所：rec_focus_20261104/{店}/（録画 mp4・frames.csv・camera.json の写し、t=1000 秒のコマ、focus_v1/、panel_v1/）
    回のフォルダ：20261104_rec87_cs76_{店}_r2_s{種}_passon_sbret_ek_post_rescue/
  前の分（rec_focus_20261103 など）は消していない・上書きしていない


--------------------------------------------------------------------
2. 店ごと
--------------------------------------------------------------------
  （時刻は店の時刻・開店から。問題は focus_clips.py と同じまとめ方：30 秒以上の止まりか動けなくなった止まりを、1.5 m・120 秒以内でまとめたもの）

  ③ fam_p1 種7　題「③ 標準ファミレス・ロボット2台」
    最後まで回った（completed）・全員帰った（11,880 秒）・実時間 50.0 分・瞬間移動 0
    問題1 (10.6, 4.2)　2時間14分〜2時間20分　止まった合計 256 秒（5 回）　お客さんとすれ違えなかった
    問題2 (16.5, 5.9)　43分〜46分　止まった合計 159 秒（2 回）　ロボットどうしが道をふさぎ合った
    問題3 (9.6, 4.2)　1時間08分〜1時間10分　止まった合計 120 秒（2 回）　お客さんとすれ違えなかった
    動画：whole_wide_l30_panel.mp4 76.2 秒（10.5 倍）・focus_trial_panel.mp4 68.9 秒

  ⑦ fam_p5 種7　題「⑦ 効率重視・席を詰めた店・ロボット2台」
    最後まで回った・全員帰った（11,737 秒）・実時間 49.8 分・瞬間移動 0
    問題1 (5.8, 4.1)　1時間20分〜1時間25分　213 秒（4 回）　人が立ち止まっていた
    問題2 (8.8, 4.3)　1時間13分〜1時間15分　153 秒（2 回）　ロボットどうしが道をふさぎ合った
    問題3 (1.6, 6.1)　1時間58分〜2時間00分　120 秒（2 回）　お客さんとすれ違えなかった
    動画：whole_wide_l30_panel.mp4 75.5 秒（10.5 倍）・focus_trial_panel.mp4 68.6 秒

  ④ fam_p2 種1　題「④ 効率重視・小さめの店・ロボット2台」
    最後まで回った・全員帰った（12,458 秒）・実時間 55.2 分・瞬間移動 0（依頼75 では 80 分で止まった店）
    問題1 (9.0, 9.0)　2時間03分〜2時間09分　297 秒（5 回）　スタッフとすれ違えなかった
    問題2 (2.1, 4.2)　1時間38分〜1時間43分　292 秒（5 回）　ロボットどうしが道をふさぎ合った
    問題3 (2.2, 2.6)　31分〜33分　194 秒（4 回）　スタッフとすれ違えなかった
    動画：whole_wide_l30_panel.mp4 76.4 秒（11 倍）・focus_trial_panel.mp4 68.9 秒

  ⑤ fam_p3 種1　題「⑤ ゆったり・入口が正面・ロボット2台」
    最後まで回った・全員帰った（11,684 秒）・実時間 52.4 分・瞬間移動 0（依頼75 では止まった店）
    問題1 (8.2, 2.6)　1時間13分〜1時間16分　323 秒（6 回）　ロボットどうしが道をふさぎ合った
    問題2 (4.5, 2.6)　1時間04分〜1時間07分　180 秒（3 回）　ロボットどうしが道をふさぎ合った
    問題3 (14.3, 8.9)　2時間45分〜2時間46分　60 秒（1 回）　ロボットどうしが道をふさぎ合った
    動画：whole_wide_l30_panel.mp4 75.3 秒（10.5 倍）・focus_trial_panel.mp4 61.7 秒

  ⑥ fam_p4 種1　題「⑥ ゆったり・入口が横・ロボット2台」
    最後まで回った・全員帰った（10,428 秒）・実時間 45.0 分・瞬間移動 0
    問題1 (7.6, 4.9)　2時間10分〜2時間13分　120 秒（2 回）　お客さんとすれ違えなかった
    問題2 (6.5, 5.1)　1時間32分〜1時間34分　108 秒（2 回）　スタッフとすれ違えなかった
    問題3 (2.2, 11.6)　1時間18分〜1時間19分　60 秒（1 回）　お客さんとすれ違えなかった
    動画：whole_wide_l30_panel.mp4 74.5 秒（9.5 倍）・focus_trial_panel.mp4 60.9 秒

  ② fam_p0 種8　題「② 定番の郊外型・ロボット2台」
    最後まで回った・全員帰った（10,137 秒）・実時間 42.8 分・瞬間移動 0
    問題1 (9.0, 5.3)　1時間41分〜1時間42分　117 秒（2 回）　ロボットどうしが道をふさぎ合った
    問題2 (8.7, 8.1)　1時間10分〜1時間11分　116 秒（2 回）　ロボットどうしが道をふさぎ合った
    問題3 (13.0, 4.9)　42分〜45分　106 秒（2 回）　お客さんとすれ違えなかった
    動画：whole_wide_l30_panel.mp4 76.1 秒（9 倍）・focus_trial_panel.mp4 55.6 秒

  6 店とも解けずに残った詰まり 0。judge.md：回の失敗 0・基準なし 6（基準データに同じ入切の回が無いため）
  部品ごとの長さと時刻の範囲は {店}/panel_v1/panel_log.txt と night/20261104_rec87/report87_out.txt にある


--------------------------------------------------------------------
3. 動画の作り方
--------------------------------------------------------------------
  focus_v1：focus_clips.py（iCloud の unity/focus_clips/ から /tmp/rec87/fc/ に写した。md5 a7e1829a2479477b37779221f74235ce・中身は変えていない）を
    依頼75 と同じ post.py（置き場所だけ変えた写し）で回した。字は依頼75 と同じヒラギノ（FOCUS_FONT）
  panel_v1：make_panel_video.py を panel87.py から呼んだ（形はそのまま）
    ・通し：wide_l30 の録画の最初（開店 0 秒）から最後（全員が帰るまで）。速さは 0.5 刻みで 75 秒にいちばん近く、60〜90 秒に入るものを選んだ
    ・寄り：focus_v1 の部品（p00_open・p01a_wide・p01b_focus …）ごとに、focus_clips.py と同じ計算で部品のコマと店の時刻を出して
      部品ごとの frames.csv を作り、同じ時刻の範囲（--from／--to）でパネルを付けた。部品のコマ数が計算と合うことを確かめてから作った
      寄り（pNNb_focus）は focus_clips.py が 0.5 倍にしている（1コマを 2 回ずつ出す）ので、偶数コマだけを抜いた素材を --speed 0.5 で渡した
      （見た目の速さは元の寄りと同じ。パネルの店の時刻も合う）
    ・focus_trial_panel.mp4：部品のパネル付きを focus_trial.mp4 と同じ順につないだもの（ffmpeg concat・作り直しなし）
    ・png：通しの動画の真ん中のコマ（whole_wide_l30_panel_mid.png）
    ・1920x1080・30fps は panel87.py の中で ffprobe で確かめた（make_panel_video.py 自体には確かめる所が無かった）
  make_panel_video.py の直し（字の場所だけ。status_videos/tools/。元は night/20261104_rec87/make_panel_video_orig.py に残した）
    md5 99fa57d12accdbe72bc19f35ecf050bd → ad26939a858ffa57ca3085ecc33806d8
    差分：
      < FONT = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
      < FONTB = "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc"
      ---
      > import os
      > # 字は Noto Sans CJK JP。Linux の場所が無ければ Mac（Homebrew の font-noto-sans-cjk-jp）の場所（2026-11-04・依頼87）
      > _MAC = os.path.expanduser("~/Library/Fonts")
      > FONT = next((f for f in ("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", _MAC + "/NotoSansCJKjp-Regular.otf") if os.path.exists(f)), None)
      > FONTB = next((f for f in ("/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc", _MAC + "/NotoSansCJKjp-Bold.otf") if os.path.exists(f)), None)
    Linux の場所を先に見るので、Linux では今までと同じに動く。形・色・大きさは変えていない
  題の店の名前：③ は依頼文の「標準ファミレス」。ほかは LOG415 の名前（② 定番の郊外型・④ 効率重視・小さめの店・⑤ ゆったり・入口が正面・
    ⑥ ゆったり・入口が横・⑦ 効率重視・席を詰めた店）。LOG415 では ③ は「効率重視・入口が角」


--------------------------------------------------------------------
4. 出力を足したか
--------------------------------------------------------------------
  足していない。cs:76 の回はもう timeline.csv（60 秒ごと）と、録画のカメラごとの frames.csv を出していた。cs は上げていない


--------------------------------------------------------------------
5. 台帳
--------------------------------------------------------------------
  2675 行 → 2681 行（追記 6 行だけ。どれも completed・unity_cs ServiceSim/cs:76）
  始める前の md5：928e7e5825fee8571769722d6048faf3（退避と同じ）
  終わったあとの md5：c25f3f880430ef92cb70dc2d141aa803
  終わったあとの先頭 2675 行の md5：928e7e5825fee8571769722d6048faf3（前の行は変わっていない）。鍵ファイルは残っていない


--------------------------------------------------------------------
6. 気づいたこと（記録だけ）
--------------------------------------------------------------------
  ・録画した回は、同じ種の録画なしの回（base73・cs:76）と記録が一致しない。6 店とも trips・stops・timeline・groups・dishes・rescues が違う。
    ③ 種7 では 860 秒ごろの往復から分かれ、全員が帰った時刻 11,880 秒（録画なし 11,805 秒）・入店待ちの平均 3.06 分（同 3.03 分）・
    往復 129 回（同 118 回）。録画の回どうしの同じ種は比べていない（録画は同じ店を 1 回ずつ）
    動画のパネルは録画と同じ回の timeline.csv を使っているので、動画の中の映像と数字は合っている
  ・make_panel_video.py は時刻を「開店から 1:39」と書く。PANEL_VIDEO_FORMAT.md の決まりは「1時間39分」と書き、「1:54」とは書かない
  ・focus_v1 の動画に make_panel_video.py でパネルを付けると、1280×720 の部品を高さ 1080 に広げてから真ん中の 1360 px を切り出すので、
    focus_clips.py が左上に書いた字幕（「寄り：ロボットどうしが…」・店の時刻・止まった合計）の左がおよそ 280 px 切れ、
    その上に色の説明（お客さん／スタッフ／ロボット）が重なる。寄りの映像（問題の場所の輪）は真ん中なので切れていない


====================================================================
変えたファイル・作ったもの
====================================================================
  直した：status_videos/tools/make_panel_video.py（字の場所だけ。上の差分）
  入れた：Homebrew の font-noto-sans-cjk-jp
  写した：Builds/rec18_base76（Builds/headless＝cs:76 の写し）
  新しく置いた：night/20261104_rec87/（上の 1 章）・rec_focus_20261104/（6 店）・20261104_rec87_cs76_*（6 回の出力）・
                archive/unity_ledger_v1_prerec87_20261104/
  台帳：追記 6 行
  /tmp に残したもの：/tmp/rec87/（queue の写し・focus_clips.py の写し・前回の録画で作り方を試した動画 test・testrec）
  変えていない：Unity のコード・実行ファイルの中身・focus_clips.py・night_runner.py・make_queue.py・judge_night.py・前の録画と出力


====================================================================
決めてほしいこと
====================================================================
  1. 問題に寄る動画（panel_v1/focus_trial_panel.mp4 と部品）で、字幕の左が切れ、色の説明と重なる（6 章）。
     サイトに出す前に、どちらを変えるか（focus_clips.py の字幕の位置か、make_panel_video.py の寄りの部品の広げ方か、
     寄りはパネル付きにしないか）を決めてほしい。どちらも今回は「変えない」なのでそのまま作った
  2. 時刻の書き方：make_panel_video.py は「開店から 1:39」、PANEL_VIDEO_FORMAT.md は「1時間39分」。どちらに合わせるか
     （スクリプトを直すなら hm() の 1 行で、作り直しは 1 店 5〜6 分）
  3. 録画した回は、同じ種の録画なしの回と数字が一致しない（6 章）。サイトの動画の数字（パネル）と台帳の 180 回の数字が少し違うことを
     そのままにしてよいか

判定：止めた（決めてほしいことあり）
````

#### 依頼88 の依頼文（全文）

````markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 120
---
# 依頼88：依頼87 のパネル付き動画を、字幕が切れない形・時刻の書き方を直した形で作り直す

依頼87 の報告（claude_code_reports/20261104_rec87.txt）の「決めてほしいこと」への答え（エイイチ了承 2026-11-04）：
- 1：問題に寄る動画（focus_v1 の部品）は切らずに横幅に合わせて縮め、上下に余白を足す。make_panel_video.py に --fit を足した（Claude が直した。形の決まりは PANEL_VIDEO_FORMAT.md に追記済み）
- 2：時刻は決まりどおり「1時間39分」（1時間未満は「35分」）。make_panel_video.py の hm() を直した
- 3：録画した回と録画しない回の数字の違いはそのまま（動画の中の映像と数字は同じ回で合っている）。記録だけ
Unity は触らない。録画も撮り直さない（rec_focus_20261104 の録画・frames.csv・focus_v1 をそのまま使う）。

## やること
1. night/20261104_rec87/panel87.py を写して panel88.py にする。変えるのは次の3つだけ
   - 出力先を {店}/panel_v2/ にする（panel_v1 は消さない・上書きしない）
   - focus_v1 の部品（p00_open・pNNa_wide・pNNb_focus）を make_panel_video.py に渡すときに --fit を付ける。通しの動画（4K の録画）は付けない
   - make_panel_video.py は status_videos/tools/ の今のもの（--fit と hm() の直しが入ったもの）を使う
2. 6店（rec_focus_20261104/fam_p0〜fam_p5）を、依頼87 と同じ題で作る（題は各店の panel_v1/panel_log.txt の1行目）
3. 確かめ：どれも 1920x1080・30fps、部品のコマ数が依頼87 と同じ、通しの真ん中の png と、focus_trial_panel.mp4 の寄りの部品の1コマ（p01b_focus の真ん中）を png で panel_v2/ に置く。字幕の左端が切れていないこと（字幕の文字が録画の枠の中にあること）を目で見られる形で

## 報告
claude_code_reports/20261104_panel88.txt に：店ごとにできた動画の名前と長さ、確かめの結果、panel88.py と panel87.py の差分。
**報告の最後の1行は必ず次のどれか**：「判定：合格」／「判定：止めた（決めてほしいことあり）」／「判定：失敗」
````

#### 依頼88 の Claude Code の報告（20261104_panel88.txt・全文）

````text
====================================================================
依頼88：依頼87 のパネル付き動画を、字幕が切れない形・時刻の書き方を直した形で作り直す
2026-11-04 06:05〜06:25
====================================================================

結論
  ・6 店（② fam_p0・③ fam_p1・④ fam_p2・⑤ fam_p3・⑥ fam_p4・⑦ fam_p5）とも panel_v2/ ができた（1 店 9 本の mp4・計 54 本）
  ・54 本すべて 1920x1080・30fps。コマ数は 54 本とも依頼87（panel_v1）と同じ。focus_trial_panel.mp4 のコマ数は部品の和と同じ
  ・寄りの部品は録画を切らずに横幅 1360 px に縮め、上下に余白を足した形になり、focus_clips.py の字幕（左上）が左端まで全部見える。
    色の説明（お客さん／スタッフ／ロボット）は上の余白に入り、字幕と重ならない
  ・時刻は「開店から 1時間42分」の形になった（1時間未満は「35分」の形）
  ・panel_v1・録画・frames.csv・focus_v1 は消していない・上書きしていない。Unity は触っていない。録画は撮り直していない


--------------------------------------------------------------------
1. 作り方
--------------------------------------------------------------------
  置き場所：night/20261104_panel88/（KIOXIA の service_sim/unity/night/）
    panel88.py：night/20261104_rec87/panel87.py の写し。変えたのは 3 つだけ（下の差分）
    run88.sh：6 店を 2 店ずつ並べて panel88.py を回すもの。題は各店の panel_v1/panel_log.txt の 1 行目（「題: 」を取ったもの）
    check88.py：確かめ（大きさ・速さ・コマ数を panel_v1 と比べる・focus_trial の p01b_focus の真ん中のコマを png に）
    log_fam_p0〜p5.txt・panel_log.txt（回したときの出力）・check88_out.txt（確かめの出力）
  make_panel_video.py：status_videos/tools/ の今のもの（md5 eed8539039501415828a5ff39384c889。--fit と hm() の直し入り）
  focus_clips.py：依頼87 と同じ /tmp/rec87/fc/focus_clips.py（md5 a7e1829a2479477b37779221f74235ce・中身は変えていない）
    部品のコマと店の時刻を出す計算に使うだけ（focus_v1 は作り直していない）
  回した時間：06:07:59〜06:13:14（6 店とも rc=0）


--------------------------------------------------------------------
2. 店ごとにできた動画（{店}/panel_v2/・長さは秒）
--------------------------------------------------------------------
  ② fam_p0 種8　題「② 定番の郊外型・ロボット2台」
    whole_wide_l30_panel.mp4 76.1（9 倍）／p00_open 8.0／p01a_wide 3.0／p01b_focus 10.7／p02a_wide 3.0／p02b_focus 10.5／
    p03a_wide 3.0／p03b_focus 17.3／focus_trial_panel.mp4 55.6
  ③ fam_p1 種7　題「③ 標準ファミレス・ロボット2台」
    whole 76.2（10.5 倍）／p00_open 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.3／p03a 3.0／p03b 17.3／focus_trial 68.9
  ④ fam_p2 種1　題「④ 効率重視・小さめの店・ロボット2台」
    whole 76.4（11 倍）／p00_open 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.3／p03a 3.0／p03b 17.3／focus_trial 68.9
  ⑤ fam_p3 種1　題「⑤ ゆったり・入口が正面・ロボット2台」
    whole 75.3（10.5 倍）／p00_open 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.3／p03a 3.0／p03b 10.1／focus_trial 61.7
  ⑥ fam_p4 種1　題「⑥ ゆったり・入口が横・ロボット2台」
    whole 74.5（9.5 倍）／p00_open 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 16.5／p03a 3.0／p03b 10.1／focus_trial 60.9
  ⑦ fam_p5 種7　題「⑦ 効率重視・席を詰めた店・ロボット2台」
    whole 75.5（10.5 倍）／p00_open 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.0／p03a 3.0／p03b 17.3／focus_trial 68.6
  （部品の名前はどれも pNN…_panel.mp4。店の時刻の範囲は各店の panel_v2/panel_log.txt。依頼87 と同じ）
  png（各店の panel_v2/）：
    whole_wide_l30_panel_mid.png（通しの真ん中のコマ）
    focus_trial_panel_p01b_mid.png（focus_trial_panel.mp4 の中の p01b_focus の真ん中のコマ。② はコマ 491、ほかの 5 店はコマ 589）


--------------------------------------------------------------------
3. 確かめの結果（check88_out.txt）
--------------------------------------------------------------------
  ・大きさと速さ：54 本とも 1920x1080・30/1
  ・コマ数：54 本とも panel_v1 と同じ（例 ② whole 2284・p01b_focus 322・focus_trial 1667／③ whole 2286・focus_trial 2067）。違う 0
  ・focus_trial_panel.mp4 のコマ数＝部品 7 本のコマ数の和（6 店とも）
  ・目で見た（12 枚の png を並べて見た）：
    寄りの部品：6 店とも字幕 2 行（「寄り：…」と「店の時刻 …・止まった合計 …」）が左端の「寄」から最後の「（N回）」まで録画の枠の中にある。
      色の説明は上の余白にあり、字幕とも映像とも重ならない。問題の場所の輪も枠の中。依頼87 の同じ所（③ p01b_focus）は
      字幕の左が切れて「んとすれ違えず…」になり、色の説明が重なっていたことを先に確かめてから比べた
    通しの動画：依頼87 と同じ形（--fit なし・切り出し）。② の真ん中のコマを panel_v1 と並べ、時刻の字だけが違うことを確かめた
    時刻：「開店から 1時間25分」「開店から 2時間15分」など。「1:39」の形は出ていない


--------------------------------------------------------------------
4. panel88.py と panel87.py の差分（diff panel87.py panel88.py）
--------------------------------------------------------------------
  1,2c1,7
  < """依頼87：撮れた店ごとに、make_panel_video.py（status_videos/tools・形はそのまま）でパネル付きの動画を {店}/panel_v1/ に作る
  < 使い方: python3 panel87.py <録画のフォルダ {店}/> <回のフォルダ> <題>
  ---
  > """依頼88：panel87.py（依頼87）の写し。変えたのは 3 つだけ
  >   ・出力先を {店}/panel_v2/ にする（panel_v1 は消さない・上書きしない）
  >   ・focus_v1 の部品（p00_open・pNNa_wide・pNNb_focus）は make_panel_video.py に --fit を付けて渡す（字幕を切らない）。通しは付けない
  >   ・make_panel_video.py は status_videos/tools/ の今のもの（--fit と hm() の直し入り）
  > 以下は依頼87 の説明のまま（panel_v1 → panel_v2 と読む）
  > 依頼87：撮れた店ごとに、make_panel_video.py（status_videos/tools・形はそのまま）でパネル付きの動画を {店}/panel_v1/ に作る
  > 使い方: python3 panel88.py <録画のフォルダ {店}/> <回のフォルダ> <題>
  23c28
  < out = rec / 'panel_v1'
  ---
  > out = rec / 'panel_v2'
  25c30
  <     sys.exit('panel_v1 がもうあります（上書きしません）: %s' % out)
  ---
  >     sys.exit('panel_v2 がもうあります（上書きしません）: %s' % out)
  27c32
  < tmp = Path(tempfile.mkdtemp(prefix='panel87_'))
  ---
  > tmp = Path(tempfile.mkdtemp(prefix='panel88_'))
  47c52
  < def panel(src, frames_csv, dst, t_from=None, t_to=None, speed=1.0):
  ---
  > def panel(src, frames_csv, dst, t_from=None, t_to=None, speed=1.0, fit=False):
  48a54,55
  >     if fit:
  >         cmd += ['--fit']
  120c127
  <     d = panel(use, fcsv, dst, t_from=ts[0], t_to=ts[-1], speed=sp)
  ---
  >     d = panel(use, fcsv, dst, t_from=ts[0], t_to=ts[-1], speed=sp, fit=True)
  説明の文と一時フォルダの名前（panel88_）のほかは、出力先 panel_v2 と、寄りの部品にだけ --fit を付ける所だけ。
  通し（whole_wide_l30_panel.mp4）の呼び出しは fit を渡さないので --fit なし


--------------------------------------------------------------------
5. 気づいたこと（記録だけ・今回は変えていない）
--------------------------------------------------------------------
  ・寄りの部品の字幕は focus_clips.py が focus_v1 に焼き込んだもので、店の時刻を「101:49〜102:54」（分:秒）の形で書いている。
    パネルの「1時間42分」とは書き方が違う。focus_v1 はそのまま使う依頼なので変えていない
  ・依頼87 の 3 つ目（録画した回と録画しない回の数字の違い）は記録どおりそのまま


====================================================================
変えたファイル・作ったもの
====================================================================
  新しく置いた：night/20261104_panel88/（panel88.py・run88.sh・check88.py・log_fam_p0〜p5.txt・panel_log.txt・check88_out.txt）
                rec_focus_20261104/fam_p0〜fam_p5/panel_v2/（mp4 9 本・panel_log.txt・png 2 枚）
                claude_code_reports/20261104_panel88.txt（これ）
  変えていない：panel87.py・make_panel_video.py・focus_clips.py・panel_v1・focus_v1・録画・frames.csv・Unity・台帳
  git：触っていない（作ったものは KIOXIA と iCloud の中で、このリポジトリの外）


====================================================================
決めてほしいこと
====================================================================
  なし（今回の作業を止めることはなかった）
  次に考えるなら：寄りの字幕の中の店の時刻「101:49〜102:54」を「1時間41分〜1時間42分」の形にそろえるか（focus_clips.py の直しと focus_v1 の作り直しになる）

判定：合格
````

#### 依頼89 の依頼文（全文）

````markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 120
---
# 依頼89：寄りの字幕の時刻を「開店から 2時間14分」の形に直し、問題に寄る動画とパネル付き動画を作り直す

エイイチの指示（2026-11-04）：寄りの字幕の店の時刻「134:14〜140:10」を、パネルと同じ「開店から 2時間14分〜2時間20分」の形に直す。スマホ用の別の形は作らない。
focus_clips.py（iCloud の unity/focus_clips/）は Claude が直した：caption() の時刻を hm() で書くようにしただけ（直す前の写しは focus_clips_pre20261104.py）。ほかは変えていない。
Unity は触らない。録画は撮り直さない（rec_focus_20261104 の録画・frames.csv をそのまま使う）。

## やること
1. 直した focus_clips.py（中身は変えない。iCloud の外へ写して使う）で、6店（rec_focus_20261104/fam_p0〜fam_p5）の問題に寄る動画を {店}/focus_v2/ に作る。字幕の倍率などの引数は依頼87 の focus_v1 と同じにする（focus_v1 は消さない・上書きしない）
2. night/20261104_panel88/panel88.py を写して panel89.py にし、読む部品を focus_v2、出力を {店}/panel_v3/ にする（変えるのはこの2つだけ。--fit はそのまま）。make_panel_video.py は status_videos/tools/ の今のもの
3. 確かめ：どれも 1920x1080・30fps、部品のコマ数が focus_v1・panel_v2 と同じ、各店の focus_trial_panel.mp4 の p01b_focus の真ん中の1コマを png で panel_v3/ に置く（字幕が「開店から …時間…分〜…」になっていることを目で見られる形で）
4. サイト用に書き出す：各店の panel_v3/focus_trial_panel.mp4 を、KIOXIA の service_sim/unity/series8_web_20261104/upload_v3/ に series8_unity_{店}_v3.mp4 として（ffmpeg -c:v libx264 -preset veryfast -crf 26 -movflags +faststart -an）、表紙は同じ動画の 1 秒目のコマを series8_unity_{店}_v3.jpg（-q:v 4）。R2 への入れ込みとサイトの差し替えは Claude がする

## 報告
claude_code_reports/20261104_focus89.txt に：店ごとにできた動画の名前と長さ、確かめの結果、panel89.py と panel88.py の差分、upload_v3 の中身。
**報告の最後の1行は必ず次のどれか**：「判定：合格」／「判定：止めた（決めてほしいことあり）」／「判定：失敗」
````

#### 依頼89 の Claude Code の報告（20261104_focus89.txt・全文）

````text
====================================================================
依頼89：寄りの字幕の時刻を「開店から 2時間14分」の形に直し、問題に寄る動画とパネル付き動画を作り直す
2026-11-04 06:35〜06:50
====================================================================

結論
  ・6 店（② fam_p0・③ fam_p1・④ fam_p2・⑤ fam_p3・⑥ fam_p4・⑦ fam_p5）とも focus_v2/ と panel_v3/ ができた
  ・寄りの字幕の時刻は「開店から 2時間14分〜2時間20分」の形になった（1時間未満は「42分〜45分」の形）。6 店の png を目で見て確かめた
  ・panel_v3 の mp4 は 54 本とも 1920x1080・30fps。コマ数は 54 本とも panel_v2 と同じ。focus_v2 の mp4 は 48 本ともコマ数が focus_v1 と同じ
  ・upload_v3/ に mp4 6 本と jpg 6 枚を書き出した（R2 へは入れていない。サイトも触っていない）
  ・focus_v1・panel_v1・panel_v2・upload_v2・録画・frames.csv は消していない・上書きしていない。Unity は触っていない。録画は撮り直していない


--------------------------------------------------------------------
1. 作り方
--------------------------------------------------------------------
  置き場所：KIOXIA の service_sim/unity/night/20261104_focus89/
    focus_clips_used.py：使った focus_clips.py の写し（記録用）
    run_focus89.sh・focus_log.txt：focus_v2 を作ったもの・その出力
    panel89.py・run89.sh・log_fam_p0〜p5.txt・panel_log.txt：panel_v3 を作ったもの・その出力
    diff_panel88_89.txt：panel88.py との差分
    check89.py・check89_out.txt：確かめ・その出力
    export89.sh・export89_log.txt：サイト用の書き出し
  focus_clips.py：iCloud の unity/focus_clips/focus_clips.py を /tmp/rec89/fc/ に写して使った（中身は変えていない）
    md5 63829a223b8d615c88a44ef493f60cd4（iCloud の今のもの・写し・記録用の写しの 3 つとも同じ）
    直す前の写し focus_clips_pre20261104.py（md5 a7e1829a…）との違いは hm() を足したことと、caption() の 2 行目だけであることを diff で見た
  focus_v2 の引数：依頼87 の focus_v1（night/20261104_rec87/post.py）と同じ
    python3 focus_clips.py {店}/ {回のフォルダ} {店}/focus_v2、環境は FOCUS_FONT＝ヒラギノ角ゴシック W6 だけ
    （FOCUS_TEXT_SCALE・FOCUS_TOP などは focus_v1 と同じく決めていない＝初めの値）
    回した時間 06:37:25〜06:37:55（6 店とも rc=0）。問題の場所・まとめ方・止まった合計は 6 店とも focus_v1 と同じ
  panel_v3：panel89.py（下の 4 章）を run89.sh で 2 店ずつ回した。題は依頼88 と同じく各店の panel_v1/panel_log.txt の 1 行目
    make_panel_video.py：status_videos/tools/ の今のもの（md5 eed8539039501415828a5ff39384c889。依頼88 と同じ）
    回した時間 06:38:09〜06:43:24（6 店とも rc=0）


--------------------------------------------------------------------
2. 店ごとにできた動画（長さは秒）
--------------------------------------------------------------------
  字幕（focus_v2 の各問題。focus_log.txt から）と panel_v3 の長さ

  ② fam_p0　題「② 定番の郊外型・ロボット2台」
    字幕：1「開店から 1時間41分〜1時間42分・止まった合計 117秒（2回）」／2「1時間10分〜1時間11分・116秒（2回）」／3「42分〜45分・106秒（2回）」
    focus_v2：focus_trial 55.7／p00_open 8.0／p01a_wide 3.0／p01b_focus 10.8／p02a 3.0／p02b 10.6／p03a 3.0／p03b 17.3
    panel_v3：whole_wide_l30_panel 76.1（9 倍）／p00_open 8.0／p01a 3.0／p01b 10.7／p02a 3.0／p02b 10.5／p03a 3.0／p03b 17.3／focus_trial_panel 55.6
  ③ fam_p1　題「③ 標準ファミレス・ロボット2台」
    字幕：1「開店から 2時間14分〜2時間20分・止まった合計 256秒（5回）」／2「43分〜46分・159秒（2回）」／3「1時間08分〜1時間10分・120秒（2回）」
    focus_v2：focus_trial 69.0／p00 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.3／p03a 3.0／p03b 17.3
    panel_v3：whole 76.2（10.5 倍）／p00 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.3／p03a 3.0／p03b 17.3／focus_trial_panel 68.9
  ④ fam_p2　題「④ 効率重視・小さめの店・ロボット2台」
    字幕：1「開店から 2時間03分〜2時間09分・297秒（5回）」／2「1時間38分〜1時間43分・292秒（5回）」／3「31分〜33分・194秒（4回）」
    focus_v2：focus_trial 69.0／p00 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.3／p03a 3.0／p03b 17.3
    panel_v3：whole 76.4（11 倍）／p00 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.3／p03a 3.0／p03b 17.3／focus_trial_panel 68.9
  ⑤ fam_p3　題「⑤ ゆったり・入口が正面・ロボット2台」
    字幕：1「開店から 1時間13分〜1時間16分・323秒（6回）」／2「1時間04分〜1時間07分・180秒（3回）」／3「2時間45分〜2時間46分・60秒（1回）」
    focus_v2：focus_trial 61.8／p00 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.3／p03a 3.0／p03b 10.1
    panel_v3：whole 75.3（10.5 倍）／p00 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.3／p03a 3.0／p03b 10.1／focus_trial_panel 61.7
  ⑥ fam_p4　題「⑥ ゆったり・入口が横・ロボット2台」
    字幕：1「開店から 2時間10分〜2時間13分・120秒（2回）」／2「1時間32分〜1時間34分・108秒（2回）」／3「1時間18分〜1時間19分・60秒（1回）」
    focus_v2：focus_trial 61.1／p00 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 16.6／p03a 3.0／p03b 10.1
    panel_v3：whole 74.5（9.5 倍）／p00 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 16.5／p03a 3.0／p03b 10.1／focus_trial_panel 60.9
  ⑦ fam_p5　題「⑦ 効率重視・席を詰めた店・ロボット2台」
    字幕：1「開店から 1時間20分〜1時間25分・213秒（4回）」／2「1時間13分〜1時間15分・153秒（2回）」／3「1時間58分〜2時間00分・120秒（2回）」
    focus_v2：focus_trial 68.7／p00 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.1／p03a 3.0／p03b 17.3
    panel_v3：whole 75.5（10.5 倍）／p00 8.0／p01a 3.0／p01b 17.3／p02a 3.0／p02b 17.0／p03a 3.0／p03b 17.3／focus_trial_panel 68.6
  （panel_v3 の部品の名前は pNN…_panel.mp4。店の時刻の範囲は各店の panel_v3/panel_log.txt。依頼88 と同じ値）
  focus_v2 には mp4 のほか episodes.json・list.txt・ov_*.png も focus_clips.py が出した（focus_v1 と同じ形）
  png：各店の panel_v3/whole_wide_l30_panel_mid.png（panel89.py が出す通しの真ん中）と
       panel_v3/focus_trial_panel_p01b_mid.png（確かめ用。② はコマ 491、ほかの 5 店はコマ 589）


--------------------------------------------------------------------
3. 確かめの結果（check89_out.txt）
--------------------------------------------------------------------
  ・panel_v3：54 本とも 1920x1080・30/1。コマ数は 54 本とも panel_v2 と同じ（違う 0）
      例 ② whole 2284・p01b 322・focus_trial 1667／③ whole 2286・focus_trial 2067／⑤ focus_trial 1851／⑥ 1828／⑦ 2058
    focus_trial_panel.mp4 のコマ数＝部品 7 本のコマ数の和（6 店とも）
  ・focus_v2：48 本とも 1280x720・30/1 で、コマ数は focus_v1 と同じ（違う 0）
    focus_v2 の部品は focus_v1 と同じく 1280x720（focus_clips.py の出す大きさ。1920x1080 になるのは panel_v3 のほう）
  ・focus_v1 と focus_v2 を真ん中のコマで比べた：p00_open・pNNa_wide（字幕に時刻が無い部品）は違いなし。
    寄りの部品で違うのは字幕の 2 行目の場所（x 15〜約 660・y 51〜73）。いくつかの部品で字幕の外に違いが出たので
    ⑥ p02b_focus で調べたところ、字幕の外で差が 40 を超える画素は 81 万 9200 画素のうち 1 画素（差 46）で、圧縮の揺れだった
  ・目で見た：6 店の focus_trial_panel_p01b_mid.png（③ ② は全体、残りは字幕の所を切り出して並べた）
    6 店とも 2 行目が「開店から 1時間41分〜1時間42分・止まった合計 117秒（2回）」の形。「134:14」の形は出ていない。
    字幕は左端の「寄」から最後の「（N回）」まで枠の中にあり、色の説明（上の余白）とも重ならない。パネルの「開店から 2時間15分」と書き方がそろった
  ・upload_v3：mp4 6 本とも h264・1920x1080・30/1・音なし。コマ数は元の focus_trial_panel.mp4 と同じ。6 本とも moov が mdat より前（faststart）。
    jpg 6 枚とも 1920x1080。AppleDouble（._）なし
  ・そのままであることの確かめ：focus_v1・panel_v1・panel_v2 の中に、依頼88 の確かめより後に変わったファイルは無い。
    upload_v2 のファイルの時刻は 06:22〜06:23（今回の作業より前）で、今回は触っていない


--------------------------------------------------------------------
4. panel89.py と panel88.py の差分（diff panel88.py panel89.py）
--------------------------------------------------------------------
  27,28c27,28
  < focus = rec / 'focus_v1'
  < out = rec / 'panel_v2'
  ---
  > focus = rec / 'focus_v2'
  > out = rec / 'panel_v3'
  30c30
  <     sys.exit('panel_v2 がもうあります（上書きしません）: %s' % out)
  ---
  >     sys.exit('panel_v3 がもうあります（上書きしません）: %s' % out)
  読む部品（focus_v2）と出力先（panel_v3）だけ。30 行目は出力先がもうあるときに止まる知らせの文で、出力先の名前に合わせただけ。
  --fit の付け方・説明の文・一時フォルダの名前（panel88_）はそのまま。
  部品のコマと時刻の計算に使う focus_clips は panel88.py のまま /tmp/rec87/fc（直す前の写し）を読む。
  直しは字幕の文字だけで、コマと時刻の計算は直す前と同じなので結果は変わらない（コマ数が計算と合うことは panel89.py の中でも確かめて通った）


--------------------------------------------------------------------
5. upload_v3 の中身（KIOXIA の service_sim/unity/series8_web_20261104/upload_v3/）
--------------------------------------------------------------------
  series8_unity_fam_p0_v3.mp4  1,049,334 バイト  55.6 秒  1667 コマ
  series8_unity_fam_p0_v3.jpg     97,012 バイト
  series8_unity_fam_p1_v3.mp4  1,588,877 バイト  68.9 秒  2067 コマ
  series8_unity_fam_p1_v3.jpg    105,725 バイト
  series8_unity_fam_p2_v3.mp4  1,247,625 バイト  68.9 秒  2067 コマ
  series8_unity_fam_p2_v3.jpg    106,811 バイト
  series8_unity_fam_p3_v3.mp4  1,252,906 バイト  61.7 秒  1851 コマ
  series8_unity_fam_p3_v3.jpg    112,144 バイト
  series8_unity_fam_p4_v3.mp4  1,303,673 バイト  60.9 秒  1828 コマ
  series8_unity_fam_p4_v3.jpg    108,590 バイト
  series8_unity_fam_p5_v3.mp4  1,883,410 バイト  68.6 秒  2058 コマ
  series8_unity_fam_p5_v3.jpg    111,633 バイト
  mp4：ffmpeg -i panel_v3/focus_trial_panel.mp4 -c:v libx264 -preset veryfast -crf 26 -movflags +faststart -an
  jpg：ffmpeg -ss 1 -i （書き出した同じ mp4）-frames:v 1 -q:v 4
  R2 へは入れていない。サイトの差し替えもしていない（依頼どおり Claude がする）


====================================================================
変えたファイル・作ったもの
====================================================================
  新しく置いた：night/20261104_focus89/（1 章のもの）
                rec_focus_20261104/fam_p0〜fam_p5/focus_v2/・panel_v3/
                series8_web_20261104/upload_v3/（mp4 6 本・jpg 6 枚）
                claude_code_reports/20261104_focus89.txt（これ）
                /tmp/rec89/fc/focus_clips.py（使った写し）
  変えていない：focus_clips.py（iCloud）・panel88.py・make_panel_video.py・focus_v1・panel_v1・panel_v2・upload_v2・録画・frames.csv・Unity・台帳
  git：触っていない（作ったものは KIOXIA と iCloud の中で、リポジトリの外）


====================================================================
決めてほしいこと
====================================================================
  なし

判定：合格
````

#### PANEL_VIDEO_FORMAT.md（パネル付き動画の決まり・2026-11-04 の追記を含む全文）

````markdown
# ServiceSim パネル付き動画の形（決まり）

サイトに出す ServiceSim の動画（通し・問題に寄る・比較）は、すべてこの形にそろえる。2026-11-03 エイイチ了承。変えるときはエイイチに確かめてから。
作り方：`tools/make_panel_video.py rec.mp4 frames.csv timeline.csv out.mp4 --title "③ 標準ファミレス・ロボット2台"`（形はこのスクリプトに固定してある。手で別の形を作らない）

- 画面：1920x1080・30fps。左 1360px が録画、右 560px がパネル
- 色：立体と同じ。お客さん＝黄・スタッフ＝青・ロボット＝白。録画の左上に色の説明「お客さん／スタッフ／ロボット」
- パネル（上から）：題（店・台数）→「開店から 1時間54分」→ スタッフ N人がしていること（案内・料理・呼び出し・会計・片付け・ロボットの助け・手すき。1人＝青い四角1つ）→ ロボット N台（運んでいる＝白・黒縁／待機＝薄い）→ 入口で待つ組・席にいる組・片付けを待つ卓 → 入口で待つ組の一日の線
- 寄りの部品など、録画に字幕が入っているもの（focus_clips.py の部品）は --fit で入れる：切らずに横幅 1360px に縮め、上下の余白は Unity の背景に近い色（2026-11-04 エイイチ了承。依頼87 で字幕の左が切れたため）
- 言葉：「客」ではなく「お客さん」。時間は「1時間54分」と書き、「1:54」とは書かない（1時間未満は「35分」。スクリプトは 2026-11-04 にこの決まりに合わせた）
- 数字：録画と同じ回の timeline.csv を使う。別の回を重ねるのは試しのときだけ（--trial、題に（試作）が付く）
- 崩れ防止：長い題・人数や台数が多いときは字や四角を小さくして収める。パネルがはみ出す・列が足りない・出来た動画が 1920x1080 でないときは止まる
````

#### make_panel_video.py（--fit と時刻の書き方を足した版の全文）

````python
"""ServiceSim の録画に、店の様子のパネル（timeline.csv）を横に付ける。
使い方: python3 make_panel_video.py rec.mp4 frames.csv timeline.csv out.mp4 [--from 秒] [--to 秒] [--speed 倍] [--title 文字]
録画は 1コマ = frames.csv の t_s（店の時刻・秒）。パネルは timeline.csv の t_s ごと（60秒おき）に描き直す。
"""
import csv, sys, argparse, subprocess, tempfile, pathlib, bisect
from PIL import Image, ImageDraw, ImageFont

W, H, PW = 1920, 1080, 560          # 全体・パネルの幅
VW = W - PW                          # 録画の幅
BG, INK, QUIET, LINE = "#faf9f5", "#1d1d1b", "#6b6a64", "#d9d6cc"
ACC, GOOD, BAD, WARN = "#2f6fdf", "#1d9e75", "#d85a30", "#c98a1a"
import os
# 字は Noto Sans CJK JP。Linux の場所が無ければ Mac（Homebrew の font-noto-sans-cjk-jp）の場所（2026-11-04・依頼87）
_MAC = os.path.expanduser("~/Library/Fonts")
FONT = next((f for f in ("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", _MAC + "/NotoSansCJKjp-Regular.otf") if os.path.exists(f)), None)
FONTB = next((f for f in ("/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc", _MAC + "/NotoSansCJKjp-Bold.otf") if os.path.exists(f)), None)
F = lambda s, b=False: ImageFont.truetype(FONTB if b else FONT, s, index=0)

PAD = "#66605b"                       # --fit の余白（Unity の背景に近い色）
STAFF_C, ROBOT_C = "#2a55c8", "#ffffff"   # 立体の色に合わせる（スタッフ青・ロボット白）
STAFF = [("staff_guide", "案内", ACC), ("staff_serve", "料理", GOOD), ("staff_call", "呼び出し", "#7a5cc7"),
         ("staff_pay", "会計", WARN), ("staff_clear", "片付け", "#8a6d3b"), ("staff_rescue", "ロボットの助け", BAD),
         ("staff_idle", "手すき", "#b8b5ab")]

def hm(t):
    t = int(t); h, m = t // 3600, t % 3600 // 60
    return f"{h}時間{m:02d}分" if h else f"{m}分"

def panel(row, rows, robots, t_from, t_to, title):
    im = Image.new("RGB", (PW, H), BG); d = ImageDraw.Draw(im)
    x0 = 40
    d.text((x0, 36), title, font=F(26), fill=QUIET)
    d.text((x0, 76), f"開店から {hm(row['t_s'])}", font=F(52, True), fill=INK)
    y = 170
    # スタッフ
    n = sum(int(row[k]) for k, _, _ in STAFF)
    d.text((x0, y), f"スタッフ {n}人 がしていること", font=F(28, True), fill=INK); y += 52
    for k, name, c in STAFF:
        v = int(row[k])
        d.text((x0, y), name, font=F(26), fill=INK if v else QUIET)
        for i in range(v):
            d.rounded_rectangle((x0 + 210 + i * 46, y + 4, x0 + 246 + i * 46, y + 38), 6, fill=STAFF_C)
        y += 46
    y += 20
    # ロボット
    rb = int(row["robots_busy"])
    # 下げ膳にも使う回（timeline.csv に robots_bussing の列がある回）だけ、動いている台のうち下げ膳の台を「下げ膳」と出す（2026-11-04・依頼91）
    bus = min(int(row.get("robots_bussing") or 0), rb)
    d.text((x0, y), f"ロボット {robots}台", font=F(28, True), fill=INK); y += 52
    for i in range(robots):
        busy = i < rb
        d.rounded_rectangle((x0 + i * 150, y, x0 + 136 + i * 150, y + 50), 10, fill=ROBOT_C if busy else BG, outline=INK if busy else LINE, width=3)
        d.text((x0 + 68 + i * 150, y + 25), ("下げ膳" if i >= rb - bus else "運んでいる") if busy else "待機", font=F(24, True), fill=INK if busy else QUIET, anchor="mm")
    if robots == 0:
        d.text((x0, y + 8), "入れていない", font=F(26), fill=QUIET)
    y += 86
    # 数字
    for k, name, c in [("waiting_groups", "入口で待つ組", BAD), ("seated_groups", "席にいる組", INK),
                       ("tables_dirty_untaken", "片付けを待つ卓", WARN)]:
        v = int(row[k])
        d.text((x0, y + 8), name, font=F(28), fill=INK)
        d.text((PW - 50, y), str(v), font=F(48, True), fill=c if v else QUIET, anchor="ra")
        y += 66
    # 入口で待つ組の一日
    y += 14; gh = 120; gx0, gx1 = x0, PW - 40
    d.text((x0, y), "入口で待つ組（営業の始めから終わり）", font=F(22), fill=QUIET); y += 36
    ts = [r["t_s"] for r in rows]; vs = [int(r["waiting_groups"]) for r in rows]
    vmax = max(max(vs), 1); tmax = ts[-1] or 1
    X = lambda t: gx0 + (gx1 - gx0) * t / tmax; Y = lambda v: y + gh - gh * v / vmax
    d.rectangle((X(t_from), y, X(t_to), y + gh), fill="#eeece4")
    d.line([(X(t), Y(v)) for t, v in zip(ts, vs)], fill=BAD, width=3)
    d.line((gx0, y + gh, gx1, y + gh), fill=LINE, width=2)
    cx = X(row["t_s"]); d.line((cx, y, cx, y + gh), fill=INK, width=3)
    return im

def legend(path):
    im = Image.new("RGBA", (560, 64), (250, 249, 245, 230)); d = ImageDraw.Draw(im); x = 20
    for c, name in [("#e8c520", "お客さん"), ("#2a55c8", "スタッフ"), ("#f2f2f2", "ロボット")]:
        d.ellipse((x, 18, x + 28, 46), fill=c, outline="#6b6a64", width=2); d.text((x + 38, 32), name, font=F(26), fill=INK, anchor="lm")
        x += 70 + 30 * len(name)
    im.save(path)

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("rec"); ap.add_argument("frames"); ap.add_argument("timeline"); ap.add_argument("out")
    ap.add_argument("--from", dest="t_from", type=float, default=0); ap.add_argument("--to", dest="t_to", type=float, default=None)
    ap.add_argument("--speed", type=float, default=1.0); ap.add_argument("--title", default="ServiceSim")
    ap.add_argument("--fit", action="store_true", help="録画を切らずに横幅に合わせて縮め、上下に余白を足す（字幕の入った寄りの部品用）")
    a = ap.parse_args()
    fr = [(int(r["frame"]), float(r["t_s"])) for r in csv.DictReader(open(a.frames))]
    rows = []
    for r in csv.DictReader(open(a.timeline)):
        r = dict(r); r["t_s"] = float(r["t_s"]); rows.append(r)
    robots = int(rows[0]["condition_id"].split("_r")[1].split("_")[0]) if "_r" in rows[0]["condition_id"] else 0
    t_to = a.t_to if a.t_to is not None else fr[-1][1]
    fps = 30
    f_from = next(f for f, t in fr if t >= a.t_from); f_to = max(f for f, t in fr if t <= t_to)
    v_from, v_dur = f_from / fps, (f_to - f_from) / fps
    tmp = pathlib.Path(tempfile.mkdtemp())
    # パネル：timeline の行ごと。その行が見える録画の長さ（速さで割る）だけ出す
    sel = [r for r in rows if a.t_from - 60 < r["t_s"] <= t_to]
    lst = []
    for i, r in enumerate(sel):
        t0 = max(r["t_s"], a.t_from); t1 = sel[i + 1]["t_s"] if i + 1 < len(sel) else t_to
        if t1 <= t0: continue
        dur = (t1 - t0) / 0.5 / fps / a.speed
        p = tmp / f"p{i:04d}.png"; panel(r, rows, robots, a.t_from, t_to, a.title).save(p)
        lst.append(f"file '{p}'\nduration {dur:.4f}\n")
    lst.append(f"file '{p}'\n")
    (tmp / "p.txt").write_text("".join(lst))
    legend(tmp / "lg.png")
    vf = (f"[0:v]trim=start={v_from}:duration={v_dur},setpts=(PTS-STARTPTS)/{a.speed},"
          + (f"scale={VW}:-2,pad={VW}:{H}:0:(oh-ih)/2:color={PAD}[v0];" if a.fit else f"scale=-2:{H},crop={VW}:{H}[v0];") +
          f"[2:v]format=rgba[lg];[v0][lg]overlay=32:32[v];"
          f"[1:v]fps={fps},setpts=PTS-STARTPTS[p];[v][p]hstack=inputs=2,format=yuv420p")
    subprocess.run(["ffmpeg", "-y", "-loglevel", "error", "-i", a.rec, "-f", "concat", "-safe", "0", "-i", str(tmp / "p.txt"), "-loop", "1", "-i", str(tmp / "lg.png"),
                    "-filter_complex", vf, "-t", f"{v_dur / a.speed:.3f}", "-r", str(fps),
                    "-c:v", "libx264", "-preset", "veryfast", "-crf", "22", a.out], check=True)
    print(a.out, f"{v_dur / a.speed:.1f}s")

if __name__ == "__main__":
    main()
````

#### focus_clips.py（寄りの字幕の時刻を直した版の全文）

````python
"""問題に寄る動画を作る（サービスロボット導入シミュレーション・2026-11-02）

カメラの目的を分ける（エイイチと決めた）
- 引き：全体の流れを見る（60°見下ろし・左30°／右30°の店全体）
- 寄り：問題が起きている所を見る（ロボットが動けなくなった・長く止まった所と時刻）

問題がどこでいつ起きるかは回してみないと分からないので、1回の回で引きを高解像度（3840×2160）で撮り、
その回の stops.csv から問題を拾って、引きの映像から切り出して寄りを作る（寄りのカメラを別に置かない）。

流れ
1. stops.csv の止まりのうち、長いもの（MIN_STOP 秒以上、または「動けなくなった」）を拾う
2. 同じ所（SAME_M 以内）で続けて起きた止まりを1つの「問題」にまとめ、止まっていた秒の合計で並べる
3. 上位 TOP 件それぞれについて：
   - 引き：問題が始まる少し前から、その場所に輪を付けて見せる（どこで起きたか）
   - 寄り：問題の場所を中心に 1280×720 で切り出す（何が起きたか）。左30°・右30°のうち、その場所が画面の真ん中に近い方を使う
4. 引き（全体の流れ）→ 問題ごとに［引きで場所 → 寄り］をつなぐ

使い方: python3 focus_clips.py <録画のフォルダ> <回のフォルダ> <出力フォルダ>
  要るもの：python3・numpy・Pillow・ffmpeg。問題の数は FOCUS_TOP（既定 3）、字は FOCUS_FONT、字幕の大きさは FOCUS_TEXT_SCALE（既定 1.0・サイト用は 1.5）で替えられる
  問題が1つもない回（30秒以上の止まりがない）は、引きだけの動画になる
  録画のフォルダ：{名前}.mp4・{名前}_frames.csv・{名前}_camera.json（wide_l30・wide_r30）
"""
import csv
import json
import os
import math
import subprocess
import sys
from pathlib import Path

import numpy as np
from PIL import Image, ImageDraw, ImageFont

MIN_STOP = 30.0      # これ以上の止まりを問題として拾う（秒・店の時刻）
SAME_M = 1.5         # この距離以内の止まりは同じ所
SAME_GAP = 120.0     # 前の止まりが終わってからこの秒以内なら同じ問題
TOP = int(os.environ.get("FOCUS_TOP", "3"))   # 動画にする問題の数
# 字幕の大きさの倍率（2026-11-03）。サイト（/series8）に載せる版はスマホの幅で字が小さすぎたので 1.5 で書き出す
TEXT_SCALE = float(os.environ.get("FOCUS_TEXT_SCALE", "1.0"))
CROP = (1280, 720)   # 寄りの切り出しの大きさ（3840×2160 の 1/3）
LEAD = 10.0          # 問題が始まる前から見せる秒（店の時刻）
TAIL = 6.0
MAX_FOCUS = 120.0    # 寄りの長さの上限（店の時刻）
WIDE_SEC = 3.0       # 問題ごとの「引きで場所」の長さ（動画の秒）
import os
# 字（Linux の Noto、Mac のヒラギノ）。見つかった最初のものを使う
FONT = next((f for f in (os.environ.get("FOCUS_FONT", ""),
                         "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc",
                         "/System/Library/Fonts/ヒラギノ角ゴシック W6.ttc",
                         "/System/Library/Fonts/Hiragino Sans GB.ttc",
                         "/Library/Fonts/Arial Unicode.ttf") if f and os.path.exists(f)), None)
CAMS = ("wide_l30", "wide_r30")


def load_cam(rec, name):
    J = json.load(open(next(rec.glob(f"*{name}_camera.json")), encoding="utf-8"))
    V = np.array(J["worldToCameraMatrix"], dtype=float).reshape(4, 4)
    P = np.array(J["projectionMatrix"], dtype=float).reshape(4, 4)
    W, H = J["width"], J["height"]
    mp4 = next(f for f in rec.glob(f"*{name}.mp4"))
    frames = [(int(r["frame"]), float(r["t_s"])) for r in csv.DictReader(open(next(rec.glob(f"*{name}_frames.csv"))))]

    def to_px(x, y):
        """店の座標 (x, y)（床）→ 画面の画素 (u, v)。Unity は x→X、y→Z、床の高さ Y=0"""
        c = P @ V @ np.array([x, 0.0, y, 1.0])
        nx, ny = c[0] / c[3], c[1] / c[3]
        return (nx + 1) / 2 * W, (1 - ny) / 2 * H

    return dict(name=name, mp4=mp4, W=W, H=H, frames=frames, to_px=to_px)


def t_to_frame(frames, t):
    return min(frames, key=lambda f: abs(f[1] - t))[0]


def episodes(run):
    rows = list(csv.DictReader(open(run / "stops.csv", encoding="utf-8")))
    ev = [r for r in rows if float(r["duration_s"]) >= MIN_STOP or r["resolved"] == "動けなくなった"]
    ev.sort(key=lambda r: float(r["t_s"]))
    eps = []
    for r in ev:
        t0, d = float(r["t_s"]), float(r["duration_s"])
        x, y = float(r["x"]), float(r["z"])
        for e in eps:
            if math.hypot(e["x"] - x, e["y"] - y) <= SAME_M and t0 - e["t1"] <= SAME_GAP:
                e["t1"] = max(e["t1"], t0 + d)
                e["total"] += d
                e["n"] += 1
                e["robots"].add(r["robot_id"])
                e["causes"][r["cause"]] = e["causes"].get(r["cause"], 0) + d
                e["stuck"] += r["resolved"] == "動けなくなった"
                break
        else:
            eps.append(dict(x=x, y=y, t0=t0, t1=t0 + d, total=d, n=1, robots={r["robot_id"]},
                            causes={r["cause"]: d}, stuck=int(r["resolved"] == "動けなくなった")))
    eps.sort(key=lambda e: -e["total"])
    return eps


def mmss(t):
    return f"{int(t // 60)}:{int(t % 60):02d}"


def hm(t):
    # 時刻は「開店から 2時間14分」の形（PANEL_VIDEO_FORMAT.md の決まり。1:54 や 134:14 とは書かない）。2026-11-04
    t = int(t); h, m = t // 3600, t % 3600 // 60
    return f"{h}時間{m:02d}分" if h else f"{m}分"


def caption(e):
    cause = max(e["causes"], key=e["causes"].get)
    what = {"もう1台のロボット": "ロボットどうしが道をふさぎ合って止まる",
            "人が立ち止まっていた": "人が立ち止まっていて、ロボットが止まる",
            "お客さんとすれ違った": "お客さんとすれ違えず、ロボットが止まる",
            "スタッフとすれ違った": "スタッフとすれ違えず、ロボットが止まる"}.get(cause, f"ロボットが止まる（{cause}）")
    return what, f"開店から {hm(e['t0'])}〜{hm(e['t1'])}・止まった合計 {int(e['total'])}秒（{e['n']}回）"


def overlay_png(path, W, H, title, sub, ring=None, ring_r=60):
    im = Image.new("RGBA", (W, H), (0, 0, 0, 0))
    d = ImageDraw.Draw(im)
    s0 = W / 1280          # 輪の大きさはこちら（字幕の倍率をかけない）
    s = s0 * TEXT_SCALE    # 字幕の字・余白・帯の高さ
    if FONT is None:
        raise SystemExit("日本語の字が見つからない。FOCUS_FONT に .ttc/.ttf の場所を入れて回す")
    f1, f2 = ImageFont.truetype(FONT, int(30 * s)), ImageFont.truetype(FONT, int(22 * s))
    pad = int(14 * s)
    tw = max(d.textlength(title, font=f1), d.textlength(sub, font=f2)) + 2 * pad
    d.rectangle([0, 0, tw, int(86 * s)], fill=(17, 17, 17, 210))
    d.text((pad, int(8 * s)), title, font=f1, fill=(245, 245, 240, 255))
    d.text((pad, int(50 * s)), sub, font=f2, fill=(220, 220, 214, 255))
    if ring:
        u, v = ring
        r = ring_r * s0
        d.ellipse([u - r, v - r, u + r, v + r], outline=(232, 89, 12, 255), width=max(3, int(6 * s0)))
    im.save(path)


def run_ff(args):
    subprocess.run(["ffmpeg", "-y", "-loglevel", "error", *args], check=True)


def clip(cam, f0, f1, out, crop=None, ov=None, speed=1.0):
    # 先頭から読まずに、始まりの少し手前へ飛んでから切る（2026-11-03。4K を頭から読むと1本に数分かかっていた）
    # 録画は 30 コマ/秒なので、コマ番号 f0 は f0/30 秒。-ss を入力の前に置いても、書き出し直すのでコマ単位で合う
    ss = f0 / 30
    vf = [f"trim=end_frame={f1 - f0}", "setpts=PTS-STARTPTS"]
    if speed != 1.0:
        vf.append(f"setpts={1 / speed}*PTS")
    if crop:
        cx, cy = crop
        vf.append(f"crop={CROP[0]}:{CROP[1]}:{cx}:{cy}")
    else:
        vf.append(f"scale={CROP[0]}:{CROP[1]}")
    chain = ",".join(vf)
    if ov:
        run_ff(["-ss", f"{ss:.4f}", "-i", str(cam["mp4"]), "-i", str(ov), "-filter_complex",
                f"[0:v]{chain}[b];[b][1:v]overlay=0:0,format=yuv420p,fps=30[v]", "-map", "[v]",
                "-c:v", "libx264", "-preset", "veryfast", "-crf", "20", str(out)])
    else:
        run_ff(["-ss", f"{ss:.4f}", "-i", str(cam["mp4"]), "-vf", chain + ",format=yuv420p,fps=30", "-c:v", "libx264", "-preset", "veryfast", "-crf", "20", str(out)])


def main():
    rec, run, out = map(Path, sys.argv[1:4])
    out.mkdir(parents=True, exist_ok=True)
    cams = {n: load_cam(rec, n) for n in CAMS}
    eps = episodes(run)
    json.dump([{**e, "robots": sorted(e["robots"])} for e in eps], open(out / "episodes.json", "w", encoding="utf-8"), ensure_ascii=False, indent=1)
    parts = []
    # 引き：全体の流れ（左30°・回の最初の問題の少し前から 8 秒）
    L = cams["wide_l30"]
    t_open = max(L["frames"][0][1], (min(e["t0"] for e in eps[:TOP]) if eps else L["frames"][0][1] + 900) - 120)
    f0 = t_to_frame(L["frames"], t_open)
    ov = out / "ov_open.png"
    overlay_png(ov, CROP[0], CROP[1], "引き：店全体の流れ", "60°見下ろし・左30°")
    clip(L, f0, f0 + 240, out / "p00_open.mp4", ov=ov)
    parts.append(out / "p00_open.mp4")
    for i, e in enumerate(eps[:TOP], 1):
        # その場所が画面の真ん中に近いカメラを使う
        best = min(cams.values(), key=lambda c: math.hypot(c["to_px"](e["x"], e["y"])[0] - c["W"] / 2, c["to_px"](e["x"], e["y"])[1] - c["H"] / 2))
        u, v = best["to_px"](e["x"], e["y"])
        what, sub = caption(e)
        # 引きで場所（輪を付ける）
        fs = t_to_frame(best["frames"], e["t0"] - LEAD)
        ov = out / f"ov_{i}_wide.png"
        k = CROP[0] / best["W"]
        overlay_png(ov, CROP[0], CROP[1], f"問題{i}：ここで起きる", "引き・" + ("左30°" if best["name"].endswith("l30") else "右30°"), ring=(u * k, v * k), ring_r=40)
        clip(best, fs, fs + int(WIDE_SEC * 30), out / f"p{i:02d}a_wide.mp4", ov=ov)
        # 寄り：問題の場所を中心に切り出す
        cx = int(min(max(u - CROP[0] / 2, 0), best["W"] - CROP[0]))
        cy = int(min(max(v - CROP[1] / 2, 0), best["H"] - CROP[1]))
        f0 = t_to_frame(best["frames"], e["t0"] - LEAD)
        f1 = t_to_frame(best["frames"], min(e["t1"] + TAIL, e["t0"] + MAX_FOCUS))
        ov = out / f"ov_{i}_focus.png"
        overlay_png(ov, CROP[0], CROP[1], f"寄り：{what}", sub, ring=(u - cx, v - cy), ring_r=70)
        clip(best, f0, f1, out / f"p{i:02d}b_focus.mp4", crop=(cx, cy), ov=ov, speed=0.5)
        parts += [out / f"p{i:02d}a_wide.mp4", out / f"p{i:02d}b_focus.mp4"]
    lst = out / "list.txt"
    lst.write_text("".join(f"file '{p.name}'\n" for p in parts))
    run_ff(["-f", "concat", "-safe", "0", "-i", str(lst), "-c", "copy", str(out / "focus_trial.mp4")])
    for i, e in enumerate(eps[:TOP], 1):
        print(i, caption(e), (round(e["x"], 1), round(e["y"], 1)))
    print("OK", out / "focus_trial.mp4")


if __name__ == "__main__":
    main()
````


## 作業ログ ― 依頼90・91：Unity の配膳ロボットに下げ膳を入れた

> 比較動画下げ膳いれる進めて

サイトの試算が正なので、先にサイトの側を整えました。試算にはもともと「下げ膳にも使う」という回し方があります。スタッフが片付けに向かうとき、空いているロボットがいれば一緒に卓へ行き、スタッフが皿を載せ終えるまで卓で待ち、洗い場へ運ぶ形です。空いているロボットがいなければ、人だけで下げます。

Unity が読む条件の表（public/sim/serving-robot-params.json）に、この下げ膳の条件を12個（6店 × ロボット1・2台、120〜131番）足し、決まりを meta.bus に書きました。今までの120条件は変えていません。試算の結果は v2.9 の results.json の同じ条件のものです。

#### export_params.py の差分（下げ膳の条件を足した所）

````diff
commit 41e9364cbddfdb8e9ea6748cb1da3e50852765e9
Author: Claude <noreply@anthropic.com>
Date:   Wed Nov 4 06:36:35 2026 +0900

    Unity の条件に下げ膳にも使う（mode bus）を12条件足す（120〜131番）
    
    配膳だけと配膳＋下げ膳の比較動画のため。6店 × 普通・真ん中の人数 × ロボット1・2台。
    試算の結果は v2.9 の results.json の同じ条件。前の120条件は変えていない。
    
    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01LevEXRqrYPEjm1w9jgQTcD

diff --git a/tools/serving_sim/export_params.py b/tools/serving_sim/export_params.py
index 724548c..832b453 100644
--- a/tools/serving_sim/export_params.py
+++ b/tools/serving_sim/export_params.py
@@ -6,7 +6,7 @@ Unity はこの JSON を読み、値を手で写さない（LOG359 のずれ9「
 使い方: python3 export_params.py results.json <出力先>   （出力先は p2m-site の public/sim/serving-robot-params.json。unity_rules は出力先の今の値を引き継ぐ）
 - common：店に共通の値。role が "unity_measures" の値は Unity で測ってサイトに戻すための仮の値なので、Unity は読まない
 - stores：Unity で回す店（fam_p1・fam_p5・fam_p2・fam_p3・fam_p4・fam_p0、2026-11-02 から大型店の large_p6・large_p7）の値。registers はレジの数（v2.8）
-- unity_conditions：Unity で回す条件（0〜17番は店ごとに混み具合が普通の3つ。18〜53番は2026-10-29に足した空いている・混んでいるの各3つ。54〜89番は2026-10-30に足したスタッフが少ない・多いの各3つ（混み具合は普通）。計90条件）と、同じ条件の試算の結果（40回の平均）。Unity の店はレジの内側に店員が1人だけなので、レジは1つ
+- unity_conditions：Unity で回す条件（0〜17番は店ごとに混み具合が普通の3つ。18〜53番は2026-10-29に足した空いている・混んでいるの各3つ。54〜89番は2026-10-30に足したスタッフが少ない・多いの各3つ（混み具合は普通）。計90条件。90〜119番は2026-11-02に足した大型店⑧⑨。120〜131番は2026-11-04に足した下げ膳にも使う条件）と、同じ条件の試算の結果（40回の平均）。Unity の店はレジの内側に店員が1人だけなので、レジは1つ
 """
 import json
 import sys
@@ -91,6 +91,17 @@ for k in UNITY_STORES_LARGE:
             r = rows[h.key(c)]
             conds.append({"condition": c, "site_result": {m: r[m] for m in r if m not in c}})
 
+# 2026-11-04 エイイチと決めた：配膳だけと配膳＋下げ膳の比較動画のため、下げ膳にも使う（mode "bus"）を Unity で回す。
+# 前の120条件（0〜119番）は並びも中身も変えず、後ろに足す。店ごとに 普通・真ん中の人数で ロボット1・2台（12条件・120〜131番）。
+# 下げ膳の回し方はサイトの試算と同じ（スタッフが片付けに向かうとき、空いているロボットがいれば一緒に卓へ。皿を載せ終えたら洗い場へ）
+for k in UNITY_STORES:
+    s = h.STORES[k]
+    for robots in (1, 2):
+        c = {"store": k, "staff": s["staff"][1], "robots": robots, "arrivals_per_h": s["arrivals"][1], "mode": "bus",
+             "trays": 3, "fragile_by": "any", "registers": UNITY_REGISTERS}
+        r = rows[h.key(c)]
+        conds.append({"condition": c, "site_result": {m: r[m] for m in r if m not in c}})
+
 D = {
     "meta": {
         "schema_version": "serving-robot-params/0.4",
````

依頼90 で Unity に下げ膳を入れると、120回のうち4回で店が止まりました。下げ膳のロボットは先に卓へ着き、スタッフが来るのを待ちます。この待ちに上限がなく、しかも助けの決まりが「卓で受け渡し中の台は動かさない」だったので、待っている台がほかのロボットやスタッフの道をふさぐと、だれも動かせませんでした。解けずに残った詰まりは53件で、配膳だけの同じ120回では1件です。

> どこで区切るつもり？

依頼91 を区切りにしました。待つのは2分まで（過ぎたら皿を載せずに待機場所へ戻り、その卓は人だけで下げる）、待っている台も助けで動かしてよい、の2つを入れ、120回を回して、結果がどうでも比較動画の素材を撮る。止めるのは瞬間移動が出たときと、同じ種で同じ結果にならなかったときだけです。2分は、料理を2分待ってもロボットが来なければスタッフが運ぶ、という前からの決まりにそろえました。

細い通路の卓には下げ膳のロボットを出さない、という案も Claude Code から出ましたが、入れていません。サイトの試算にない出し方を Unity だけで決めることになるためです。

- ねらい：下げ膳のロボットが卓で待ち続けて、店が止まるのをなくす
- 変わったこと：全員が帰らない回は120回中4回から1回。解けずに残った詰まりは53件から4件。上限で戻った回は14回、卓で待つ下げ膳の台を助けで動かしたのは166回。残った1回（④2台 種4）は料理の往復どうしの向かい合いで、下げ膳の台ではない
- 見込める効果：測った値では、下の表のとおり、歩く距離は12条件すべてで減った

配膳だけ（cs:76・base73）と下げ膳にも使う（cs:78・bus75）の、店・台数ごとの中央値です（種10個）。歩いた距離はスタッフ1人の km、卓が使えるまではお客さんが帰ってからの分、入店待ちは来てから席に着くまでの分です。

| 店・台数 | 歩いた距離 配膳だけ → 下げ膳も | 卓が使えるまで 配膳だけ → 下げ膳も | 入店待ち 配膳だけ → 下げ膳も |
|---|---|---|---|
| ③1台 | 2.72 → 2.62 | 4.97 → 5.10 | 3.47 → 3.47 |
| ③2台 | 2.54 → 2.35 | 4.05 → 6.05 | 2.72 → 3.95 |
| ⑦1台 | 2.74 → 2.62 | 6.47 → 6.59 | 3.87 → 3.87 |
| ⑦2台 | 2.55 → 2.36 | 4.49 → 8.06 | 3.87 → 4.65 |
| ④1台 | 2.37 → 2.17 | 19.72 → 19.66 | 11.02 → 11.39 |
| ④2台 | 2.66 → 2.25 | 28.61 → 30.62 | 18.66 → 16.70 |
| ⑤1台 | 3.22 → 3.10 | 10.21 → 10.30 | 6.99 → 6.98 |
| ⑤2台 | 2.87 → 2.66 | 10.45 → 9.84 | 6.12 → 5.83 |
| ⑥1台 | 2.58 → 2.47 | 11.73 → 11.40 | 5.19 → 4.92 |
| ⑥2台 | 2.37 → 2.14 | 12.05 → 11.87 | 4.54 → 4.54 |
| ②1台 | 1.53 → 1.33 | 3.49 → 3.01 | 1.60 → 1.62 |
| ②2台 | 1.55 → 1.19 | 4.03 → 3.90 | 1.65 → 1.66 |

同じ条件の試算（v2.9）では、卓が使えるまでの時間は下げ膳にも使うとわずかに縮みます（③2台で 2.14 → 2.00分）。Unity では、③⑦のロボット2台で大きく延びました。③⑦は席を詰めた店で、細い通路が多い店です。下げ膳のロボットが卓に着いてスタッフを待つあいだ、通路が1本ふさがり、ほかのロボットとスタッフが回り道をするか待つことになります。試算はこの通路の取り合いを数えていないので、ここが Unity と試算の差です。

#### 依頼90 の依頼文（全文）

````markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 480
---
# 依頼90：下げ膳にも使う（mode bus）を Unity に入れ、120回で確かめ、比較動画の素材を撮る

エイイチの指示（2026-11-04）：配膳だけと配膳＋下げ膳の比較動画を作る。そのために Unity に下げ膳を入れる。
固めた版は cs:76（瞬間移動0・同じ種で同じ結果）。この版の配膳だけ（mode serve）の動きは変えない。
サイトが正：下げ膳の回し方はサイトの試算と同じにする。サイトの public/sim/serving-robot-params.json に、下げ膳の条件 120〜131番（6店 × 普通・真ん中の人数 × ロボット1・2台・mode "bus"）と、meta.bus に決まりを足した（Claude・2026-11-04）。Unity はこの JSON を読み、値を手で写さない。

## 下げ膳の決まり（サイトの試算 v2.4 から。meta.bus と同じ）
- スタッフが片付けに向かうとき、空いているロボットがいれば一緒に卓へ向かう
- スタッフは卓で皿をまとめ（clear_s）、ロボットが着いたら皿を載せ（load_s）、卓を拭いて（wipe_s）戻る
- ロボットはスタッフが皿を載せ終えるまで卓で待ち、載せ終えたら洗い場へ行って皿を下ろし、待機場所へ戻る
- 空いているロボットがいなければ、人だけで下げる（今までと同じ）
- 仕事の優先順はロボットの救出 → 配膳・案内・会計・呼び出し → 下げ膳。料理はロボット最優先（2分でスタッフ）は今までどおり
- 値（clear_s・load_s・wipe_s など）は params の common から読む。洗い場の位置は店の形（public/sim/layouts/）から。洗い場でロボットが止まる点が店の形に無ければ、受け渡し口の近くの洗い場側に、店の形から決まる規則で置き、報告に書く（店の形の JSON は変えない）

## 始める前に確かめること（違えば手を止めて報告）
Unity エディタ・night_runner／rec_runner が動いていない、KIOXIA がマウント済み、unity_ledger_v1.lock がない、保留 0、作業場所が cs:76。サイトの params を git pull して 132 条件あること。台帳は退避してから回す。台帳は追記だけ。

## やること
1. 下げ膳を入れる（条件の mode が bus のときだけ働く。serve のときの動きは1行も変わらないこと）
   - 見張り（10秒で0.5m）・助け・瞬間移動なしの作りは、下げ膳の往復にも同じように効かせる。卓でスタッフを待っている間・洗い場で皿を下ろしている間は「わざと待っている間」として見張らない
   - パネルの数字のため timeline.csv に robots_bussing（下げ膳を運んでいる台数）を足す。staff_clear は今のまま
2. check-in し、画面なしの実行ファイルを作り直す（保留 0）
3. 確かめ（画面なし）
   - serve が変わっていないこと：⑦ fam_p5・2台・種7 を新しい版で回し、base73（cs:76）の同じ回と記録が1行も違わないこと
   - bus の同じ種で同じ結果：③ fam_p1・2台・bus・種7 を2回、記録が1行も違わないこと
   - 120回：条件 120〜131 × 種0〜9（同時4本・label bus74）。base73 の同じ店・台数の serve と並べる：瞬間移動、解けずに残った詰まり、全員が帰らなかった回、入店待ち・料理の待ち・客が帰ってから卓が使えるまで（turn）・スタッフ1人の歩いた距離・ロボットが下げ膳を運んだ割合の中央値、試算（serve→bus）との向き
4. 比較動画の素材を撮る（3 が合格のときだけ）
   - ③ fam_p1・2台・種7 を serve と bus で1回ずつ。カメラ・置き方・字幕などは依頼87 と同じ（wide_l30・wide_r30・4K・回の最初から終わりまで・frames.csv・timeline.csv）。置き場所 rec_compare_20261104/{serve|bus}/
   - それぞれ make_panel_video.py で通しのパネル付き動画を作る（依頼87 の whole と同じ作り方、出力は rec_compare_20261104/{serve|bus}/panel/）。2本を並べた比較動画は Claude が作る

## 変えないもの
serve のときの動き・決まり・数字。ロボットの速さ・物理の設定・譲る順番・見張りの 10秒・0.5m・30秒・60秒の線・センサー 0.6m・瞬間移動をなくした作り・店の形・台帳の列と今までの行。

## 止める線
瞬間移動が1回でも出たら、または serve の同じ回の記録が base73 と違ったら止めて報告する。

## 報告
claude_code_reports/20261104_bus90.txt に：変えたファイルと cs・build_id、洗い場の止まる点の決め方、2つの一致の確かめ、120回の表（serve と並べる）と向き、残った詰まりの中身と場所、撮った素材の場所と長さ。
**報告の最後の1行は必ず次のどれか**：「判定：合格」／「判定：止めた（決めてほしいことあり）」／「判定：失敗」
````

#### 依頼90 の Claude Code の報告（20261104_bus90.txt・全文）

````text
====================================================================
依頼90：下げ膳にも使う（mode bus）を Unity に入れ、120回で確かめ、比較動画の素材を撮る
2026-11-04 07:00〜08:45　作業場所 cs:76 → cs:77　build_id cs77_20261104_0746（画面なし・保留 0）
====================================================================

結論
  ・下げ膳を入れた（cs:77）。serve の回は base73 と記録が一致、bus の同じ種の2回も一致、120回で瞬間移動 0・1コマの跳び 0
  ・しかし 120 回のうち 4 回（③2台 種2・④2台 種4・④2台 種9・⑥2台 種4）で店が止まり、全員が帰らなかった
    （回の上限 720 分まで回った）。解けずに残った詰まり 53 件（serve の同じ 120 回は 1 件）
  ・止まった元は、下げ膳で卓に着いたロボットがスタッフの来るのを時間の上限なく待つこと。助けの決まりは
    「卓で受け渡し中の台は動かさない」なので、その台がもう1台のロボットやスタッフの道をふさぐと解けない
  ・直すには決まりを足す必要があり、それはエイイチが決めることなので、ここで止めた。比較動画の素材（4）は撮っていない
    （録画の用意だけした。下の 6 章）

--------------------------------------------------------------------
0. 始める前の確かめ（どれも依頼どおり）
--------------------------------------------------------------------
  Unity エディタ・night_runner・rec_runner：動いていない（Unity Hub だけ）／KIOXIA：マウント済み／unity_ledger_v1.lock：無し／
  保留 0／作業場所 cs:76 - head
  サイトの params：手元に p2m-site の clone が無かったので、git pull のかわりに gh api で GitHub の main（31f3d3c。params を変えたコミットは
    41e9364「Unity の条件に下げ膳にも使う（mode bus）を12条件足す（120〜131番）」）から取った。132 条件・meta.bus あり。
    https://pixelstomotors.com/sim/serving-robot-params.json と md5 が同じ（c07e6c256afc1659a733d3562fa28f7c）
    前の写し（cs:76）との違いは meta.bus と 120〜131 番だけ（0〜119 番・common・unity_rules・stores は同じ）。店の形の md5 も同じ
  台帳を archive/unity_ledger_v1_pre_bus90_20261104/ に退避（2681 行・md5 c25f3f880430ef92cb70dc2d141aa803）

--------------------------------------------------------------------
1. 入れたこと（cs:77）
--------------------------------------------------------------------
  サイトの決まり（meta.bus・試算 v2.4 の bus()）と同じにした。条件の mode が bus の回だけ働く
  ・スタッフが片付けを仕事板から取ったとき、空いているロボットがいれば一緒に卓へ向かわせる。
    空いている＝往復していない（待機・往復おわり）・押されていない・下げ膳中でない・受け渡し口に積める料理が無い
    （料理はロボット最優先。試算でも料理を待つロボットの頼みがあればロボットは空いていない）。いなければ今までどおり人だけ
  ・スタッフ：卓で clear_s → ロボットが着くのを待つ → load_s で載せる → wipe_s。待つ・載せる・拭くは歩かずその場で、あきらめ・交代はしない
  ・ロボット：待機場所からそのまま卓へ（積む料理が無いので受け渡し口には寄らない）→ 卓で載せ終えるまで待つ（Dwell）→
    洗い場へ → load_s で下ろす（Dwell）→ 待機場所へ戻る（待機場所へ戻るが入の回。道が引けなければそこで往復を終え、今までどおり下がる）
  ・値は params から：clear_s 40・wipe_s 40・load_s 15（common）。下ろす時間は load_s を使った
    （試算のコードでは「15」と数字で書いてある。値は同じ）
  ・見張り（10秒で0.5m）・助け・瞬間移動なしは料理の往復と同じ作りのまま。卓で待つ・洗い場で下ろすは Dwell なので見張らない。
    待ったあと走り出すときは見張りを始め直す
  ・仕事の優先順（救出0 → 配膳・案内・会計・呼び出し1 → 片付け2）・料理は2分でスタッフ、は変えていない

  試しの回（/tmp。台帳に書いていない）で動けなくなったので、次の3つを足した（どれも bus の回だけ働く。決めてほしいこと 2）
   a. 卓で待っている下げ膳の台は、人の「細い通路にロボットがいたら入口で待つ」の相手にしない
      （待つと、台はスタッフを待ち、スタッフは台を待つ。試し ④2台 種1 で回の上限まで止まった）
   b. 片付けのスタッフがもう卓にいれば、台はそのスタッフから 1.2 m 以内で卓に着いたとみる
      （1.2 m＝台の半径 0.25＋前のセンサー 0.6＋人の半径 0.2＋余裕 0.15。スタッフは卓の止まる点に立っているので、台はセンサーで
       0.6 m 手前に止まり、スタッフは止まっている台には譲らない。試し ②2台 種8 で卓を強引に空ける 600 秒まで待った）。
      同じように、スタッフも卓で待つ自分の台の 0.85 m 以内まで来たら着いたとみる
   c. 卓で止まって待っている自分の台だけは、片付けのスタッフがよけない（台が動いているあいだは今までどおり譲る）
  記録（bus の回だけ。serve の回は今までと同じファイル・同じ列）
   ・timeline.csv のいちばん後ろに robots_bussing（下げ膳をしている台数。卓へ向かう〜待機場所に戻るまで）。staff_clear は今のまま
   ・bus_runs.csv（下げ膳1回ずつ：向かった・卓に着いた・載せ終えた・洗い場に着いた・下ろした・終わった時刻、スタッフのそばで着いたか）
   ・bus_summary.json（片付けの数・ロボットが運んだ数・人だけ・ロボットが下げ膳を運んだ割合＝試算の robot_bus_share と同じ式）
   ・trips.csv には下げ膳の往復も皿 0 の行で入る（台帳の trips の数にも入る）
  名前：bus の条件は fam_p1_s4_r2_a42_bus のように _bus を付けた（serve と名前がぶつかるため）。出力フォルダも最後に _bus。
    tools/night_runner.py・make_queue.py も同じに直し、make_queue に --mode serve|bus（既定 serve）を足した。
    serve の並べ方は前と同じ（base73 の 180 回の queue と、作り直した queue が1字も違わないことを確かめた）

  洗い場の止まる点の決め方
   店の形（public/sim/layouts/unity/*.json）の places に DishReturn がある（6店とも）。その点はロボット用の点として読まれていて、
   店の形の決まり（meta.rules）に「下げ膳の返却口は受け渡し口と同じ点（試算の dish_extra_m=0 と同じ前提）」とある。
   店の形に点があるので、新しくは置かず、その点（＝受け渡し口の点。③ (15.3, 5.95) など）を使った。店の形の JSON は変えていない

--------------------------------------------------------------------
2. 変えたファイル・版
--------------------------------------------------------------------
  cs:77：Service/ServiceOps.cs・Service/ServiceSpec.cs・Robot/ServingRobotController.cs・People/StaffAgent.cs・People/PersonRobotYield.cs・
         Experiment/ExperimentRunner.cs・Experiment/HeadlessRun.cs・Experiment/SimParams.cs・Experiment/SiteValues.cs・
         Experiment/TimelineLogger.cs・Experiment/serving-robot-params.json（サイトの写しに替えた）・tools/night_runner.py・tools/make_queue.py
  実行ファイル：Builds/headless　build_id cs77_20261104_0746・unity_cs ServiceSim/cs:77・pending_changes 空・error CS 0
  録画用：Builds/rec19_bus90（Builds/headless の写し。md5 291677dfbc64f53edd3e59476d1cc7a8）
  params の控え：unity/site_copy_9b8dae7ebf8c_bus90/（params・README.txt）
  （check-in の前に /tmp/req90/try1〜try5 に試しのビルドを作り、書き先を /tmp に向けて回した。その一時の直しと調べ用の記録は
   check-in の前に外した）

--------------------------------------------------------------------
3. 2つの一致の確かめ（cs:77）
--------------------------------------------------------------------
  ・serve が変わっていない：⑦ fam_p5・2台・種7（det90s）と base73（cs:76）の同じ回
    contacts・dishes・give_ups・groups・nowarp_jams・passes・people_jams・requeues・rescues・robot_track・stops・timeline・yields は1行も違わない。
    trips.csv は plan_ms_max の列だけ、summary.json・conditions.json は written_at だけ、run_info.json は版・回の名前・時刻・実時間の欄と
    plan_ms_max_per_trip（道を引くのにかかった実時間）だけ違う。→ 一致（依頼86 と同じ扱い）
  ・bus の同じ種で同じ結果：③ fam_p1・2台・bus・種7 を2回（det90a・det90b）。上の13ファイル・bus_runs.csv・bus_summary.json・
    summary.json・conditions.json が一致。違うのは run_info.json の回の名前・時刻・実時間・plan_ms_max_per_trip と trips.csv の plan_ms_max だけ → 一致

--------------------------------------------------------------------
4. 120回（label bus74・同時4本・条件 120〜131 × 種0〜9）
--------------------------------------------------------------------
  120 回とも completed（やり直し 0）。実時間 1〜数分。07:49〜08:34。瞬間移動の止める線には当たっていない
  記録：night/20261104_bus74_cs77/（queue・runner_log・judge.md・agg90.py・agg90_out.txt・cmp.py・watch90.py・watch_log.txt）

全体（同じ店・台数・種どうし）	serve（base73・cs:76）	bus（bus74・cs:77）
回の数	120	120
瞬間移動	0	0
1コマの跳び	0	0
解けずに残った詰まり（件）	1	53
同（回）	1	4
全員が帰ったあとに始まった詰まり（件）	0	0
全員が帰らなかった回	[]	[('③', 2, 2), ('④', 2, 4), ('④', 2, 9), ('⑥', 2, 4)]
詰まり（回）	2215	2565
詰まり（秒）	133086	1567741
卓を強引に空けた	32	30
助け	2243	2674

  下げ膳の中身（120 回の合計）：片付け 8316・ロボットが運んだ 2496・人だけ 5820・ロボットが向かった 2514・載せる前に取りやめ 10・
    スタッフのそばで卓に着いたとみた 1485

店・台数ごと（種 0〜9 の中央値。分・km・割合。向き＝serve→bus の増減、＋は増える）
店 台数	項目	Unity serve→bus（向き）	試算 serve→bus（向き）	合う？
③1台	入店待ち	3.47→3.47（＝）	1.68→1.72（＋）	逆
③1台	料理の待ち	2.45→2.50（＋）	1.97→2.03（＋）	合う
③1台	卓が使えるまで(turn)	4.97→5.11（＋）	2.27→2.27（－）	逆
③1台	スタッフ1人の歩いた距離km	2.72→2.63（－）	1.88→1.86（－）	合う
③1台	ロボットが下げ膳を運んだ割合	0.150	試算 0.165	（記録）
③2台	入店待ち	2.72→3.61（＋）	1.13→2.22（＋）	合う
③2台	料理の待ち	1.71→1.82（＋）	0.96→1.08（＋）	合う
③2台	卓が使えるまで(turn)	4.05→5.58（＋）	2.14→2.00（－）	逆
③2台	スタッフ1人の歩いた距離km	2.54→2.35（－）	1.61→1.45（－）	合う
③2台	ロボットが下げ膳を運んだ割合	0.354	試算 0.442	（記録）
⑦1台	入店待ち	3.87→3.87（＝）	1.58→1.53（－）	逆
⑦1台	料理の待ち	2.51→2.51（＋）	2.01→2.04（＋）	合う
⑦1台	卓が使えるまで(turn)	6.47→6.59（＋）	2.31→2.27（－）	逆
⑦1台	スタッフ1人の歩いた距離km	2.74→2.63（－）	1.97→1.90（－）	合う
⑦1台	ロボットが下げ膳を運んだ割合	0.145	試算 0.166	（記録）
⑦2台	入店待ち	3.87→5.07（＋）	1.60→1.70（＋）	合う
⑦2台	料理の待ち	1.52→1.83（＋）	1.01→1.10（＋）	合う
⑦2台	卓が使えるまで(turn)	4.49→6.79（＋）	2.19→2.04（－）	逆
⑦2台	スタッフ1人の歩いた距離km	2.55→2.37（－）	1.69→1.47（－）	合う
⑦2台	ロボットが下げ膳を運んだ割合	0.386	試算 0.443	（記録）
④1台	入店待ち	11.02→11.38（＋）	4.81→4.85（＋）	合う
④1台	料理の待ち	1.79→1.95（＋）	1.29→1.38（＋）	合う
④1台	卓が使えるまで(turn)	19.72→19.41（－）	9.51→9.43（－）	合う
④1台	スタッフ1人の歩いた距離km	2.37→2.17（－）	1.75→1.64（－）	合う
④1台	ロボットが下げ膳を運んだ割合	0.298	試算 0.274	（記録）
④2台	入店待ち	18.66→16.70（－）	5.57→3.86（－）	合う
④2台	料理の待ち	1.98→3.03（＋）	0.47→0.57（＋）	合う
④2台	卓が使えるまで(turn)	28.61→31.51（＋）	9.88→8.57（－）	逆
④2台	スタッフ1人の歩いた距離km	2.66→2.20（－）	1.75→1.37（－）	合う
④2台	ロボットが下げ膳を運んだ割合	0.550	試算 0.710	（記録）
⑤1台	入店待ち	6.99→6.98（－）	3.16→3.38（＋）	逆
⑤1台	料理の待ち	2.63→2.69（＋）	2.28→2.32（＋）	合う
⑤1台	卓が使えるまで(turn)	10.21→10.83（＋）	3.39→3.40（＋）	合う
⑤1台	スタッフ1人の歩いた距離km	3.22→3.10（－）	2.59→2.52（－）	合う
⑤1台	ロボットが下げ膳を運んだ割合	0.121	試算 0.145	（記録）
⑤2台	入店待ち	6.12→5.83（－）	2.37→2.78（＋）	逆
⑤2台	料理の待ち	1.71→2.06（＋）	1.27→1.34（＋）	合う
⑤2台	卓が使えるまで(turn)	10.45→9.86（－）	2.41→2.25（－）	合う
⑤2台	スタッフ1人の歩いた距離km	2.87→2.62（－）	2.12→1.91（－）	合う
⑤2台	ロボットが下げ膳を運んだ割合	0.353	試算 0.392	（記録）
⑥1台	入店待ち	5.19→4.92（－）	3.68→4.01（＋）	逆
⑥1台	料理の待ち	2.03→2.09（＋）	2.01→2.03（＋）	合う
⑥1台	卓が使えるまで(turn)	11.73→11.40（－）	6.61→6.57（－）	合う
⑥1台	スタッフ1人の歩いた距離km	2.58→2.47（－）	2.18→2.09（－）	合う
⑥1台	ロボットが下げ膳を運んだ割合	0.172	試算 0.164	（記録）
⑥2台	入店待ち	4.54→4.54（－）	2.11→1.77（－）	合う
⑥2台	料理の待ち	1.05→1.32（＋）	0.82→0.92（＋）	合う
⑥2台	卓が使えるまで(turn)	12.05→10.42（－）	5.27→4.74（－）	合う
⑥2台	スタッフ1人の歩いた距離km	2.37→2.14（－）	1.91→1.64（－）	合う
⑥2台	ロボットが下げ膳を運んだ割合	0.400	試算 0.482	（記録）
②1台	入店待ち	1.60→1.62（＋）	1.79→2.47（＋）	合う
②1台	料理の待ち	1.02→1.13（＋）	0.91→1.04（＋）	合う
②1台	卓が使えるまで(turn)	3.49→3.01（－）	3.06→3.02（－）	合う
②1台	スタッフ1人の歩いた距離km	1.53→1.33（－）	1.16→1.09（－）	合う
②1台	ロボットが下げ膳を運んだ割合	0.403	試算 0.399	（記録）
②2台	入店待ち	1.65→1.66（＋）	1.30→2.12（＋）	合う
②2台	料理の待ち	0.61→0.94（＋）	0.40→0.48（＋）	合う
②2台	卓が使えるまで(turn)	4.03→3.80（－）	2.80→2.66（－）	合う
②2台	スタッフ1人の歩いた距離km	1.55→1.21（－）	1.11→0.91（－）	合う
②2台	ロボットが下げ膳を運んだ割合	0.690	試算 0.818	（記録）
向き：合う 38・逆 10（入店待ち・料理の待ち・turn・歩いた距離 × 12）
  （逆の 10 本のうち 6 本は turn：試算では bus で減るか横ばいだが、Unity は ③⑦ の 1・2台と ④2台で増えた。4 本は入店待ちで、
   Unity は ③⑦1台・⑤⑥1台でほぼ横ばいか減り、試算はわずかに増える。差の小さいものが多い）
  ロボットが下げ膳を運んだ割合は 12 本とも試算より低め〜同じ（例 ③2台 0.354／試算 0.442、②2台 0.690／0.818）

  夜の判定（judge.md）の「回の失敗」7 件：全員が帰っていない 4 件（下の 5 章）と、「ロボットが1コマで 0.05 m 超え」3 件
   （②2台 種3・④1台 種6・④2台 種7。どれも連れて戻した回で、瞬間移動 0・1コマの跳び 0。base73b で書いたのと同じ、連れて戻す速さ
    1.0 m/秒 × 0.05 秒がちょうど 0.05 m になるため）

--------------------------------------------------------------------
5. 残った詰まりの中身と場所（止まった 4 回）
--------------------------------------------------------------------
  ・③2台 種2：2号機が下げ膳で卓8 (1.91, 10.73)（細い通路 A01）に着いて待っているところへ、1号機が同じ通路の卓4 へ向かって (1.95, 9.64) で
    向かい合って止まった。1号機は 4745 秒ごろに卓22・6・4 を回る往復で出ていて、2号機の下げ膳（4784 秒）はそのあと同じ通路へ出した
    （料理の往復には「同じ通路に2台を集めない」があるが、下げ膳を出すときには見ていない）。片付けのスタッフは2台のあいだ (1.89, 10.24) で
    譲ったまま卓に着けず、交代をくり返した。その後スタッフの料理・案内・呼び出し・会計が受け渡し口 (15.3, 6.0) などで止まり、詰まり 33 件
  ・⑥2台 種4：2号機が下げ膳で卓5 (2.17, 5.22) で待っているところへ、皿を載せた1号機が洗い場へ戻る途中 (2.27, 5.88) で止まった（0.67 m）。
    助けは卓で待つ台を動かさないので解けず、詰まり 12 件
  ・④2台 種9：1号機が下げ膳で卓21 (9.80, 4.40) で待ち、2号機が受け渡し口へ戻る途中 (9.29, 4.99) で止まった。受け渡し口の前の料理 (10.1, 4.75) の
    詰まり 5 件
  ・④2台 種4：2台が (3.51, 2.39) と (4.42, 2.34) で向かい合って止まった（どちらも料理の往復で、下げ膳の台ではない）。呼び出し・料理の詰まりと合わせて 4 件。
    serve（base73）の同じ回は全員が帰っている
  serve の同じ 120 回で残った詰まりは 1 件（⑤2台 種7・スタッフ片付け (5.68, 13.13)。base73b で書いたもの）

--------------------------------------------------------------------
6. 比較動画の素材
--------------------------------------------------------------------
  3 が合格でないので撮っていない。用意だけした：
   ・録画用の実行ファイル Builds/rec19_bus90（cs:77。-ssRecord・-ssRecCam・-ssRecHidePaths・-ssMaxWallMin が入っていることを確かめた）
   ・night/20261104_rec90/rec_runner.py（依頼87 の写しに説明を足しただけ）と queue_src.json（③2台 種7 の serve と bus の2回）
  撮るときは依頼87 と同じ --oblique --hide-paths --max-wall-min 80 --parallel 2 --no-retry --limit-min 120 で回し、
  rec_compare_20261104/{serve|bus}/ に写して make_panel_video.py で通しのパネル付きを作る

--------------------------------------------------------------------
7. 台帳
--------------------------------------------------------------------
  2681 行 → 2804 行（追記 123 行だけ：確かめ 3・120 回。どれも completed・unity_cs ServiceSim/cs:77・mode は serve 1／bus 122）
  先頭 2681 行の md5 は c25f3f880430ef92cb70dc2d141aa803（退避と同じ）。終わったあとの md5 8beaf91f429e049ce10152bd5ebf6946。鍵ファイルは残っていない

--------------------------------------------------------------------
決めてほしいこと
--------------------------------------------------------------------
  1. 下げ膳で卓に着いたロボットがふさぎ続けるのをどう解くか（どれも決まりを足すことになる）。たとえば
     (ア) 下げ膳を出すときも「同じ通路に2台を集めない」を使う（ほかの台が向かっている・いる細い通路の卓なら、ロボットは出さず人だけで下げる）。
         ③2台 種2 はこれで起きなかったはず
     (イ) 卓で待つ下げ膳の台は、助けで動かしてよい（今は「卓で受け渡し中の台は動かさない」。受け渡しは 25 秒で終わるが、下げ膳の待ちは上限がない）
     (ウ) 下げ膳の台が卓で待つ時間に上限を置く（過ぎたら皿を載せずに戻り、人だけで下げる）。サイトの試算には上限がない
     ⑥2台 種4・④2台 種9 は (イ) か (ウ) が要る。④2台 種4 は下げ膳の台ではない向かい合いで、元は調べきれていない
  2. 試しで足した a〜c（1 章）でよいか。どれも bus の回だけで、serve は変わらないことを確かめてある
  3. 比較動画の素材は、1 を決めて直し、120 回で全員が帰ることを確かめてから撮るのでよいか（用意は 6 章）
  4. 動画の題は依頼87 と同じ「③ 標準ファミレス・ロボット2台」のままでよいか（serve と bus で同じ題になる）

判定：止めた（決めてほしいことあり）
````

#### 依頼91 の依頼文（全文）

````markdown
---
作業フォルダ: /Users/shimazueiichi/Robotics_UX/ServiceSim
上限時間: 480
---
# 依頼91：下げ膳で卓に着いた台のふさぎを直し、120回を回し、比較動画の素材を撮る（ここで区切る）

エイイチと決めた区切り（2026-11-04）：依頼91 が配膳ロボットのベースの最後の直し。結果がどうでも素材を撮って終える。残った詰まりや試算とのずれは記録だけにし、あとで直す。
依頼90 の報告：claude_code_reports/20261104_bus90.txt（判定：止めた）。今の作り cs:77。

依頼90 の「決めてほしいこと」への答え（エイイチ了承）：
- 1：(イ) と (ウ) を入れる。(ア)（細い通路の卓には下げ膳のロボットを出さない）は入れない（サイトの試算にない出し方なので）
  (イ) 卓でスタッフを待っている下げ膳の台は、助けで動かしてよい（料理の受け渡し中の台は今までどおり動かさない）
  (ウ) 下げ膳の台が卓でスタッフを待つ時間の上限を 120 秒にする（料理の「2分でスタッフ」と同じ考え方）。過ぎたら皿を載せずに待機場所へ戻り、その卓は人だけで下げる。上限で戻った回数を数える
- 2：試しで足した a〜c はこのままでよい
- 3：素材は 1 を直してから撮る。ただし区切りに従い、120 回で全員が帰らない回が残っても止めずに撮る
- 4：題は2本を分ける：「③ 標準ファミレス・ロボット2台・配膳だけ」「③ 標準ファミレス・ロボット2台・配膳＋下げ膳」

## 始める前に確かめること（違えば手を止めて報告）
Unity エディタ・night_runner／rec_runner が動いていない、KIOXIA がマウント済み、unity_ledger_v1.lock がない、保留 0、作業場所が cs:77。台帳は退避してから回す。台帳は追記だけ。

## やること
1. (イ)(ウ) を入れる（bus の回だけ働く。serve の動きは1行も変えない）。check-in し、画面なしの実行ファイルを作り直す（保留 0）
2. 確かめ（画面なし）
   - serve：⑦ fam_p5・2台・種7 が base73（cs:76）の同じ回と記録が1行も違わないこと
   - bus：③ fam_p1・2台・bus・種7 を2回、記録が1行も違わないこと
   - 120 回：条件 120〜131 × 種0〜9（同時4本・label bus75）。依頼90（bus74）・base73（serve）と並べる：瞬間移動、解けずに残った詰まり、全員が帰らなかった回、上限で戻った回数、助けの回数、入店待ち・料理の待ち・卓が使えるまで（turn）・スタッフ1人の歩いた距離・ロボットが下げ膳を運んだ割合の中央値、試算（serve→bus）との向き
3. 比較動画の素材を撮る（止める線に当たらなければ、120 回の結果に関わらず撮る）
   - ③ fam_p1・2台・種7 を serve と bus で1回ずつ。依頼90 で用意した録画の手順（6 章）で。カメラ・置き方は依頼87 と同じ。置き場所 rec_compare_20261104/{serve|bus}/。録画した回が全員帰ったかを報告に書く
   - それぞれ make_panel_video.py で通しのパネル付き動画を作る（依頼87 の whole と同じ作り方。出力 rec_compare_20261104/{serve|bus}/panel/。題は上の 4）。パネルのロボットの欄に「下げ膳」の状態が出るなら、それも確かめる（make_panel_video.py の形を変えたら差分を報告に）
   - 2本を並べた比較動画は Claude が作る

## 止める線
瞬間移動が1回でも出たとき、serve の記録が base73 と違ったとき、bus の同じ種の2回が違ったときだけ止めて報告する。

## 報告
claude_code_reports/20261104_bus91.txt に：変えたファイルと cs・build_id、確かめ、120 回の表（bus74・serve と並べる）と向き、残った詰まりの中身と場所、撮った素材の場所と長さ・全員帰ったか。
**報告の最後の1行は必ず次のどれか**：「判定：合格」／「判定：止めた（決めてほしいことあり）」／「判定：失敗」
````

#### 依頼91 の Claude Code の報告（20261104_bus91.txt・全文）

````text
====================================================================
依頼91：下げ膳で卓に着いた台のふさぎを直し、120回を回し、比較動画の素材を撮る（ここで区切る）
2026-11-04 09:39〜12:20　作業場所 cs:77 → cs:78　build_id cs78_20261104_1011（画面なし・保留 0）
====================================================================

結論
  ・(イ) と (ウ) を入れた（cs:78。bus の回だけ働く）。serve の回は base73 と記録が一致、bus の同じ種の2回も一致
  ・120 回（bus75）：瞬間移動 0・1コマの跳び 0。全員が帰らなかった回は 4 回 → 1 回（④2台 種4）。
    解けずに残った詰まりは 53 件 → 4 件（どれも ④2台 種4）。上限で戻った 14 回・卓で待つ下げ膳の台を動かす助け 166 回
  ・④2台 種4 は、料理の往復の2台が向かい合って止まったもの（下げ膳の台ではない。依頼90 と同じ場所）。区切りに従い記録だけにした
  ・比較動画の素材を撮った（③2台 種7 の serve と bus。どちらも全員帰った）。通しのパネル付き動画も2本作った（どちらも 10.5 倍）
  ・止める線（瞬間移動・serve が base73 と違う・bus の同じ種の2回が違う）には当たっていない

--------------------------------------------------------------------
0. 始める前の確かめ（どれも依頼どおり）
--------------------------------------------------------------------
  Unity エディタ・night_runner・rec_runner：動いていない（Unity Hub だけ）／KIOXIA：マウント済み／unity_ledger_v1.lock：無し／
  保留 0／作業場所 cs:77 - head
  台帳を archive/unity_ledger_v1_pre_bus91_20261104/ に退避（2804 行・md5 8beaf91f429e049ce10152bd5ebf6946）

--------------------------------------------------------------------
1. 入れたこと（cs:78。条件の mode が bus の回だけ働く）
--------------------------------------------------------------------
  (イ) 卓でスタッフを待っている下げ膳の台は、助けで動かしてよい
    ・30 秒動けなかった台の向かい合いの相手が、卓でスタッフを待っている下げ膳の台なら、その台を動かす
      （往復を終えて止まっている台と同じ扱い：止まっている方を動かす。動かす先の決め方も同じ＝相手の道の先から
       相手の半径＋前のセンサー 0.6 m＋自分の半径＋robotYieldSeparationM 離れた、床をたどって届く所）
    ・押されたあとは道を引き直さず、押された所でスタッフを待ち続ける。載せ終えたら、そこから洗い場へ
      （スタッフはそのまま卓で載せる。押されている間は卓での待ちの続きなので止まりに数えない）
    ・人が 30 秒動けず、すぐ前に止まっている台があるときにどかす決まり（依頼84）にも、この台を入れた。
      ただし、その台の片付けのスタッフのためにはどかさない
    ・助けのスタッフが 60 秒着けずに交代するとき、相手の台に動かす台を替える決まり（依頼84）にも、この台を入れた
    ・料理の受け渡し中の台（25 秒）は、今までどおり動かさない
  (ウ) 卓でスタッフを待つ時間の上限 120 秒（ServiceOps.BusWaitCapSec）
    ・台が卓に着いて（スタッフのそばで着いたとみた時も）から 120 秒たっても、スタッフが皿を載せ始めていなければ、
      皿を載せずに待機場所へ戻る（洗い場には寄らない）。その卓はスタッフが人だけで下げる（返却口へ運ぶ・拭く。今までの人だけと同じ）
    ・スタッフがもう載せ始めていたら戻らない（皿を載せたまま放り出さないため）
    ・120 秒はサイトの params に無い（試算には上限が無い）ので、コードの定数にした。サイトの試算に入れるかは決めてほしいこと 2
  記録（bus の回だけ。serve の回は今までと同じファイル・同じ列）
    ・bus_runs.csv のいちばん後ろに wait_capped（上限で戻ったら 1。end_why は「上限で戻った」）
    ・bus_summary.json に wait_cap_s（120）・bus_wait_cap_returns（上限で戻った回数）・bus_wait_rescue_calls（卓で待つ台を動かす助けを呼んだ回数）

  試しの回（check-in の前。書き先を KIOXIA の night/20261104_try91/ に向ける一時の直しを入れた版で、台帳には書いていない）：
    依頼90 で止まった4回のうち ③2台 種2・④2台 種9・⑥2台 種4 は全員帰った。④2台 種4 は残った（下の 5 章）。
    一時の直しは check-in の前に外した（HeadlessRun.cs は cs:77 と1字も違わないことを確かめ、保留から外した）

--------------------------------------------------------------------
2. 変えたファイル・版
--------------------------------------------------------------------
  cs:78：Service/ServiceOps.cs・Robot/ServingRobotController.cs・People/StaffAgent.cs・Experiment/ExperimentRunner.cs
  実行ファイル：Builds/headless　build_id cs78_20261104_1011・unity_cs ServiceSim/cs:78・pending_changes 空・error CS 0
  録画用：Builds/rec20_bus91（Builds/headless の写し）
  make_panel_video.py（status_videos/tools）：ロボットの欄に「下げ膳」を出すようにした（下の 6 章。元は night/20261104_rec91/make_panel_video_orig.py）

--------------------------------------------------------------------
3. 確かめ（画面なし・cs:78）
--------------------------------------------------------------------
  ・serve：⑦ fam_p5・2台・種7（det91s）と base73（cs:76）の同じ回
    contacts・dishes・give_ups・groups・nowarp_jams・passes・people_jams・requeues・rescues・robot_track・stops・timeline・yields は1行も違わない。
    trips.csv は plan_ms_max の列だけ、summary.json・conditions.json は written_at だけ、run_info.json は build_id・night・parallel・
    parallel_actual・run_label・speedup・unity_cs・wall_seconds・written_at と plan_ms_max_per_trip（道を引く実時間）だけ違う → 一致（依頼86・90 と同じ扱い）
  ・bus：③ fam_p1・2台・bus・種7 を2回（det91a・det91b）。上の13ファイル・bus_runs.csv・bus_summary.json・summary.json・conditions.json が一致。
    違うのは run_info.json の run_label・speedup・wall_seconds・written_at・plan_ms_max_per_trip と trips.csv の plan_ms_max だけ → 一致
  記録：night/20261104_det91s・det91a・det91b

--------------------------------------------------------------------
4. 120回（label bus75・同時4本・条件 120〜131 × 種0〜9）
--------------------------------------------------------------------
  120 回とも completed（やり直し 0）。10:13〜10:56。実時間 平均 1.4 分・最長 3.8 分
  見張り（1分ごと）：瞬間移動 0・1コマの跳び 0 のまま終わった
  記録：night/20261104_bus75_cs78/（queue_src.json・runner_log・runs.csv・judge.md・agg91.py・agg91_out.txt・run120.sh・watch91.py・watch_log.txt）

全体（同じ店・台数・種どうし）	serve（base73・cs:76）	bus74（cs:77）	bus75（cs:78）
回の数	120	120	120
瞬間移動	0	0	0
1コマの跳び	0	0	0
解けずに残った詰まり（件）	1	53	4
同（回）	1	4	1
全員が帰ったあとに始まった詰まり（件）	0	0	1
全員が帰らなかった回	なし	③2台種2・④2台種4・④2台種9・⑥2台種4	④2台種4
上限（120秒）で戻った回数	-	-	14
卓で待つ下げ膳の台を動かす助け（呼んだ回数）	-	-	166
詰まり（回）	2215	2565	2544
詰まり（秒）	133086	1567741	326575
卓を強引に空けた	32	30	25
助け	2243	2674	2732

  下げ膳の合計（bus75）：片付け 8484・ロボットが運んだ 2582・人だけ 5902・ロボットが向かった 2608・載せる前に取りやめ 23（うち上限で戻った 14）・
    スタッフのそばで卓に着いたとみた 1545（bus74：片付け 8316・運んだ 2496・人だけ 5820・向かった 2514・取りやめ 10・そばで着いた 1485）

店・台数ごと（種 0〜9 の中央値。分・km・割合。向き＝serve→bus75 の増減、＋は増える）
店 台数	項目	serve	bus74	bus75（向き）	試算 serve→bus（向き）	合う？
③1台	入店待ち	3.47	3.47	3.47（＝）	1.68→1.72（＋）	逆
③1台	料理の待ち	2.45	2.50	2.50（＋）	1.97→2.03（＋）	合う
③1台	turn	4.97	5.11	5.10（＋）	2.27→2.27（－）	逆
③1台	歩いた距離km	2.72	2.63	2.62（－）	1.88→1.86（－）	合う
③1台	下げ膳を運んだ割合	-	0.150	0.150	試算 0.165	（記録）
③2台	入店待ち	2.72	3.61	3.95（＋）	1.13→2.22（＋）	合う
③2台	料理の待ち	1.71	1.82	1.76（＋）	0.96→1.08（＋）	合う
③2台	turn	4.05	5.58	6.05（＋）	2.14→2.00（－）	逆
③2台	歩いた距離km	2.54	2.35	2.35（－）	1.61→1.45（－）	合う
③2台	下げ膳を運んだ割合	-	0.354	0.358	試算 0.442	（記録）
⑦1台	入店待ち	3.87	3.87	3.87（＝）	1.58→1.53（－）	逆
⑦1台	料理の待ち	2.51	2.51	2.51（＋）	2.01→2.04（＋）	合う
⑦1台	turn	6.47	6.59	6.59（＋）	2.31→2.27（－）	逆
⑦1台	歩いた距離km	2.74	2.63	2.62（－）	1.97→1.90（－）	合う
⑦1台	下げ膳を運んだ割合	-	0.145	0.145	試算 0.166	（記録）
⑦2台	入店待ち	3.87	5.07	4.65（＋）	1.60→1.70（＋）	合う
⑦2台	料理の待ち	1.52	1.83	1.86（＋）	1.01→1.10（＋）	合う
⑦2台	turn	4.49	6.79	8.06（＋）	2.19→2.04（－）	逆
⑦2台	歩いた距離km	2.55	2.37	2.36（－）	1.69→1.47（－）	合う
⑦2台	下げ膳を運んだ割合	-	0.386	0.364	試算 0.443	（記録）
④1台	入店待ち	11.02	11.38	11.39（＋）	4.81→4.85（＋）	合う
④1台	料理の待ち	1.79	1.95	1.91（＋）	1.29→1.38（＋）	合う
④1台	turn	19.72	19.41	19.66（－）	9.51→9.43（－）	合う
④1台	歩いた距離km	2.37	2.17	2.17（－）	1.75→1.64（－）	合う
④1台	下げ膳を運んだ割合	-	0.298	0.303	試算 0.274	（記録）
④2台	入店待ち	18.66	16.70	16.70（－）	5.57→3.86（－）	合う
④2台	料理の待ち	1.98	3.03	3.03（＋）	0.47→0.57（＋）	合う
④2台	turn	28.61	31.51	30.62（＋）	9.88→8.57（－）	逆
④2台	歩いた距離km	2.66	2.20	2.25（－）	1.75→1.37（－）	合う
④2台	下げ膳を運んだ割合	-	0.550	0.590	試算 0.710	（記録）
⑤1台	入店待ち	6.99	6.98	6.98（－）	3.16→3.38（＋）	逆
⑤1台	料理の待ち	2.63	2.69	2.68（＋）	2.28→2.32（＋）	合う
⑤1台	turn	10.21	10.83	10.30（＋）	3.39→3.40（＋）	合う
⑤1台	歩いた距離km	3.22	3.10	3.10（－）	2.59→2.52（－）	合う
⑤1台	下げ膳を運んだ割合	-	0.121	0.132	試算 0.145	（記録）
⑤2台	入店待ち	6.12	5.83	5.83（－）	2.37→2.78（＋）	逆
⑤2台	料理の待ち	1.71	2.06	2.06（＋）	1.27→1.34（＋）	合う
⑤2台	turn	10.45	9.86	9.84（－）	2.41→2.25（－）	合う
⑤2台	歩いた距離km	2.87	2.62	2.66（－）	2.12→1.91（－）	合う
⑤2台	下げ膳を運んだ割合	-	0.353	0.348	試算 0.392	（記録）
⑥1台	入店待ち	5.19	4.92	4.92（－）	3.68→4.01（＋）	逆
⑥1台	料理の待ち	2.03	2.09	2.09（＋）	2.01→2.03（＋）	合う
⑥1台	turn	11.73	11.40	11.40（－）	6.61→6.57（－）	合う
⑥1台	歩いた距離km	2.58	2.47	2.47（－）	2.18→2.09（－）	合う
⑥1台	下げ膳を運んだ割合	-	0.172	0.172	試算 0.164	（記録）
⑥2台	入店待ち	4.54	4.54	4.54（－）	2.11→1.77（－）	合う
⑥2台	料理の待ち	1.05	1.32	1.34（＋）	0.82→0.92（＋）	合う
⑥2台	turn	12.05	10.42	11.87（－）	5.27→4.74（－）	合う
⑥2台	歩いた距離km	2.37	2.14	2.14（－）	1.91→1.64（－）	合う
⑥2台	下げ膳を運んだ割合	-	0.400	0.393	試算 0.482	（記録）
②1台	入店待ち	1.60	1.62	1.62（＋）	1.79→2.47（＋）	合う
②1台	料理の待ち	1.02	1.13	1.13（＋）	0.91→1.04（＋）	合う
②1台	turn	3.49	3.01	3.01（－）	3.06→3.02（－）	合う
②1台	歩いた距離km	1.53	1.33	1.33（－）	1.16→1.09（－）	合う
②1台	下げ膳を運んだ割合	-	0.403	0.403	試算 0.399	（記録）
②2台	入店待ち	1.65	1.66	1.66（＋）	1.30→2.12（＋）	合う
②2台	料理の待ち	0.61	0.94	0.98（＋）	0.40→0.48（＋）	合う
②2台	turn	4.03	3.80	3.90（－）	2.80→2.66（－）	合う
②2台	歩いた距離km	1.55	1.21	1.19（－）	1.11→0.91（－）	合う
②2台	下げ膳を運んだ割合	-	0.690	0.704	試算 0.818	（記録）
  （turn＝客が帰ってから卓が使えるまで。歩いた距離＝スタッフ1人の歩いた距離）
  向き：合う 38・逆 10（bus74 と同じ本数・同じ項目）。逆の 10 本は bus74 と同じ：turn 5 本（③1・2台・⑦1・2台・④2台。試算は bus で減るか
    横ばい、Unity は増える。⑦2台は 6.79→8.06 とさらに増えた）・入店待ち 5 本（③⑦1台・⑤1・2台・⑥1台。差が小さいものが多い）
  ロボットが下げ膳を運んだ割合は ④1台・⑥1台を除き試算より低め（例 ③2台 0.358／試算 0.442、②2台 0.704／0.818）

  夜の判定（judge.md）の「回の失敗」2 件：④2台 種4 の全員が帰っていない（5 章）と、②2台 種3 の「ロボットが1コマで 0.05 m 超え」2コマ
    （瞬間移動 0・1コマの跳び 0。依頼90 で書いたのと同じ、連れて戻す速さ 1.0 m/秒 × 0.05 秒がちょうど 0.05 m になるもの）

--------------------------------------------------------------------
5. 残った詰まりの中身と場所（記録だけ。直していない）
--------------------------------------------------------------------
  ・④2台 種4（全員帰らなかった。回の上限 720 分まで回った）：料理の往復の2台が (3.51, 2.39)（7050 秒から）と (4.42, 2.34)（7112 秒から）で
    向かい合って止まり、どちらも 1往復の打ち切りのまま回の終わりまで残った。近くでスタッフの呼び出し (5.09, 2.65)・料理 (5.11, 2.10) も
    止まったまま。下げ膳の台は関わっていない（この回の最後の下げ膳は 6267 秒に終わっている）。依頼90 と同じ場所・同じ形。
    serve（base73）の同じ回は全員が帰っている
  ・③2台 種7（全員は帰った。11701 秒）：全員が帰ったのとほぼ同じ時刻（11700.9 秒）に2号機を卓22 への下げ膳に出したが、卓を強引に空けたので
    取りやめになり、2号機は待機場所のそば (17.3〜17.75, 5.6〜5.7) で行ったり来たりしたまま、600 秒後の 1往復の打ち切り（12299 秒）で回が終わった
    （「全員が帰ったあとに始まった詰まり」の 1 件）。bus74 の同じ回では起きていない（(イ)(ウ) で卓の動きが変わり、最後の下げ膳の時刻が変わった）。
    録画した同じ回（6 章）は録画なしの回と数字が違い（下記）、こちらでは起きていない
  serve（base73）の同じ 120 回で残った詰まりは 1 件（⑤2台 種7・スタッフ片付け (5.68, 13.13)。base73b で書いたもの）

--------------------------------------------------------------------
6. 比較動画の素材
--------------------------------------------------------------------
  回し方：night/20261104_rec91/rec_runner.py（依頼90 の写し。説明を足しただけ）で --oblique --hide-paths --max-wall-min 80 --parallel 2 --no-retry
    --limit-min 120 --build Builds/rec20_bus91。カメラは依頼87 と同じ wide_l30・wide_r30（方位 ±30°・見下ろし 60°・画角 40°・3840×2160・
    0.5 秒ごと・30 コマ/秒・回の最初から終わりまで・カメラの行列も）。並び：night/20261104_rec91/queue.json（③ fam_p1・2台・種7 の serve と bus）
  ・serve：20261104_rec91_cs78_fam_p1_r2_s7_passon_sbret_ek_post_rescue
      completed・全員帰った・店の時刻 199.5 分・実時間 58.0 分・瞬間移動 0・1コマの跳び 0・解けずに残った詰まり 0
      録画 wide_l30 799.9 秒（23996 コマ・店の時刻 0〜11997.5 秒）・wide_r30 も同じ長さ
  ・bus：20261104_rec91_cs78_fam_p1_r2_s7_passon_sbret_ek_post_rescue_bus
      completed・全員帰った・店の時刻 196.6 分・実時間 57.5 分・瞬間移動 0・1コマの跳び 0・解けずに残った詰まり 0
      録画 wide_l30 788.3 秒（23649 コマ・店の時刻 0〜11824.0 秒）・wide_r30 も同じ長さ
      録画なしの同じ回（det91a・bus75）は 205.0 分で 5 章の終わりの詰まりがあった。録画した回と録画なしの回で数字が違うのは
      依頼87 で書いたのと同じ（動画の映像とパネルの数字は、同じ録画の回の timeline.csv なので合っている）
  置き場所：/Volumes/KIOXIA/r2r2r-data/service_sim/unity/rec_compare_20261104/{serve|bus}/
    （録画 mp4・frames.csv・camera.json の写し、timeline.csv・summary.json、bus は bus_summary.json・bus_runs.csv も）
  通しのパネル付き動画：night/20261104_rec91/post91.py（依頼87 の panel87.py の「通し」と同じ作り方：wide_l30 を開店から終わりまで、
    0.5 刻みで 75 秒にいちばん近く 60〜90 秒に入る速さ）で make_panel_video.py を呼んだ
    ・serve/panel/whole_wide_l30_panel.mp4　76.2 秒・10.5 倍・1920x1080・30fps　題「③ 標準ファミレス・ロボット2台・配膳だけ」
    ・bus/panel/whole_wide_l30_panel.mp4　　75.1 秒・10.5 倍・1920x1080・30fps　題「③ 標準ファミレス・ロボット2台・配膳＋下げ膳」
    ・どちらも真ん中のコマ whole_wide_l30_panel_mid.png と panel_log.txt
    ・2本とも同じ 10.5 倍なので、並べたときに店の時刻がそろう（長さの違いは、bus の方が 173 秒早く全員が帰ったため）
  パネルの「下げ膳」：今の make_panel_video.py はロボットの欄を「運んでいる／待機」の2つだけで出していたので、timeline.csv に
    robots_bussing の列がある回だけ、動いている台のうち下げ膳の台を「下げ膳」と出すようにした。bus の動画の 2時間13分（店の 7980 秒）の
    コマで「運んでいる」「下げ膳」と出ることを確かめた。serve の timeline.csv にはこの列が無いので、serve の絵は前と同じ
    make_panel_video.py の md5 eed8539039501415828a5ff39384c889 → 45a541e860222bb0426ea30c5bd976d8　差分：
      46a47,48
      >     # 下げ膳にも使う回（timeline.csv に robots_bussing の列がある回）だけ、動いている台のうち下げ膳の台を「下げ膳」と出す（2026-11-04・依頼91）
      >     bus = min(int(row.get("robots_bussing") or 0), rb)
      51c53
      <         d.text((x0 + 68 + i * 150, y + 25), "運んでいる" if busy else "待機", font=F(24, True), fill=INK if busy else QUIET, anchor="mm")
      ---
      >         d.text((x0 + 68 + i * 150, y + 25), ("下げ膳" if i >= rb - bus else "運んでいる") if busy else "待機", font=F(24, True), fill=INK if busy else QUIET, anchor="mm")
  気づいたこと：パネルの題は 26 px の1行で、bus の題「③ 標準ファミレス・ロボット2台・配膳＋下げ膳」はパネルの右端で「配膳＋下」まで切れる
    （serve の題は右端ぎりぎりで収まる）。形は変えていない（決めてほしいこと 1）

--------------------------------------------------------------------
7. 台帳
--------------------------------------------------------------------
  2804 行 → 2929 行（追記 125 行だけ：確かめ 3・120 回・録画 2。どれも completed・unity_cs ServiceSim/cs:78）
  先頭 2804 行の md5 は 8beaf91f429e049ce10152bd5ebf6946（退避と同じ）。終わったあとの md5 a0589b65d2aae361301c9033afe92994。鍵ファイルは残っていない
  試しの回（night/20261104_try91/）は別の台帳（ヘッダだけ）に書かせ、本物の台帳には書いていない

--------------------------------------------------------------------
決めてほしいこと（どれも作業を止めるものではない。素材は撮り終えた）
--------------------------------------------------------------------
  1. bus の動画の題がパネルで切れる（「…配膳＋下」まで）。題を短くするか、パネルの題の字を小さくするか（パネルの形は変えていない）。
     比較動画を作るときに題を付け直すなら、このままでもよい
  2. 下げ膳の台が卓で待つ上限 120 秒は、サイトの params に無いのでコードの定数にした。サイトの試算（meta.bus）にも入れるか
  3. 区切りに従い記録だけにしたもの：④2台 種4 の料理の往復どうしの向かい合い（全員帰らない）・③2台 種7 の終わりの2号機の行ったり来たり・
     turn と入店待ちの向きが試算と逆の 10 本。いつ直すか

判定：合格
````


## 作業ログ ― ③の店の比較動画：配膳だけと配膳＋下げ膳を左右に並べた

依頼91 で、③の店・ロボット2台・種7 を、配膳だけと下げ膳にも使うの2通りで撮りました。どちらも全員が帰っています。それぞれのパネル付きの通しの動画を、左右に並べて同じ速さ（10.5倍）で同時に流し、下にその回の4つの数字を置きました。2本は同じ開店からの時刻で進むので、同じ瞬間の店の様子を見比べられます。

![③の店のロボット2台で、左が配膳だけ、右が配膳＋下げ膳。同じ開店から1時間44分の様子と、その回の4つの数字](https://pixelstomotors.com/media/LOG440_01_compare_serve_bus.png)

[図解: LOG440_serve_vs_bus.html](https://pixelstomotors.com/embeds/LOG440_serve_vs_bus.html)

この1回の数字は、スタッフ1人が歩いた距離が 2.65km → 2.38km、卓が使えるまでが 3.4分 → 4.7分、入店待ちが 3.1分 → 3.4分、ロボットを助けた回数が 20回 → 41回です。歩く距離は減ったけれど、ほかは悪くなりました。良い面だけを切り取らず、そのまま並べています。

サイトでは、試算のページで③の店を選び「Unity で動かすと」を押すと、いつもの動画の下にこの比較動画が出ます。

#### make_compare.py（比較動画を作るコードの全文）

````python
"""配膳だけと配膳＋下げ膳のパネル付き通し動画を左右に並べ、下に数字の帯を付ける（2026-11-04・Claude）
使い方: python3 make_compare.py  （rec_compare_20261104/ の中で）"""
import json, subprocess
from PIL import Image, ImageDraw, ImageFont
W,H=1920,1080; BG="#faf9f5"; INK="#1d1d1b"; Q="#6b6a64"; GOOD="#1d9e75"; BAD="#d85a30"; LINE="#d9d6cc"
F=lambda s,b=False: ImageFont.truetype("/usr/share/fonts/opentype/noto/NotoSansCJK-%s.ttc"%("Bold" if b else "Regular"),s,index=0)
S={m:json.load(open(m+"/summary.json"))["site_metrics"] for m in ("serve","bus")}
im=Image.new("RGB",(W,H),BG); d=ImageDraw.Draw(im)
d.text((40,22),"③ 標準ファミレス・ロボット2台　配膳だけ と 配膳＋下げ膳",font=F(40,True),fill=INK)
d.text((W-40,34),"同じお客さんの来かた（種7）・同じ速さ",font=F(24),fill=Q,anchor="ra")
VW,VH,Y0=936,527,150
for i,(m,lab) in enumerate((("serve","配膳だけ"),("bus","配膳＋下げ膳"))):
    x=16+i*(VW+16); d.text((x,104),lab,font=F(32,True),fill=INK)
rows=[("スタッフ1人が歩いた距離","walk_km_per_staff","km",2,True),("お客さんが帰ってから卓が使えるまで","turn_mean","分",1,True),
      ("入店待ち（来てから席に着くまで）","entry_wait_mean","分",1,True),("ロボットが止まってスタッフが助けた回数","rescues","回",0,True)]
y=Y0+VH+30; d.line((40,y-12,W-40,y-12),fill=LINE,width=2)
for name,k,u,dp,low in rows:
    a,b=S["serve"][k],S["bus"][k]; good=(b<a)==low
    d.text((40,y+6),name,font=F(30),fill=INK)
    fa=("%%.%df"%dp)%a; fb=("%%.%df"%dp)%b
    d.text((1040,y),fa+" "+u,font=F(40,True),fill=Q,anchor="ra")
    d.text((1100,y+4),"→",font=F(34),fill=Q)
    d.text((1420,y),fb+" "+u,font=F(40,True),fill=GOOD if good else BAD,anchor="ra")
    d.text((1460,y+8),"減った" if b<a else "増えた",font=F(28,True),fill=GOOD if good else BAD)
    y+=78
d.text((40,H-44),"Unity の中で1回動かした結果です。実際のロボットや人が同じ動きをするとは限りません。",font=F(22),fill=Q)
im.save("compare/bg.png")
dur=max(76.2,75.1)
vf=("[1:v]scale=%d:%d[a];[2:v]scale=%d:%d,tpad=stop_mode=clone:stop_duration=2[b];"
    "[0:v][a]overlay=16:%d[t];[t][b]overlay=%d:%d,format=yuv420p"%(VW,VH,VW,VH,Y0,16+VW+16,Y0))
subprocess.run(["ffmpeg","-y","-v","error","-loop","1","-i","compare/bg.png","-i","serve/panel/whole_wide_l30_panel.mp4","-i","bus/panel/whole_wide_l30_panel.mp4",
  "-filter_complex",vf,"-t","%.2f"%dur,"-r","30","-c:v","libx264","-preset","veryfast","-crf","22","-movflags","+faststart","compare/compare_serve_bus_p1_s7.mp4"],check=True)
subprocess.run(["ffmpeg","-y","-v","error","-ss","40","-i","compare/compare_serve_bus_p1_s7.mp4","-frames:v","1","compare/compare_mid.png"],check=True)
print("ok")
````

#### serving-robot.html の差分（③の動画の下に比較動画を足した所）

````diff
diff --git a/public/sim/serving-robot.html b/public/sim/serving-robot.html
index dc846e6..eeb72a1 100644
--- a/public/sim/serving-robot.html
+++ b/public/sim/serving-robot.html
@@ -172,6 +172,8 @@ footer { color: var(--ink-3); font-size: 11px; }
 .pv-sw button:focus-visible { outline: 2px solid #111; outline-offset: 2px; }
 .pv-unity video { display: block; width: 100%; aspect-ratio: 16 / 9; background: #3a3a3a; border-radius: 4px; }
 .pv-plan[hidden], .pv-unity[hidden] { display: none; }
+.pv-ch { margin: 18px 0 8px; font-size: 15px; }
+.pv-unity .pv-ch + video { display: block; width: 100%; aspect-ratio: 16 / 9; background: #3a3a3a; border-radius: 4px; }
 @media (max-width: 599px) { .plan-big .ph .pv-sw { margin-left: 0; width: 100%; grid-auto-columns: 1fr; } }
 .modes { display: grid; gap: 4px; background: var(--soft); padding: 4px; border-radius: 8px; }
 .modes label { display: grid; gap: 0; padding: 8px 10px; border-radius: 4px; cursor: pointer; color: var(--ink-2); }
@@ -503,7 +505,8 @@ function bigPlanSvg(p) {
 // 条件は Unity の録画の回のもの（試算で選んでいる人数・台数とは別）。動画と表紙の画像は R2（/media/）
 const UNITY = {
   fam_p0: { video: "/media/series8_unity_fam_p0_v3.mp4", poster: "/media/series8_unity_fam_p0_v3.jpg", staff: 2, note: "引きで店全体を見たあと、ロボットが長く止まった場所に3か所寄ります。右のパネルに、スタッフとロボットがいま何をしているかが出ます（約55秒）" },
-  fam_p1: { video: "/media/series8_unity_fam_p1_v3.mp4", poster: "/media/series8_unity_fam_p1_v3.jpg", staff: 4, note: "引きで店全体を見たあと、ロボットが長く止まった場所に3か所寄ります。右のパネルに、スタッフとロボットがいま何をしているかが出ます（約70秒）" },
+  fam_p1: { compare: { video: "/media/series8_compare_serve_bus_p1_v1.mp4", poster: "/media/series8_compare_serve_bus_p1_v1.jpg", note: "同じお客さんの来かたで、ロボットを配膳だけに使った店（左）と下げ膳にも使った店（右）を同時に流します（約75秒）。この1回では、スタッフの歩く距離は減りましたが、卓が使えるまでの時間と入店待ちは延び、ロボットを助けに行く回数は増えました。下げ膳の台が卓でスタッフを待つあいだ、細い通路をふさぐことがあるためです" },
+    video: "/media/series8_unity_fam_p1_v3.mp4", poster: "/media/series8_unity_fam_p1_v3.jpg", staff: 4, note: "引きで店全体を見たあと、ロボットが長く止まった場所に3か所寄ります。右のパネルに、スタッフとロボットがいま何をしているかが出ます（約70秒）" },
   fam_p2: { video: "/media/series8_unity_fam_p2_v3.mp4", poster: "/media/series8_unity_fam_p2_v3.jpg", staff: 2, note: "引きで店全体を見たあと、ロボットが長く止まった場所に3か所寄ります。右のパネルに、スタッフとロボットがいま何をしているかが出ます（約70秒）" },
   fam_p3: { video: "/media/series8_unity_fam_p3_v3.mp4", poster: "/media/series8_unity_fam_p3_v3.jpg", staff: 4, note: "引きで店全体を見たあと、ロボットが長く止まった場所に3か所寄ります。右のパネルに、スタッフとロボットがいま何をしているかが出ます（約60秒）" },
   fam_p4: { video: "/media/series8_unity_fam_p4_v3.mp4", poster: "/media/series8_unity_fam_p4_v3.jpg", staff: 3, note: "引きで店全体を見たあと、ロボットが長く止まった場所に3か所寄ります。右のパネルに、スタッフとロボットがいま何をしているかが出ます（約60秒）" },
@@ -514,7 +517,10 @@ function unityPane(k) {
   const u = UNITY[k]; if (!u) return "";
   return `<div class="pv-unity"${planView === "unity" ? "" : " hidden"}>`
     + `<video controls muted playsinline preload="none" poster="${u.poster}" data-src="${u.video}" aria-label="${STORES[k].short}を Unity で動かした様子"></video>`
-    + `<p class="pn">${u.note}。動画の条件はふつうの混み具合・スタッフ${u.staff}人・ロボット2台で、上で選んでいる条件とは別です。Unity の中で起きたことで、実際のロボットや人が同じ動きをするとは限りません。</p></div>`;
+    + `<p class="pn">${u.note}。動画の条件はふつうの混み具合・スタッフ${u.staff}人・ロボット2台で、上で選んでいる条件とは別です。Unity の中で起きたことで、実際のロボットや人が同じ動きをするとは限りません。</p>`
+    + (u.compare ? `<h4 class="pv-ch">配膳だけ と 配膳＋下げ膳</h4><video controls muted playsinline preload="none" poster="${u.compare.poster}" src="${u.compare.video}" aria-label="${STORES[k].short}で、ロボットを配膳だけに使った店と、下げ膳にも使った店を左右に並べた動画"></video>`
+      + `<p class="pn">${u.compare.note}</p>` : "")
+    + `</div>`;
 }
 function bigPlan(k) {
   const s = STORES[k], p = PLANS[k];
````


## 作業ログ ― 区切りで残したこと

決めた区切りに従って、次のことは直さずに記録だけにしています。

| 残したこと | 中身 | いまの扱い |
|---|---|---|
| ④2台 種4 の向かい合い | 料理を運ぶ2台が向かい合って止まり、全員が帰らない | 記録だけ。下げ膳とは関係ない |
| 立ち往生の多さ | 立ち往生が1回でもあった往復の割合 0.062（試算 0.01） | 記録だけ。試算の値は変えない |
| ⑦の細い通路 | 見張りで止まった台が入口側の通路をふさぎ、入店待ちが延びる回がある | 記録だけ |
| 下げ膳で試算と逆になった向き | 卓が使えるまでと入店待ちの向きが試算と逆の10本 | 記録だけ |
| 下げ膳の待ちの上限2分 | いまは Unity のコードの定数。サイトの試算には上限がない | サイトの試算の決まりに足すかは、これから決める |
| 録画した回と録画しない回の違い | 同じ種でも、録画すると860秒ごろから記録が分かれる | 記録だけ。動画の映像とパネルの数字は同じ回なので合っている |

これで、配膳ロボットのベースは一区切りです。次は、配膳ロボットでまだできていない大型店⑧⑨を足し、そのあとほかの種類のロボットへ進みます。
