Files
TheTree_mock/docs/DESIGN_DECISIONS.md
T

241 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 設計判断記録
本書はGAME_SPECIFICATION.mdで採用した重要判断と、その理由を記録する。過去案へ戻す場合は、影響範囲を確認して新しい判断を追記する。
## D-001 地上/地下とFRONT/BACKを別軸にする
- 状態: 採用
- 判断: Y軸のゾーンと、奥行きの業務レイヤーを完全に分離する。
- 理由: 旧文書では「表」が合法地上と客用空間の両方を指し、地下カジノが表施設なのか裏施設なのか判断できなかった。
- 影響: 施設はzoneとlayerを必ず別フィールドで持つ。
## D-002 主人公を従業員ユニットにしない
- 状態: 採用
- 判断: 主人公は一施設へ現場介入できる経営者として扱い、スタッフ枠を占有しない。
- 理由: 神視点の間接操作と「主人公を同室配置」の記述が矛盾していたため。
- 影響: 移動時間、個人行動ポイント、主人公能力値が必要になる。
## D-003 標準速度の1日を現実12分にする
- 状態: 採用
- 判断: 現実30秒をゲーム内1時間とする。
- 理由: 旧案の1日4分では、夕方ラッシュ、通知、シフト、関係イベントへ対応する時間が不足する。高速化はx2とx4で提供する。
- 影響: 試作GameClockと操作UIを30秒/時間、x1/x2/x4へ同期済み。
## D-004 通貨は一つ、違法性はHeatで表現する
- 状態: 採用
- 判断: 表金と裏金を分けない。
- 理由: 二重残高と資金洗浄はUI負荷が高く、建築と動線の中心体験を薄める。違法収益の代償はHeatで十分に表現できる。
- 影響: 違法サービスは収益と同時にHeatを発生させる。
## D-005 風紀度と全館清潔度を廃止する
- 状態: 採用
- 判断: 風紀度をReputation、Heat、局所治安へ分け、清潔度はセル単位にする。
- 理由: 一つの全体値が、客層、犯罪、衛生、監査を同時に動かしており原因が読めなかった。
- 影響: レポートでは局所値の集計を表示するが、ゲーム判定は可能な限り現場値を使う。
## D-006 破産結果を性別で分けない
- 状態: 採用
- 判断: 暴動、逃走、装備精算、契約化を性格、戦闘力、信用、ポリシーで決める。
- 理由: 性別固定は客AIとして不自然で、プレイヤーが結果を予測・操作できない。
- 影響: 性別は外見、好み、成人関係、妊娠可否など必要な箇所だけに用いる。
## D-007 自由雇用者は売却できない
- 状態: 採用
- 判断: 契約移転の対象は、成人隷属契約など明示状態を持つユニットだけとする。
- 理由: 旧文書内で一般従業員の売却可否が矛盾していた。
- 影響: 雇用区分と契約状態をデータで明確に分ける。
## D-008 愛の盾を好感度と別保存する
- 状態: 採用
- 判断: Shield MaxはAffectionから算出し、現在Shieldは別値として攻防に使う。
- 理由: 好感度そのものを攻撃で減らすと、長期関係と短期防御の意味が混ざる。
- 影響: Shieldは時間だけでは減らず、接触イベントでのみ損耗する。
## D-009 重要ルートは閾値だけで確定させない
- 状態: 採用
- 判断: 50と80の境界では明示イベントとプレイヤーへの予告を要求する。
- 理由: 見ていない場所の自動計算だけで取り返しのつかない結果になると、経営判断ではなく不意打ちになる。
- 影響: 関係状態は数値とイベントフラグの両方を持つ。
## D-010 決闘勝利で関係履歴を全消去しない
- 状態: 採用
- 判断: 勝利効果はRival Bond -20、Shield +30、接近禁止とする。
- 理由: 一回の勝負で長期進行を0へ戻せると、日常の配置管理が無意味になる。
- 影響: Rival Bond 80以上は通常決闘では解決できない。
## D-011 ヒロイン一人の離脱を即時ゲームオーバーにしない
- 状態: 採用
- 判断: 離脱は経営能力と物語分岐の損失として扱う。
- 理由: 20~30時間の経営ゲームで一人の自動進行が全セーブを終わらせると、実験的な経営を妨げる。
- 影響: ゲームオーバーは経営破綻、世界樹喪失、明示された最終章へ限定する。
## D-012 CorruptionとRival Bondを独立させる
- 状態: 採用
- 判断: 禁忌への適応と、特定ライバルへの関係を別軸にする。
- 理由: 地下勤務を選ぶだけで自動的にNTRへ進むと、地下経営と純愛維持を両立できない。
- 影響: 高Corruptionかつ高Affectionの忠誠型サブ分岐を許可する。
## D-013 全登場人物の成人条件をデータで保証する
- 状態: 採用
- 判断: 成人向け行為、成人労働、契約取引に関わる人物は成人確認済みフラグを必須とする。
- 理由: 世代システムと成人向け要素を同一作品で扱うため、境界を実装上も曖昧にしない必要がある。
- 影響: 未成年期は非性的な人口データのみ。成人化は明示的な時間経過後に行う。
## D-014 MVPは14日間の垂直スライスにする
- 状態: 採用
- 判断: Rank 1~3、ヒロイン1人、ライバル1人、100客を対象とする。
- 理由: 全仕様を薄く作るより、本作固有の二層動線と関係リスクが面白いかを先に検証する。
- 影響: 世代、大規模戦争、7人分のシナリオはMVP後に実装する。
## D-015 成人向けルートを設定で無効化可能にする
- 状態: 採用
- 判断: NTR、強制性の強い展開、妊娠などを個別設定する。
- 理由: プレイヤーの嗜好差が大きく、望まないルートを避ける管理負担をゲーム難易度に含めるべきではない。
- 影響: 無効化時の代替イベントを必ず用意し、進行不能にしない。
## D-016 1ゲーム分の固定TickとCommand Queueを採用する
- 状態: 採用
- 判断: Simulationの状態変更は1ゲーム分の固定Tick境界で、順序付けしたCommandを通して行う。
- 理由: 画面更新速度や入力TimingによってAI、収支、イベント結果が変わると、再現TestとSave復旧が成立しない。
- 影響: UIは状態を直接変更せずCommandを発行し、同一Tick内の処理順を固定する。
## D-017 人物移動はSoft Collisionにする
- 状態: 採用
- 判断: 通路Cellを一人だけが占有するHard Reservationではなく、密度を移動Costと速度へ反映する。
- 理由: 多人数が狭い縦動線へ集中する本作では、Hard Reservationは相互待ちと永久停止を起こしやすい。
- 影響: 混雑は視覚と効率低下で表現し、施設入口、座席、昇降機だけ明示Slotを予約する。
## D-018 在庫・料金・Service開始を原子的に処理する
- 状態: 採用
- 判断: 在庫Reservation、料金決済、Service Slot確保、状態遷移を一つのTransactionで確定する。
- 理由: 途中失敗時にItemだけ消える、料金だけ取る、座席だけ埋まる不整合を防ぐため。
- 影響: 取消は履歴削除ではなく、Reservation解除と逆取引で表現する。
## D-019 SaveはSnapshot方式を採用する
- 状態: 採用
- 判断: 全状態Snapshotと短い診断Journalを保存し、完全なEvent Sourcingは採用しない。
- 理由: 任意時点再生より、通常のSave容量、Load速度、Migrationの理解しやすさを優先する。
- 影響: 決定性確認用のCommand ReplayはTest機能として持つが、製品Saveの復元方式にはしない。
## D-020 RNGをSystem別Streamへ分離する
- 状態: 採用
- 判断: 客判断、Event、行政、戦闘、生成を別の決定的RNG Streamで処理する。
- 理由: 無関係な客が一人増えただけで監査や重要Eventの乱数結果まで変わる連鎖を避けるため。
- 影響: Seedだけでなく各StreamのStateとCounterをSaveする。
## D-021 監査は監査官の巡回と視認で判定する
- 状態: 採用
- 判断: 監査発生後の発見は全館一括抽選ではなく、監査官の移動、視線、帳簿、証言、既知証拠で判定する。
- 理由: FRONT/BACK動線と隠蔽設計を監査対策へ接続し、処罰の理由をプレイヤーが追跡できるようにする。
- 影響: 監査官はPathServiceを使い、証拠ごとに発見元と位置を保存する。
## D-022 日次の金融締めを00:00、朝の運用境界を06:00に分ける
- 状態: D-031により廃止
- 判断: 売上・原価・賃金・維持費・未払金の日次締めとDaySummary確定は日付境界の00:00に行う。06:00はシフト交代、個人AP回復、監査抽選、朝Event、その後のAutosaveだけを行う。
- 理由: 日付と財務期間の境界を一致させ、同じ売上や費用がどの日に属するかを一意にする。同時に、06:00の人物・監査処理と保存を重い金融処理から分離する。
- 影響: 23:59から00:00で保留Service確定、Ledger照合、未払判定、DaySummaryをこの順で行う。05:59から06:00のTestは財務締めを再実行しないことも検証する。
## D-023 世界樹Rankは1段階ずつ原子的に昇格する
- 状態: 採用
- 判断: Rankは条件を満たした次段階へだけ上げる。World拡張、Path再構築、GameState、進行履歴を一つの原子的境界として扱う。
- 理由: デバッグ用の直接Rank指定を製品Commandへ残すと、解禁条件を飛ばせるだけでなく、Map Boundsだけが先に広がる部分適用を起こし得るため。
- 影響: 累計Faithと累計客を現在値から分離し、昇格Requestを冪等化する。Rollback不能時は自動再試行せず隔離し、保存復旧を要求する。
## D-024 客の欲求を6軸へ統一し、安全・交流を文脈へ分離する
- 状態: 採用
- 判断: 永続する客欲求はHunger、Sleep、Hygiene、Medical、Leisure、Intimacyの6種だけとする。安全は危険評価と強制行動、交流は好み・同行者・接客・関係Eventの文脈として扱う。
- 理由: ゲーム仕様の6欲求と実装の旧5欲求が不一致で、Safetyの不安値が負傷・病気、Socialの孤独値が成人向けIntimacyと混同され得た。原因と解決施設が異なる値を同じ軸へ載せると、客の選択理由とバランス調整が読めなくなる。
- 影響: GuestService SnapshotをVersion 2へ上げる。Version 1だけは`rest→sleep`、`fun→leisure`、`social→intimacy`、`safety→medical`、`hygiene=0`として原子的に移行する。旧名は通常の生成・更新・候補入力では拒否し、Intimacyの時間帯Contextは成人確認済みDefinitionに限定する。
## D-025 境界施設は配置anchorでZoneを判定する
- 状態: 採用
- 判断: BOUNDARY施設は配置anchorを`y = 0`へ固定し、Footprintが地上側へ広がることを許可する。ただし地下側へのはみ出しは拒否する。ABOVE_GROUND/UNDERGROUND施設は全占有Cellを指定Zone内へ固定する。
- 理由: 仕様上の受付はFRONT/境界かつ4×2であり、全Cellを`y = 0`へ要求すると正規データの施設が原理的に建設不能になる。一方、地下施設の一部だけを未掘削地上へ逃がす配置は許可できない。
- 影響: Placement Previewと建設確定は同じZone規則を使い、地下CellにはZoneとは別に全Cell掘削済み条件を適用する。
## D-026 人物配置リスクPreviewは読み取り専用にする
- 状態: 採用
- 判断: 配置確定前の接触時間、Shield攻撃候補、発火可能Event、Route Lock警告、回避案は、既存状態と提案Shiftから生成する純粋なPreviewとして計算する。Previewだけで関係値やLockを変更しない。
- 理由: 画面を開いた順序や候補の比較回数で関係進行が変わると、配置判断の再現性が失われる。Route Lockは取り返しのつかない境界なので、予測結果から暗黙確定してはならない。
- 影響: 接触区間は半開区間のunionで二重計上を防ぎ、同一actor・同一shift IDの提案だけを置換する。Content Filterは表示だけを変え、risk、cost、cooldown、Lockの機械的結果は変えない。
## D-027 採用費と運営費戻しを日次分類で明示する
- 状態: 採用
- 判断: 契約時の採用費は日給と分離して運営費へ計上し、運営費の戻しは同期間費用の相殺として扱う。相殺超過だけをexpense recovery収益へ振り替える。
- 理由: 採用費を賃金へ入れるとStaffの日次発生額と二重計上になり、運営費戻しを客向け返金へ入れると符号が逆になる。どちらもunknown categoryのままでは正常な雇用後の日次締めが停止する。
- 影響: `STAFF_SIGNING_COST→cost_of_goods`、`OPERATING_REFUND→cost_of_goods相殺`を固定し、相殺超過はanomaly付きで`revenue`へ入れる。それ以外の未知categoryはfail-closedを維持する。
## D-028 通路施設は副占有からPathへ投影し、未完成の垂直Topologyを推測しない
- 状態: 採用
- 判断: 客用通路と業務用通路は主要施設占有と共存する`ROUTE` subslotとして実Pathへ投影する。従業員ドアは職員権限付きFRONT↔BACK Connectorにする。昇降機は、同階隣接Edgeを安全に抑制する垂直Topologyが完成するまで明示的に無変更拒否する。
- 理由: 通路proxyを主要占有だけで完成扱いにすると、地図には存在しても移動不能になる。一方、現在の平面Graphへ昇降機Connectorだけを足すと、通常隣接Edgeが待ち時間や停止状態を迂回し、運行規則が無効になる。
- 影響: 建設完成・撤去はProjectorを通してSpatial、Path、Connectorを一つの原子的境界として更新する。未対応昇降機は`UNSUPPORTED_VERTICAL_TOPOLOGY`を返し、どの依存状態も変更しない。
次の実装契約(未実装):
- `PathService`の通常WALK Edgeは同じ`y`の`x±1`だけとし、`y`が変わる移動は明示Connectorだけに限定する。実A*、到達不能理由の診断探索、復旧地点検索に同じ規則を適用し、別階への暗黙テレポート候補を作らない。
- 客用/業務用昇降機は回転0度に固定し、同じ`x`・同じFRONT/BACK内の`origin → origin + (0, 1, 0)`を双方向ELEVATOR Connectorにする。全FootprintはROUTEとして各階から乗降点へ到達可能にする。
- 客用はFRONT、容量4、待機8、1階10分、一般利用。業務用はBACK、容量8、待機16、1階5分、`staff`権限とする。停止・停電中も通常WALKで迂回できてはならない。
- 待機列、現在階、CabinState、運行状態は`PathService`所有の可変値とし、ProjectorはID、端点、権限、容量、所要時間など不変部分だけを照合する。乗車中または待機中の撤去は無変更拒否する。
- 保存意味が変わるため、Path v4、Projector v2、Runtime v7として明示移行する。v6に存在し得る未投影の完成昇降機は、v7移行時に安定IDで投影し、片側だけ生成された状態を許可しない。
- maintenance Mana 5/6を実Consumerへ登録し、Brownout/OUTAGEをConnector運行状態へ同期する。完成・撤去・停電・Save復元はConstruction、World、Spatial、Path、Mana、通知を一つのrollback境界で検証する。
## D-029 境界PauseはTickのhard stopとして扱う
- 状態: 採用
- 判断: catch-up中の境界失敗、rollback隔離、日次照合待ち、破綻がPauseを要求したら、同一Frameの残りTickと次の時刻加算を止める。境界分までClockが進んだ失敗は、その分の後続段階だけを再開時に1回実行する。
- 理由: Pause flagだけを立てて既に算出したTick数を走らせると、Coordinatorの保留分とClockがずれ、保存不能になる。Clockを巻き戻すと、先に確定したCommandと通知の時刻が過去へ取り残される。
- 影響: running中のCommandは到達予定分をeffective minuteとしてClock加算前に確定する。速度変更と手動stepはhard stopを解除せず、再開は専用の確認境界を通す。
## D-030 複数DomainEventは履歴確定後に一括配信する
- 状態: 採用
- 判断: Transactionが生成したDomainEventは全件を先に検証・履歴Commitし、その後で固定順にSubscriberへ配る。配信中の再入EventはBatch末尾へ送る。
- 理由: 1件ずつ検証と通知を交互に行うと、後続ID衝突時に先行通知だけが外へ残り、状態rollback後の再試行で二重通知になる。
- 影響: UIと不可逆な外部処理はService固有signalではなくCommit済みDomainEventまたはTick Snapshotを使う。Batch拒否は履歴・通知とも無変更となる。
## D-031 営業日と日次決算の境界を06:00に統合する
- 状態: 採用
- 判断: 暦日は00:00に更新する一方、宿の営業日は06:00から翌日05:59までとする。日次決算は翌06:00に行い、その後に昼番開始、個人AP回復、監査抽選、朝Event、Autosaveを処理する。
- 理由: 夜間の宿泊、酒場、地下営業を途中の00:00で分断せず、一続きの夜営業として同じDaySummaryへ含める。朝昼営業と夜営業の交代時に会計と運営判断をまとめる方が、宿の経営感覚と一致する。
- 影響: DaySummaryの期間は`Day N 06:00 <= minute < Day N+1 06:00`となる。05:59から06:00の境界では財務締めを最初に一度だけ確定し、失敗時は昼番開始以降を保留する。旧D-022は廃止する。
## D-032 通常UIの配属は継続計画と勤務実績を分けて保存する
- 状態: 採用(2026-09-09。通常開業の単日受入・保存復元を確認。3営業日を含むP1全体は未合格)
- 判断: 通常UIから行う施設配属と勤務帯変更は、従業員ごとの `DAY`/`NIGHT` 継続計画 `work_assignments` として保存する。計画から以後の日次出勤に必要な具体的Shiftを決定的に生成し、毎朝プレイヤーが同じ配属をやり直す必要をなくす。未配属は施設IDを空にした明示計画として扱う。
- 理由: 雇用時や単日Shiftの一度きりの指定だけでは翌営業日の出勤が途切れる。一方、再配属で既存Shiftの施設を直接書き換えると、過去の勤務時間と日次給与の施設別配賦まで新しい配属先へ移り、決算と保存再開の整合が崩れる。
- 勤務履歴: 配属変更時に、進行中Shiftは変更時刻で区切って旧施設・既勤務区間を保持する。過去のShiftは書き換えない。未開始の旧予定は取消し、新しい計画の有効区間を別Shiftとして作る。日付をまたぐ夜勤も同じ区間規則を使い、実績時間を重複計上しない。
- 操作境界: UIは `set_staff_work_assignment` Commandを送り、Runtimeで施設、役割、定員、到達経路、勤務変更可能状態を検証してから確定する。変更後の将来予定に旧単日Overrideが残って以前の配属へ戻ることを防ぐ。作業中など変更を受け付けられない場合は、理由を表示して状態を維持する。
- 保存互換: StaffService Snapshotをversion 4とし、継続計画を保存する。旧version 3の保存は計画なしで読み込み、既存の人物・単日Shift・給与履歴を保持する。旧保存の最終勤務先を推測して全員へ繰返し予定を付与しない。読み込み後に通常UIで配属を指定した人物から、新しい継続計画を使う。
- 影響: 翌日出勤、再配属、夜勤の日付跨ぎ、未配属、作業中拒否、途中Save復元を受入へ含める。施設別給与は保存した実勤務区間を根拠とし、現在の計画だけから過去分を再分類しない。
- 今回の範囲外: 施設価格、受付の直接収入、宿泊料金の決済・売上記帳タイミングは改定しない。開業ガイドと帳簿は現在のサービス・台帳・06:00決算を読み取って表示する。これらと仕様正本の照合・変更はPLAY-04/PLAY-05で別に判断する。