Files
TheTree_mock/docs/plans/original-completion-2026-10-02/execution/p16-01-dismiss/IMPLEMENTATION_NOTES.md
T

13 KiB
Raw Blame History

P16-01-DISMISS 実装の記録(実 Opus の実装担当、2026-10-24)

  • 仕様: 同じフォルダの SPEC.md(登録版 r04。main 0b59d7c に固定。Runner の spec_sha256 は 14efffd9…e6b)。出典は PROVENANCE.json。
  • 原本への加算は 0。原単位 P16-01・P16-03、AR.staff.dismissal_severance の package P05 の原 work・原 AC は閉じない(SPEC §8)。
  • 管理の記録は artifacts/original-completion-2026-10-02/p16-01-dismiss-control-r01/ にある(git の外)。
  • 変えた製品のファイル: autoload/simulation_runtime.gd・scripts/economy/finance_policy.gd・scripts/ui/staff_management_panel.gd。scripts/staff/staff_service.gd と scenes/main/main.gd は変えていない(§1・§4)。

1. 命令と判定の順(SPEC §4.1)

  • SimulationRuntime に通常の command dismiss_staff(payload staff_id)を足した(_execute_dismiss_staff)。
  • (a) 運営の終了(BANKRUPT)と (b) 同じ key の再送(DUPLICATE_IDEMPOTENCY_KEY)は、今の submit_command と CommandQueue.enqueue のまま受付の前・受付で止まる(R5・R6、5.b)。
  • (c) executor は、状態を変える前に次の順で確かめる。どれかに当たれば、その理由で失敗の結果を返す(5.c)。
    1. payload に staff_id が無い → INVALID_PAYLOAD
    2. 職員が居ない → NOT_FOUND(R4)
    3. UNIQUE → UNIQUE(R1。今の remove_staff と同じ code と文)
    4. FREE_HIRE でない(ADULT_CONTRACT)→ NOT_GENERAL_EMPLOYEE(R7)
    5. 外部が持つ作業(仕入れの物流)→ EXTERNAL_TASK(R2。今の remove_staff と同じ code と文)
    6. 終わっていない襲撃の防衛者 → DEFENSE_LOCKED(R9。Root の一時の境界)
    7. 救護の組が一緒に昇降機に乗っている → RESCUE_PAIR_ABOARD(§3 の決め)
    8. 表金と裏金の合計が退職金に足りない → INSUFFICIENT_FUNDS(R8)
  • (d) 全て通れば、次を1つの操作として行う。
    1. 既存の削除の契約 StaffService.remove_staff(staff_id, &"DISMISSED", true, 分)。作業の予約を解けない時(R3)は、この契約が何も変えずに拒む(在庫の解放は自分で巻き戻す)。理由は RESERVATION_RELEASE_FAILED、文は今の契約のまま。
    2. 退職金の記帳(§2)。
    3. 救護の後始末(§3)、施設の人員の投影(_sync_facility_staffing)、出来事の欠けた職員の扱い(event_service.audit_actor_availability)。
  • 1 の後で失敗すれば、命令の前の写し(staff・inventory・path・elevators・移動の残り・出来事・ID・帳簿・Gold の写し)に全て戻して、TRANSACTION_APPLY_FAILED を返す。試験は、退職金の記帳の key を先に使っておく fixture でこの経路を通し、5.c の比べ方で何も変わらないことを確かめる。
  • 画面と試験のための読むだけの関数 get_staff_dismissal_preview(staff_id) を足した(解雇できるか・理由・退職金・未払い・開き直す作業・表金・資金の合計)。get_staff_management_report の各行に dismissal として載る。R3 は前もって分からないので、押した後に命令が拒み、理由を出す。

