コードは出来て、両方のアセンブリがエラー・警告ゼロで通りました。ただし Check-in
  はまだしていません — 指示書の 4 が「Check-in
  の前に1回回して確かめる」なので、そこで止めています。

  直したファイル

  1. ロボットが運んだ皿を、卓に着いた時点で「届いた」に

  ファイル: ServingRobotController.cs
  変えた所: StopArrived（ロボット・止まる所の番号）イベントを足し、CheckArrival
  で
  Phase.Dwell に入る所で発火。受け渡しの25秒の前です。あわせて
  StopArrivedS（所ごとの着いた時刻、未着は -1）を持たせ、StartRun で初期化
  ────────────────────────────────────────
  ファイル: ServiceOps.cs
  変えた所: _stopDishes（止まる所の番号 → 皿 の対応表）を追加。AssignRobots で 
  stops と同じ並びに組みます（SlotOf が null 
  の皿はどちらからも外すので番号がずれません）。OnRobotStopArrived で
  DishArrived(d, true)
  ────────────────────────────────────────
  ファイル: ServiceOps.cs
  変えた所: OnRobotRunDone は StopsCompleted の数で数えるのをやめ、arrivedS < 0
  の皿だけを受け渡し口の先頭へ戻す形に。理由（打ち切り・取りやめ・動けなくなった
  ・着かなかった）は前と同じ

  DishArrived の既存ガード（arrivedS >= 0
  なら何もしない）で二重計上は起きません。GroupManager
  の食べ始め・会計の決まりは触っていません。

  2. 往復の記録が1つ前の往復になっていた

  原因は指示書のとおりでした。直し方は呼ばれる順番に頼らない形にしました。

  前: ExperimentRunner → c.TripCompleted += OnRunDone   （ops
  より先に登録＝先に呼ばれる）
  後: ExperimentRunner → ops.RunRecorded += OnRunDone   （ops
  が片づけを終えてから出す）
  ServiceOps.OnRobotRunDone の最後に RunRecorded を出すので、LastBatchOf
  はその往復の皿を返します。

  足した列（既存の並びは変えず、後ろに）:
  trips.csv  : run_start_s, dish_ids, stop_arrived_s
  groups.csv : eat_start_s      （GroupManager に g.eatStartS を追加）
  conditions.json の trips_csv_columns は Header
  をそのまま出しているので自動で追従します。あわせて groups_csv_columns と
  dishes_csv_columns も出すようにしました。

  3. 段階Bの押し直し（v7b の中身）

  ┌───────────────┬──────────────────────────────────────────────────────────┐
  │     項目      │                         直した所                         │
  ├───────────────┼──────────────────────────────────────────────────────────┤
  │               │ ServiceSimLedger.RunKey(店, 台数, 種, unity_cs) ＋       │
  │ 照合キー      │ DoneKeys() を追加。出力フォルダ名では照らし合わせません  │
  │               │ 。版が違えば回します                                     │
  ├───────────────┼──────────────────────────────────────────────────────────┤
  │ フォルダ名    │ {日付}_stageB_cs{版}_{店}_r{台数}_s{種}。既にあれば      │
  │               │ _2・_3 … を付けた新しいフォルダへ（上書きしません）      │
  ├───────────────┼──────────────────────────────────────────────────────────┤
  │ pending_chang │ 置いてあるだけ（Private）も数に入れるようにしました。前  │
  │ es            │ は PR  行を外していたので、2件あったのに空でした。cm     │
  │               │ を呼べないときは 不明 と書きます                         │
  └───────────────┴──────────────────────────────────────────────────────────┘

  実際に確認しました — 段階Bの1回目の run_info.json は pending_changes = ''
  でした（Mat_MonitorBoard の2件が落ちていた）。これからは 保留あり 2 件（管理下 
  0 件・置いてあるだけ 2 件） のように入ります。

  台帳（18行・49列・すべて completed・unity_cs: 
  cs:140）と既存の出力フォルダは触っていません。

  ---
  お願い：確かめの1回を回してください

  Unity がプロジェクトを開いているため、私からは回せません。一度 Unity 
  に切り替えて（スクリプトが再コンパイルされます）、

  ServiceSim / Site Run / ③ スタッフ4人・ロボット2台

  を押してください。前回と同じなら実時間で12分ほどです。終わったら「終わった」と
  だけ教えてください。

  確かめ用のスクリプトは用意済みで、指示書 4 の5項目を機械で見ます:

  - a ロボットが運んだ皿すべてで arrived_s が その往復の stop_arrived_s
  のどれかと一致し、run_start_s + total_s より前
  - b 各行の dish_ids の dish_ready_s が dishes.csv の ready_s
  と一致／同じ皿が2つの往復に出ていない／1行目の dishes が0でない
  - c eat_start_s が「最初の料理が全部届いた時刻」と一致
  - d dishes.csv に同じ dish_id が2行ない／robot_dishes + staff_dishes = 行数
  - e dish_wait_parts.robot.carry_mean_min が段階Bの同じ条件より短い

  e の比べ先の数字を確認しました: 20261023_stageB_fam_p1_r2_s0 の
  robot.carry_mean_min = 2.9041 分 — 指示書の 2.90分 と一致します。

  1点だけ、確かめ方を弱めます

  指示書 b の「dish_ids の皿が dishes.csv
  で同じロボットが運んだ皿で」は、dishes.csv に robot_id 
  の列が無いため、そのままは見られません。指示書 1 に「dishes.csv
  の列は変えない」とあるので列は足していません。

  代わりに ①その皿が carried_by=ロボット であること ②同じ dish_id 
  が2つの往復に出ていないこと ③dish_ready_s が一致すること 
  で見ます。皿は1つの往復しか載らないので、③と②が通れば「前の往復の皿が混ざってい
  ない」ことは言えます。dishes.csv に robot_id
  を足してよければ、そのまま厳密に見られます — ご判断ください。
