====================================================================
依頼 v10 の報告：逃がし弁「卓を空けた」の数え方を直し、試算 v2.8 を写した
2026-10-25 10:04
====================================================================

結論：0・1・2 章ぜんぶ入れました。組み立ては通っています（53 本・エラー 0）。
B（回す）はエイイチが押す番です。押す前に 1 つだけ決めてほしいことがあります
（7 章の「種1 で回すために .asset を 1 つ変えました」）。


====================================================================
0. 試算 v2.8 を写した
====================================================================

写した：
  unity/site_copy_v28/serving-robot-params.json
  → Assets/ServiceSim/Experiment/serving-robot-params.json
ネットからは取っていません。

読む前に確かめたこと（ぜんぶ合っています）:
  meta.model            = v2.8
  meta.layout_generation = 8a5b2f6a016a（店の形は変わっていない）
  unity_conditions       = 6 件。registers はぜんぶ 1
  site_result            = 6 件とも pay_wait_mean がある
                           （③0台 12.2785 / ③1台 7.9893 / ③2台 7.9844 /
                             ⑦0台 11.7376 / ⑦1台 8.0624 / ⑦2台 7.9555）

v2.7 からの変わり方（③0台）:
  entry_wait 3.99 → 3.30 ／ staff_wait 3.36 → 0.95 ／ turn 9.72 → 2.49
  blocked_wait 2.95 → 0.73 ／ full_wait 0.46 → 2.17
  レジが詰まる分が pay_wait（12.3 分）に移ったので、席の待ちが短くなっています。

「違えば回さない」を Unity 側にも入れました（SimParams）:
  ・meta.model が expectModel（.asset の値。いま v2.8）と違えば回さない
  ・condition.registers が registersSupported（いま 1）と違えば回さない
    Unity はレジの内側に店員1人・会計は1組ずつしか作っていないので、2 は回せません
  版の番号（layout_generation）の突き合わせは前からあるので、そのままです。

  版を手で書かずに済むように、v2.8 という字は C# に埋めず SimParams.asset に置きました
  （expectModel: v2.8）。次に版が上がったら、.asset のこの 1 行だけ直してください。


====================================================================
1. 逃がし弁の数え方（直したファイル：Service/GroupManager.cs）
====================================================================

Group.stuckS を増やす所を、これだけ変えました。

  前）  if (g.state == Paying || g.state == Clearing)
        {
            g.stuckS += dt;                       ← ずっと数えていた
            if (600 秒に達したら) ForceFreeTable(g);
        }

  後）  if (g.state == Paying || g.state == Clearing)
        {
            if (g.job != null && g.job.taken) g.stuckS += dt;   ← 取られている間だけ
            if (600 秒に達したら) ForceFreeTable(g);             ← ここは変えていない
        }

数える／数えないの分かれ方:
  g.job == null        … 会計の並ぶ点が空くのを席で待っている間。数えない
  g.job.taken == false … 板に載ったまま誰も取っていない間
                         （ふつうの片付け待ち・会計待ち）。数えない
  g.job.taken == true  … スタッフが取ったのに着けない。これだけ数える

あきらめて板に戻したとき（ops.AbandonJob が taken を false に戻す）は、
数えるのを止めるだけで 0 には戻しません。何度も着けない卓はこれで見つかります。

600 秒に達したあとの流れ（ForceFreeTable）と tableStuckFreeSec は変えていません。
give_ups.csv の waited_s は g.stuckS をそのまま書いているので、
自動で新しい数え方の秒数になります。

ついでに直したもの（動きには効きません）:
  ・ForceFreeTable の説明文が UpdateSeatedBodies の上に落ちていたので、本体の上に戻した
  ・Group に tableForceFreed を足した（2 章の pay_wait_mean から外すため）


====================================================================
2. 試算と同じ数字を出す
====================================================================

(a) pay_wait_mean（summary.json の site_metrics に足した）

  直したファイル：Experiment/ExperimentRunner.cs（CollectPayWait）
                  Experiment/TripLogger.cs（SimLike・site_metrics）

  組ごとに（会計が終わった時刻 − 食べ終えた時刻 − pay_s）÷ 60 の平均（分）。
  groups.csv の pay_s 列と eat_end_s から出る値と同じで、引く pay_s は
  ServiceSpec.paySec（サイトから読んだ 90 秒）です。

  入れない組:
    ・逃がし弁で卓を空けられた組（tableForceFreed）
    ・会計が終わっていない組（pay_s が -1。打ち切りで店に残った組）
    ・慣らしで最初から座っていた組（サイトの条件では慣らしを使わないので 0 件）

  site_metrics に 2 つ出ます:
    pay_wait_mean    … 上の平均（分）
    pay_wait_groups  … その平均に入れた組の数