2. 退職金(SPEC §3.5・§3.6、A14)

  • FinancePolicy に SEVERANCE_EXPENSE(口座 STAFF_SEVERANCE_EXPENSE)・SEVERANCE_CATEGORY(区分 STAFF_SEVERANCE)・SEVERANCE_DAYS(3)・severance(日給) を足した。額は get_effective_daily_wage() × 3。
  • 記帳は命令の時刻に、1つの取引(idempotency key staff.severance.<command の ID>)で行う。
    • 表金で足りない分: 裏金 → 表金の補填(区分 BACK_FUND_TOP_UP、P05-02 の返済と同じ形)。
    • 退職金: 表金 → STAFF_SEVERANCE_EXPENSE(区分 STAFF_SEVERANCE、source は職員の ID)。
  • 日次決算の照合では cost_of_goods(画面「運営費(仕入れ・契約金等)」)に入れる。写した表は _build_operations_daily_financials と _operations_expected_category_totals の2つ。施設ごとの表は、施設でない source を読まないので変えていない。補填は fund report v2 の back_top_up(その日の全ての補填)に入る。
  • 旧セーブ: FinancePolicy.prepare_accounts の最後で、退職金の口座が無ければ空の口座として足す(A12 の5つの口座とは別に判定する。P05-02 の後・P16 の前のセーブにも足す)。口座があって負を許す設定なら拒む。
  • 解雇の前に貯まった未払いの給与は、今の契約のまま _departed_payroll に保持され、次の 00:00 の締めで払われる(A09 の補填を含む)。解雇の日の日給は今の給与の契約のまま(締めの時に雇用中の職員だけ)。

3. 後始末(SPEC §6.2・§6.2.1)

  • 勤務・予定・配置は remove_staff、経路の actor・昇降機の予約・移動の残り・STAFF_REMOVED(reason DISMISSED)は今の _on_staff_removed が行う。
  • 施設の人員の投影は命令の中で _sync_facility_staffing をすぐ行う。サービスの途中の職員が抜けて人数が staff_min を欠けると、次の施設の更新から今の規則で職員を待ち(5 分)、代わりが来なければ失敗する(A4 の試験)。
  • 救護(_interrupt_dismissed_staff_rescue): 次の時刻の救護の確認(_advance_staff_rescue の最初の段)と同じ規則を、命令の中で、解雇した職員に関わる作業にだけ当てる。
    • 患者を解雇した時: その患者を目標にした終わっていない救護の作業を RESCUE_INTERRUPTED で取り消し、患者と運搬者の昇降機の予約を取り消す。運搬者が1人で昇降機に乗っている時は、今の規則(乗っている間は保つ)どおり予約を取り消さず、運搬者は本物の階に着く。作業は取り消すので、解雇した患者への参照は残らない。
    • 運搬者を解雇した時: remove_staff が開き直した搬送(rescue_transport)は運搬者が居ないので取り消す(今の規則と同じ)。迎え(rescue_pickup)は開き直ったまま、別の医療職を待つ(今の規則でも有効な作業)。患者は次の時刻に今の規則で救護をやり直す。
    • 運搬者と患者が一緒に昇降機に乗っている時(決め): どちらの解雇も RESCUE_PAIR_ABOARD で拒む(5.c)。着くまで保つ今の規則(ElevatorService.cancel_actor も乗っている組の取り消しを拒む)と、命令の直後の保存の照合の両方が成り立つのはこの形だけである。決めた範囲(Runtime と StaffService)の外の ElevatorService を変えずに、乗っている1人だけを消すと、昇降機に持ち主の居ない予約が残る。これは R2 と同じ「着くまで待つ」の一時の拒否で、許可の行の全面の拒否ではない。A6・A7 は他の全ての段階(歩いている・昇降機を待つ・1人で乗っている・組で待つ・降りた後・治療中)で解雇でき、着いた後は同じ職員を解雇できる(試験)。退却や戦闘のような新しい規則は作っていない。
  • 出来事: 命令の中で公開の event_service.audit_actor_availability を呼び、進行中・選択待ち・中断の出来事の欠けた職員を今の missing_actor_policy で扱う(CANCEL と CONTINUE_WITHOUT を試験)。予約した費用は今の規則で1回だけ戻る。この audit は他の欠けた actor も今の規則で扱う(次の時刻と同じ処理が早く行われるだけ)。
  • 命令の直後に保存し、同じ process(写しの復元と、ディスクへの保存と読み込み)と別の process(再開の2段)で読み込んでも、欠けた職員への生きた参照(終わっていない作業の患者と運搬者、昇降機の予約と相方、経路の actor、施設の人員、出来事の拘束と actor)が残らず、保存の照合が通る。
  • 履歴として残るもの: 終わった作業の記録の target_entity_id、サービスの staff_ids(始めた時の記録)、給与の締めの行、雇った候補の記録(同じ候補は二度雇えない今の規則のまま)。