(b) 片付け・会計が板で待った最大と、長びいた数（summary.json）

  直したファイル：Service/ServiceOps.cs（RecordJobWait に最大と超えた数を足した）
                  Experiment/ExperimentRunner.cs・TripLogger.cs（書き出し）

  新しい欄（仕事の名前ごと。案内・料理・呼び出し・会計・片付け・立ち往生）:
    job_wait_max_s        … 板に載ってから取られるまでの、いちばん長かった秒数
    job_wait_over_count   … そのうち 600 秒を超えた数
    job_wait_note.over_s  … 600 秒（tableStuckFreeSec と同じ値を書く）

  数え方の但し書き（job_wait_note.note にも書いてあります）:
    ・取られないまま終わった仕事（卓を空けたときに板から外した分）は入りません。
      「板に載ってから取られるまで」なので、取られなければ値が出ません。
      直したあとは卓を空けるのが減るので、長い待ちはここに出てきます
    ・あきらめて板に戻った仕事は、取られるたびに 1 回ずつ数えます
      （板に出た時刻からは数え直しません）


====================================================================
3. 確かめ A（Claude Code が見た）
====================================================================

(1) 組み立て

Unity Editor がプロジェクトを押さえているので、Unity を立てずに
Unity 同梱の csc（Roslyn・2022.3.62f3）で ServiceSim の .cs を 53 本ぜんぶ
組み立てました。エラー 0・警告 0 です。
Unity に切り替えたら Console は見てください（.meta の作られ方は Unity 側でしか分かりません）。

(2) 数えない場面で stuckS が増えないこと（読んで確かめた）

g.job に書き込む所は 8 か所だけで、Paying・Clearing の間は
「null」か「その組の会計／片付けの仕事」のどちらかしかありません。

  SeatWaiting   g.job = 案内の仕事   → 状態は Guided（数える所に入らない）
  OnGuided      g.job = null         → 状態は Seated。このまま Eating → Paying に進む
  Paying に入った時点              → g.job は null のまま。数えない ○
  SendPayerIfPossible              → 並ぶ点が取れなかったら index < 0 で return。
                                      g.job は null のまま。数えない ○
                                      取れたときだけ会計の仕事を出して g.job に入れる
  Left → Clearing                  → 片付けの仕事を出して g.job に入れる。
                                      出した瞬間は taken = false。数えない ○
  OnPaid / OnCleared / ForceFreeTable → g.job = null

ops.AbandonJob は job.taken を false に戻すだけで板からは外さないので、
戻された仕事は同じ StaffJob のまま板に残り、g.job も指したままです。
だから「戻っている間は数えない・取られたら続きから数える・0 には戻さない」で合っています。

(3) 直したあと「卓を空けた」が 0 に近くなるはずの裏づけ

スタッフが仕事を取ってから止まっていられる時間には、もう上限があります。
PeopleSpec の staffGiveUpSec = 60 秒・staffGiveUpMaxTries = 3 なので、
行き先に着けないまま 60 秒たつと板に戻し、3 回めで「移した」になって仕事が済みます。
ふつうに着ければ、片付けは clear_s 40 + wipe_s 40 = 80 秒、会計は pay_s 90 秒。
どの道でも 600 秒には届きにくいので、卓を空けるのは
「同じ卓で何度も戻されて積み上がった」ときだけになります。

(4) 直す前の回から、新しい欄の値を先に出してみた

比べる相手の回（20261024_stageB_cs143_fam_p1_r0_s1・83 組）の
groups.csv を、新しい pay_wait_mean の決まりのまま計算しました。

  卓を空けた 24 卓（会計 7・片付け 17）。依頼にある数と同じです
  groups.csv の table_id が 0 の 24 行が、その卓を空けられた組です
  （ForceFreeTable が g.table を外すので 0 で残ります）

  pay_wait_mean（卓を空けた 24 組を外す・59 組）  = 2.90 分
  （外さずに会計の済んだ 76 組でみると         = 3.20 分）
  試算 v2.8 の同じ条件                          = 12.28 分

  → 直す前の Unity は、レジ待ちの長い組を「卓を空けた」で切っていたので、
     会計待ちが試算の 4 分の 1 しか出ていません。
     直したあとはここが伸びるはずです（伸びなければ別の原因です）。

  おまけ：いまの job_wait_mean_s は 会計 135.3 秒・片付け 176.5 秒。
  600 秒のうち半分近くが「板で順番待ち」だったことが分かります。

(5) 1 つだけ、依頼の書き方で迷った所（勝手に変えてはいません）

依頼の 2 章は「食べ終えた時刻」に groups.csv の eat_end_s を使うと書いてあるので、
そのとおりにしました。ただ Unity の eat_end_s は「食べ始めに決めた食べ終わりの時刻」で、
そのあと遅れて届いた皿やドリンクバー・トイレの人を待ってから会計に入ります
（会計に入った時刻は pay_start_s）。その待ちが pay_wait_mean に混ざります。

混ざった分の大きさが見えるように、summary.json の job_wait_note に
pay_wait_from_pay_start_mean（pay_start_s から数えた同じ値）も出しました。
上の回で比べると 2.90 分 と 2.84 分で、差は 0.06 分です。
小さいので、site_metrics に出す pay_wait_mean は依頼どおり eat_end_s のままにしました。


====================================================================
4. 回す前にしてほしいこと（B はエイイチが押す）
====================================================================

1. Unity に切り替える（新しい .cs と serving-robot-params.json が取り込まれる）。
   Console に赤い字が無いか見る。

2. ServiceSim/Site Run/条件を一覧する（回さない）を押す。
   報告に次が出るはずです。出なければ回さないでください。
     試算の版 (meta.model): v2.8（待っている版: v2.8）
       / 店の形の版 (meta.layout_generation): 8a5b2f6a016a
     条件: 6 件 … どれも「レジ 1 つ」
     合わないもの: なし
     出す数字の名前と意味に pay_wait_mean が並ぶ

3. ServiceSim/Site Run/③ スタッフ4人・ロボット0台 を 1 回。

   ★ 種 1 で回すために、ExperimentPlan.asset の trialSeed を 0 → 1 にしました。
     Site Run の種はここから来ます（0 のままだと種 0・64 組になって、
     比べる相手（種 1・83 組）と合いません）。
     trialSeed は Site Run と Stage 2 の単発だけが読みます。
     段階Bの18回は自分の種の一覧を持っているので影響しません。
     種 0 の単発に戻したいときは、ここを 0 に戻してください。

   出力フォルダは
     /Volumes/KIOXIA/r2r2r-data/service_sim/unity/
       20261025_p1_efficient_corner_fam_p1_s4_r0_a42_s1_{HHMM}/
   になります（KIOXIA をつないでから押してください）。


====================================================================
5. B で見るもの（比べる相手：20261024_stageB_cs143_fam_p1_r0_s1・83 組）
====================================================================

                                   直す前      直したあとの見込み    試算 v2.8
  卓を空けた                       24（会計7・片付け17）  0 に近い     −
  あきらめた / 移した              7 / 13      増えてよい（仕事が消えないので） −
  入店待ち entry_wait_mean         1.74 分     伸びる                3.30 分
  席は空いているのに staff_wait    0.55 分     伸びる                0.95 分
  客が帰ってから turn_mean         4.95 分     伸びる                2.49 分
  スタッフの手 staff_util          0.77        そのあたり            0.72
  pay_wait_mean                    2.90 分※   伸びる                12.28 分
  来た組                           83 組       83 組（変わらないはず） −
  最後まで回り切る                 回り切った  回り切る              −

  ※ 直す前の回の groups.csv から、新しい決まりで計算した値（3 章 (4)）

  新しい欄（直す前は無いので、出た値をそのまま見ます）:
    job_wait_max_s の 片付け・会計 … 板で待った最大（秒）
    job_wait_over_count の 片付け・会計 … そのうち 600 秒を超えた数
    job_wait_note.pay_wait_from_pay_start_mean … 照らし合わせ用

  来た組が 83 組から変わっていたら、動きのずれで来客が変わったしるしです
  （依頼 v8b の B で乱数を分けてあるので、変わらないはずです）。


====================================================================
6. 直したファイルの一覧
====================================================================

  Assets/ServiceSim/Experiment/serving-robot-params.json   v2.8 を写した
  Assets/ServiceSim/Experiment/SimParams.cs                版とレジの数の突き合わせ・
                                                           condition.registers を読む
  Assets/ServiceSim/Experiment/SimParams.asset             expectModel: v2.8 /
                                                           registersSupported: 1 /
                                                           写した記録を今日の分に直した
  Assets/ServiceSim/Service/GroupManager.cs                stuckS の数え方（1 章）・
                                                           tableForceFreed
  Assets/ServiceSim/Service/ServiceOps.cs                  板で待った最大と 600 秒超えの数
  Assets/ServiceSim/Experiment/ExperimentRunner.cs         pay_wait_mean を集める・
                                                           新しい欄を渡す
  Assets/ServiceSim/Experiment/TripLogger.cs               summary.json に書く
  Assets/ServiceSim/Experiment/ExperimentPlan.asset        trialSeed: 0 → 1（4 章の★）


====================================================================
7. 入れていないこと（決めてほしいこと）
====================================================================

1. 段階Bの台帳（unity_ledger_v1.csv・ServiceSimStageB）に pay_wait_mean と
   site_pay_wait_mean の列を足していません。
   列を足すと台帳の形が変わって、KIOXIA の集計（b1_collect.py など）を
   直す必要が出ます。18 回の回し直しを頼むときに一緒に決めたいです。
   summary.json には入っているので、集計側で読むことはできます。

2. 「移した」が増えるはずです（仕事を卓を空けて消さなくなるので、
   着けない仕事が板に残って回り続けます）。
   増え方が大きいようなら、そこを次に見る所として扱いたいです。

B が最後まで回り切ったら Check-in して番号を報告します。
段階Bの18回の回し直しは、B の結果を見てから相談します。