4. 画面(SPEC §4.3)

  • StaffManagementPanel に「解雇する…」と確定の欄(「解雇を確定」「やめる」)を足した。判定は Runtime の preview に従う。
    • 押す前に、退職金の額(日給の3日分)、裏金からの補填、未払いの給与、開き直す作業を出す。
    • 拒否の行ではボタンを無効にし、理由を出す。UNIQUE は今の「ユニーク:雇用・維持費無料 / 解雇・売却不可」、それ以外は「解雇不可:…」。無効のボタンを無理に押しても命令を送らない(5.a)。
    • 確定の時に名簿を読み直し、読み込みや変化の後の古い確認では送らない。
    • 時間が止まっている時はすぐに、進んでいる時は次の時刻に命令が処理され、結果(払った退職金・補填・保持した未払い・開き直した作業、または拒否の理由)を出し、名簿と選択を更新する。解雇の受理を待つ間、その職員の配属の変更とドラッグは止める。
  • Main の職員の管理の画面は、今の部品と送り手(_audio_feedback.submit_command)のままで使えるので、scenes/main/main.gd は変えていない。UI は今の部品のままで、完成の見た目ではない。

5. 見つけた既存の不具合と直し

  • 締めの後に税・利息の未払いが残ったゲームの保存が読めなかった(P05-02 からの不具合)。
    • 保存を読む時の Operations の照合(_parse_operations_runtime_snapshot)が、締めた未払いを「給与 + 維持費」だけで数え、実行中の照合(_operations_closed_arrears_total)が足している税・利息の未払い(_finance_arrears_through)を数えていなかった。
    • 見つけた経路: 帳簿の日の流れの試験で、退職金の補填で裏金が減り、2日目の締めで世界樹ランク税 70 のうち 30 が未払いになった。その後の保存を復元できなかった(診断の記録は管理のフォルダ)。退職金の無い同じ流れでは税を払いきれるので起きない。
    • 直し: 読む時の照合を実行中と同じ式(給与 + 維持費 + 税・利息の未払い)にそろえた。照合を緩めたのではなく、実行中の照合と同じにした。
    • 試験: test_general_dismissal.gd の帳簿の日の流れが、税の未払い 30 を確かめてから、締めの後の保存を復元する。再開の2段も締めの後の保存を別の process で読む。

6. 範囲の外として残すもの(主張しない)

  • 予約つきの作業を開き直した後、別の職員がその作業を取る時に、在庫の予約の操作 ID(staff.task.reserve.<作業>.<品目>)が前の予約と同じなので IDEMPOTENCY_CONFLICT で止まる(BLOCKED)。解雇でも今の remove_staff でも同じ結果になる(試験は、解雇の後の作業と在庫が今の remove_staff の結果と同じことを確かめる)。開き直しの全般の問題なので、別の単位として提案する。
  • まだ始まっていない(待ち行列の)出来事の actor の ID は、拘束を持たず、始まる時に今の規則(start_next_event の欠けた actor の扱い)で扱われる。命令の中では変えない。
  • 進行中の襲撃の防衛者の解雇(R9)は、原本の要件として未達のまま(SPEC §6.3・§8)。
  • 解雇した職員が歩いて出る描写は作らない。UI は今の部品のまま。Windows 実機は後。
  • 原単位 P16-01・P16-03 の残り(求人募集、奴隷市場・破産客からの獲得、人身売買、勤務・休息・気絶・救護の横断、解雇の経路の外の退職時の参照の除去)は未達のまま(SPEC §8)。

7. 試験

  • 新しい suite:
    • tests/staff/test_general_dismissal.gd(F1〜F9。§6 の全ての行。共通の部品は tests/helpers/p16_dismissal_fixture.gd)。最後の場面がゲームの Main を使うので、suite-policy で ordinary の音の後片付けの証明(single)を持つ。
    • 再開の2段 tests/staff/test_general_dismissal_restart_1_write.gd(唯一の生成ファイルは artifacts/p16-01-dismiss/restart-handoff.json)と ..._2_read.gd。
  • validation p16-dismiss: tools/run_p16_dismiss_tests.py。tools/run_p07_weather_tests.py から、名前・名簿・再開の段・handoff・protocol 名だけを明示の置き換えで変えた(段の手順・厳密な照合・ordinary と old_bounded の分類は同じ)。実 12 段(新しい suite 1 + 既存 9 + 再開 2)と import・parse。
  • suite-policy と marker contract に新しい3本の行を足し、今の source の SHA-256 で固定した。
  • 既存の試験の期待値の変更は EXPECTATION_CHANGES.json(kitchen の旧セーブの写しに退職金の口座を足す1件)。