Merge commit 'bd3a97ec741ddb2346d0c2b2e0472c978927ce82' into HEAD
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
# P13-03 内容差異台帳
|
||||
|
||||
記録の提出であり、ゲーム内容・P13パッケージの完成認定ではない。原30パッケージ/88成果、部分点なし。原子・状態台帳は変更しない。
|
||||
|
||||
通常入口、Runtime、イベント状態、保存、試験はすべて静的観測・未検証。汎用処理は原施設固有の接続や完成素材を証明しない。
|
||||
|
||||
機械台帳のshared_text/text_refとshared_evidence/evidence_refは重複証拠の共有参照。検索語、一致行番号・全文、相対出典パス、SHAを省略せず保持し、チェッカーは全参照と本文を照合する。作業計画は契約baseのGit blobを固定入力として検証する。別管理の現行進捗は内容完成の証拠にしない。
|
||||
|
||||
施設の原典IDは旧対応表の1始まりの位置を保持する。現行の data/facilities 全定義とカタログを名前・既存IDで再検索した。マナ制御室をマナ炉に代用しない。
|
||||
|
||||
|原典ID|章|原典名|現行定義候補|使用スロット数|完成素材・原内容|
|
||||
|---|---|---|---|---|---|
|
||||
|original_facility_13|10.4|風俗個室|adult_private_room|12|未検証|
|
||||
|original_facility_14|10.4|高級ソープ|対象検索範囲で欠落|12|未検証|
|
||||
|original_facility_15|10.4|SM拷問室|対象検索範囲で欠落|12|未検証|
|
||||
|original_facility_16|10.4|闇市場|black_market|12|未検証|
|
||||
|original_facility_24|10.6|覗き部屋|対象検索範囲で欠落|12|未検証|
|
||||
|original_facility_25|10.6|地下牢|対象検索範囲で欠落|12|未検証|
|
||||
|original_facility_26|10.6|マナ炉|対象検索範囲で欠落|12|未検証|
|
||||
|
||||
風俗個室は通常UIリストとRuntime読込元に候補がある。闇市場は拡張定義のみで通常読込元に含まれない。他の5施設は対象定義集合で対応が見つからない。実行・保存再開・施設固有イベントの受入は未検証。
|
||||
|
||||
## 施設別の観測と使用スロット
|
||||
|
||||
共有観測範囲(各施設の具体的検索結果は機械台帳に保持):
|
||||
|
||||
- normal_entry: adult_private_room is in the UI list and baseline catalog; black_market is expansion-only. No other original identity match. Static eligibility only; actual construction is unverified.
|
||||
- runtime: Runtime loads ORIGINAL_FACILITY_PATHS, including some files under the expansion directory. It does not load EXPANSION_FACILITY_PATHS or black_market. Generic services do not prove original special behavior.
|
||||
- event_state: No facility-specific transition established by this search. Generic EventService is not a dedicated content catalog.
|
||||
- save: Generic snapshot plumbing is a technical lead only. Facility event round-trip and original semantics remain unverified.
|
||||
- test: Selected generic suite sources searched; no formal suite run or dedicated original facility acceptance inferred.
|
||||
|
||||
共有出典・検索語はshared_contextのsource_ref/search_refから復元する。各施設の各観測は個別に参照し、合格接続を意味しない。
|
||||
|
||||
### original_facility_13 / 風俗個室
|
||||
|
||||
- normal_entry: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- runtime: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- event_state: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- save: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- test: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
|
||||
使用スロット(すべて unverified_required_slot、approved_asset=null):
|
||||
|
||||
- `adult_private_room.lv1.front.exterior`
|
||||
- `adult_private_room.lv1.front.interior`
|
||||
- `adult_private_room.lv1.back.exterior`
|
||||
- `adult_private_room.lv1.back.interior`
|
||||
- `adult_private_room.lv2.front.exterior`
|
||||
- `adult_private_room.lv2.front.interior`
|
||||
- `adult_private_room.lv2.back.exterior`
|
||||
- `adult_private_room.lv2.back.interior`
|
||||
- `adult_private_room.lv3.front.exterior`
|
||||
- `adult_private_room.lv3.front.interior`
|
||||
- `adult_private_room.lv3.back.exterior`
|
||||
- `adult_private_room.lv3.back.interior`
|
||||
|
||||
実制作資産数はunknown/null。スロット数を画像数に転用しない。
|
||||
|
||||
### original_facility_14 / 高級ソープ
|
||||
|
||||
- normal_entry: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- runtime: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- event_state: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- save: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- test: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
|
||||
使用スロット(すべて unverified_required_slot、approved_asset=null):
|
||||
|
||||
- `original_facility_14.lv1.front.exterior`
|
||||
- `original_facility_14.lv1.front.interior`
|
||||
- `original_facility_14.lv1.back.exterior`
|
||||
- `original_facility_14.lv1.back.interior`
|
||||
- `original_facility_14.lv2.front.exterior`
|
||||
- `original_facility_14.lv2.front.interior`
|
||||
- `original_facility_14.lv2.back.exterior`
|
||||
- `original_facility_14.lv2.back.interior`
|
||||
- `original_facility_14.lv3.front.exterior`
|
||||
- `original_facility_14.lv3.front.interior`
|
||||
- `original_facility_14.lv3.back.exterior`
|
||||
- `original_facility_14.lv3.back.interior`
|
||||
|
||||
実制作資産数はunknown/null。スロット数を画像数に転用しない。
|
||||
|
||||
### original_facility_15 / SM拷問室
|
||||
|
||||
- normal_entry: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- runtime: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- event_state: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- save: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- test: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
|
||||
使用スロット(すべて unverified_required_slot、approved_asset=null):
|
||||
|
||||
- `original_facility_15.lv1.front.exterior`
|
||||
- `original_facility_15.lv1.front.interior`
|
||||
- `original_facility_15.lv1.back.exterior`
|
||||
- `original_facility_15.lv1.back.interior`
|
||||
- `original_facility_15.lv2.front.exterior`
|
||||
- `original_facility_15.lv2.front.interior`
|
||||
- `original_facility_15.lv2.back.exterior`
|
||||
- `original_facility_15.lv2.back.interior`
|
||||
- `original_facility_15.lv3.front.exterior`
|
||||
- `original_facility_15.lv3.front.interior`
|
||||
- `original_facility_15.lv3.back.exterior`
|
||||
- `original_facility_15.lv3.back.interior`
|
||||
|
||||
実制作資産数はunknown/null。スロット数を画像数に転用しない。
|
||||
|
||||
### original_facility_16 / 闇市場
|
||||
|
||||
- normal_entry: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- runtime: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- event_state: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- save: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- test: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
|
||||
使用スロット(すべて unverified_required_slot、approved_asset=null):
|
||||
|
||||
- `black_market.lv1.front.exterior`
|
||||
- `black_market.lv1.front.interior`
|
||||
- `black_market.lv1.back.exterior`
|
||||
- `black_market.lv1.back.interior`
|
||||
- `black_market.lv2.front.exterior`
|
||||
- `black_market.lv2.front.interior`
|
||||
- `black_market.lv2.back.exterior`
|
||||
- `black_market.lv2.back.interior`
|
||||
- `black_market.lv3.front.exterior`
|
||||
- `black_market.lv3.front.interior`
|
||||
- `black_market.lv3.back.exterior`
|
||||
- `black_market.lv3.back.interior`
|
||||
|
||||
実制作資産数はunknown/null。スロット数を画像数に転用しない。
|
||||
|
||||
### original_facility_24 / 覗き部屋
|
||||
|
||||
- normal_entry: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- runtime: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- event_state: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- save: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- test: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
|
||||
使用スロット(すべて unverified_required_slot、approved_asset=null):
|
||||
|
||||
- `original_facility_24.lv1.front.exterior`
|
||||
- `original_facility_24.lv1.front.interior`
|
||||
- `original_facility_24.lv1.back.exterior`
|
||||
- `original_facility_24.lv1.back.interior`
|
||||
- `original_facility_24.lv2.front.exterior`
|
||||
- `original_facility_24.lv2.front.interior`
|
||||
- `original_facility_24.lv2.back.exterior`
|
||||
- `original_facility_24.lv2.back.interior`
|
||||
- `original_facility_24.lv3.front.exterior`
|
||||
- `original_facility_24.lv3.front.interior`
|
||||
- `original_facility_24.lv3.back.exterior`
|
||||
- `original_facility_24.lv3.back.interior`
|
||||
|
||||
実制作資産数はunknown/null。スロット数を画像数に転用しない。
|
||||
|
||||
### original_facility_25 / 地下牢
|
||||
|
||||
- normal_entry: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- runtime: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- event_state: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- save: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- test: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
|
||||
使用スロット(すべて unverified_required_slot、approved_asset=null):
|
||||
|
||||
- `original_facility_25.lv1.front.exterior`
|
||||
- `original_facility_25.lv1.front.interior`
|
||||
- `original_facility_25.lv1.back.exterior`
|
||||
- `original_facility_25.lv1.back.interior`
|
||||
- `original_facility_25.lv2.front.exterior`
|
||||
- `original_facility_25.lv2.front.interior`
|
||||
- `original_facility_25.lv2.back.exterior`
|
||||
- `original_facility_25.lv2.back.interior`
|
||||
- `original_facility_25.lv3.front.exterior`
|
||||
- `original_facility_25.lv3.front.interior`
|
||||
- `original_facility_25.lv3.back.exterior`
|
||||
- `original_facility_25.lv3.back.interior`
|
||||
|
||||
実制作資産数はunknown/null。スロット数を画像数に転用しない。
|
||||
|
||||
### original_facility_26 / マナ炉
|
||||
|
||||
- normal_entry: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- runtime: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- event_state: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- save: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
- test: unverified(検索語・一致行本文・出典SHAは機械台帳参照)
|
||||
|
||||
使用スロット(すべて unverified_required_slot、approved_asset=null):
|
||||
|
||||
- `original_facility_26.lv1.front.exterior`
|
||||
- `original_facility_26.lv1.front.interior`
|
||||
- `original_facility_26.lv1.back.exterior`
|
||||
- `original_facility_26.lv1.back.interior`
|
||||
- `original_facility_26.lv2.front.exterior`
|
||||
- `original_facility_26.lv2.front.interior`
|
||||
- `original_facility_26.lv2.back.exterior`
|
||||
- `original_facility_26.lv2.back.interior`
|
||||
- `original_facility_26.lv3.front.exterior`
|
||||
- `original_facility_26.lv3.front.interior`
|
||||
- `original_facility_26.lv3.back.exterior`
|
||||
- `original_facility_26.lv3.back.interior`
|
||||
|
||||
実制作資産数はunknown/null。スロット数を画像数に転用しない。
|
||||
|
||||
## 施設外の内容差異
|
||||
|
||||
- `P13-03.event` (B-1.6, B-2.5, B-8.2, B-8.3): Required original presentation/content is not accepted by generic state processing. Final catalog, variants, production quantities and ownership remain unknown.
|
||||
- `P13-03.overlay` (B-2.5): Required original presentation/content is not accepted by generic state processing. Final catalog, variants, production quantities and ownership remain unknown.
|
||||
- `P13-03.history` (B-1.6): Required original presentation/content is not accepted by generic state processing. Final catalog, variants, production quantities and ownership remain unknown.
|
||||
- `P13-03.story` (B-1.6): Required original presentation/content is not accepted by generic state processing. Final catalog, variants, production quantities and ownership remain unknown.
|
||||
- `P13-03.voice` (B-1.6): Required original presentation/content is not accepted by generic state processing. Final catalog, variants, production quantities and ownership remain unknown.
|
||||
- `P13-03.scene` (B-1.6): Required original presentation/content is not accepted by generic state processing. Final catalog, variants, production quantities and ownership remain unknown.
|
||||
|
||||
event/overlay/history/story/voice/scene の内容ID・数量・受入はunknownまたは未検証。D08(内容範囲)/D09(品質・量・担当・権利)は未決定。中立メタデータのみを記録し、場面は制作・描写しない。
|
||||
|
||||
## 出典・適用範囲
|
||||
|
||||
機械台帳に各観測の検索語・一致行・本文・実SHAを保持する。旧対応表は原典識別に利用し、現行対応は再検索で記録する。素材台帳は使用スロットと候補の証拠のみ。inventory_summaryの290 media files、0 audio files、360 slots、0 approved assetsは既存監査の限定集計であり、最終必要量を示さない。
|
||||
|
||||
- `docs/traceability/original/BASELINE.txt` / current_checkout / SHA256 `75e4bdbdeb379c9269553f0c776bdb9cc96e01f2d6aa5ca650d132c63a8aeb1a`
|
||||
- `docs/plans/original-completion-2026-10-02/work_packages.json` / base_git_blob / SHA256 `bc87ec52b4913e890fb61ad99b641dd693c0b272dbb1fab347d860118e4bd4af`
|
||||
- `docs/plans/original-completion-2026-09-29/execution/original_facility_mapping.json` / current_checkout / SHA256 `df0c933220449c8bb3e0fd942ad6f1dee49075abdd6587c4856022e12e3665cf`
|
||||
- `docs/plans/original-completion-2026-10-02/asset_inventory_reaudit/facility_usage_slots.json` / current_checkout / SHA256 `56a031b6430aa9cb408f14b66efc5dd9a779841c0e7c19301945c49c12711491`
|
||||
- `docs/plans/original-completion-2026-10-02/asset_inventory_reaudit/inventory_summary.json` / current_checkout / SHA256 `298b37e65c41febe8a2ccdea10bd105ab7a606904f06b16c1659cda6214859b9`
|
||||
- `docs/plans/original-completion-2026-10-02/decisions.json` / current_checkout / SHA256 `ad0673051b0fa601e525f05128e0b11e2dddd9d4bae6a3e0170bbf47da35efe9`
|
||||
- `autoload/simulation_runtime.gd` / main_git_blob / SHA256 `4696df4a77feb465a5a3ba8b806569f7bcbe1d03c88289acfb78a3928f307d67`
|
||||
- `data/facilities/adult_private_room.tres` / current_checkout / SHA256 `d8501586416b5c57a8b3b3b2afd1c0143428d8a4fa1df7112e995bd36649df6d`
|
||||
- `data/facilities/cafeteria.tres` / current_checkout / SHA256 `86d540fe2d78b9dcdbe5a0af6e4a001f4cec54934636ed01deb25a943c79128a`
|
||||
- `data/facilities/expansion/black_market.tres` / current_checkout / SHA256 `c209d734c82487f6df4c03714618865d6a5f1d2cf991dc0056fe4bbad8f03a42`
|
||||
- `data/facilities/expansion/chapel.tres` / current_checkout / SHA256 `9b30a7c51712e7bb99c17870d1f03e3429ea9279851d88284545bb2eb5042fcb`
|
||||
- `data/facilities/expansion/cleaning_room.tres` / current_checkout / SHA256 `ae366cf67cbf117db7989c6b76092eb5a65229b93d35999a40d19b8260f95ad8`
|
||||
- `data/facilities/expansion/clinic.tres` / current_checkout / SHA256 `339cf22c68d7ab3cb1514b9e8d2ea63dc0772fe93918d70767c11cf7b6ee0e16`
|
||||
- `data/facilities/expansion/cold_storage.tres` / current_checkout / SHA256 `1aac824147b52b41e124d2ab2ce63c3bac58de2ec7fc447a5806a1cf9fa9ad99`
|
||||
- `data/facilities/expansion/general_store.tres` / current_checkout / SHA256 `76872e0375648b43f05fdc5581ccabe4aa6a166674c3b523980dd1cf0b6e6dc1`
|
||||
- `data/facilities/expansion/guild_counter.tres` / current_checkout / SHA256 `93e8736da4aab8a17b1c8e7831c9a7b8de7f32d0ec251aa9aa5c8cf859c8fd7b`
|
||||
- `data/facilities/expansion/laundry.tres` / current_checkout / SHA256 `2518ea2e5da12cf4f2997502bf50f00dd8145caca153fb3486b44b99881fdab4`
|
||||
- `data/facilities/expansion/maintenance_workshop.tres` / current_checkout / SHA256 `8bd10332a9f45a252febdc626f22f90507317fb4cff5b18b2526aacd1f1a176b`
|
||||
- `data/facilities/expansion/mana_control_room.tres` / current_checkout / SHA256 `55e4c52a049ff61ddf3d081ccb990a8572b64bc7cf37d3a0d52ca5a08cc32f25`
|
||||
- `data/facilities/expansion/premium_room.tres` / current_checkout / SHA256 `6665090e041f36df5809314cd171be228a94bf77d7e93f5b70be648db4705d98`
|
||||
- `data/facilities/expansion/private_bath.tres` / current_checkout / SHA256 `241b807e7fa3a1b9dc4bda0d2495e637155cdaea89a4234e37a121f00098499c`
|
||||
- `data/facilities/expansion/secret_tavern.tres` / current_checkout / SHA256 `f0a1372931078fa0f93dd5b9cec6df6b137975479aa706633fdf6a9be4cf1f62`
|
||||
- `data/facilities/expansion/staff_dormitory.tres` / current_checkout / SHA256 `8d7c7cd6dfe98d137f7fef62e35eb31f82f1ca282216a40df54ac81728101271`
|
||||
- `data/facilities/expansion/tea_lounge.tres` / current_checkout / SHA256 `77d1ace36c5e84f80c0e6d563ae973c7ff1cd12b56956afd4895cdcdd5771a67`
|
||||
- `data/facilities/expansion/underground_guest_room.tres` / current_checkout / SHA256 `cdfd0f8cd21812a9972485926dff27daaa6718af16aac1651894728b087bef9e`
|
||||
- `data/facilities/expansion/vip_private_salon.tres` / current_checkout / SHA256 `1c94a7a70393262fba82112c3f4a0cb67ad22728664f5ca408f450049d3657a7`
|
||||
- `data/facilities/expansion/waste_processing.tres` / current_checkout / SHA256 `9954855c7a07e425376a220c589989beb6ec95da3c5331316ef3615a60b45f1d`
|
||||
- `data/facilities/guest_corridor.tres` / current_checkout / SHA256 `d77ccf267e20a26ed70527d29e8d54e6fcab1df213f02d5a4e28ead4f705276b`
|
||||
- `data/facilities/guest_elevator.tres` / current_checkout / SHA256 `ad4fb3c439ac4ed90fe52f07e29ed7b4ff654c54d1c400c7c8e226da77127af7`
|
||||
- `data/facilities/infrastructure/guest_stairs.tres` / current_checkout / SHA256 `757c687b1ebe2a3f237fb28092cd5f01591f15b2bcd1b4e639042a24635a92c6`
|
||||
- `data/facilities/infrastructure/service_stairs.tres` / current_checkout / SHA256 `637217d867bcc99669d27c54b6d2c391c82a4a17356ab9a80c897ccaee38622c`
|
||||
- `data/facilities/kitchen.tres` / current_checkout / SHA256 `38197aa8a3e90c03a82e9ccdc88bb444af4eeb0349c41a39e0bdd7b188e7d5d3`
|
||||
- `data/facilities/massage_room.tres` / current_checkout / SHA256 `75ecf845fb3cfa8d3150f6b0dc90e901953469af512611384b70cc4878d21e85`
|
||||
- `data/facilities/public_bath.tres` / current_checkout / SHA256 `8ec259f48ed75c8ab2e5154a1caccf19f6be04331adbe774b877f0a2d8b2f778`
|
||||
- `data/facilities/reception.tres` / current_checkout / SHA256 `bed3de120a0e98c539771d1bb189111d095712f8ae25dfdf7cb2983efc0dee9f`
|
||||
- `data/facilities/rescue/infirmary.tres` / current_checkout / SHA256 `c3e861533971e369068ae9e42f71b660fa4ab3893c7c1f798fc367893befd943`
|
||||
- `data/facilities/security_station.tres` / current_checkout / SHA256 `69f3f518df7714d00c8e954e9c7405aa44b683dd274181cc3da832cc956815b3`
|
||||
- `data/facilities/service_corridor.tres` / current_checkout / SHA256 `5d79fbde201d657740efcba924f595bd7075e069b344d708e424dbebbdc2f254`
|
||||
- `data/facilities/service_elevator.tres` / current_checkout / SHA256 `35d552d5b96065413feccb50847e3cd7173e673896ce65afba238f90abc25132`
|
||||
- `data/facilities/staff_door.tres` / current_checkout / SHA256 `a993058bfd809ccdbbb9a61b9850259d7bf6e60003e57ccfa3972f6c29170752`
|
||||
- `data/facilities/staff_waiting_room.tres` / current_checkout / SHA256 `5c7a2f7f7c508102c4ee89401ad6348191b57d1ff65538acb9d450e464a3a46f`
|
||||
- `data/facilities/standard_room.tres` / current_checkout / SHA256 `89f0a3a861d66afa4c1338ff1ec919685cf338b93b8da9a2387ce85e7e5bc336`
|
||||
- `data/facilities/tavern.tres` / current_checkout / SHA256 `eb494ae6ab0d1b9e88ae0a38944609702e43c81a370a29cfb030af9ae46f523c`
|
||||
- `data/facilities/warehouse.tres` / current_checkout / SHA256 `d0fcf0528da66da7b354ab5efaafe2483a7a76e05b324db255700ef73cdfc791`
|
||||
- `scenes/main/main.gd` / main_git_blob / SHA256 `92677e4ac57ed8d418a4a716bf0874cbbaea79cff893e5163c82ad1f75e7140a`
|
||||
- `scripts/core/save_service.gd` / current_checkout / SHA256 `0c158d3e6ee693b89814bf232c954e4757c5ff91dc9df03bb322c3e593e73617`
|
||||
- `scripts/data/facility_catalog.gd` / current_checkout / SHA256 `7bb0c5085ddb361d384314cb219620d1483840942bc3f0f46dcb9dfa29d56e29`
|
||||
- `scripts/events/event_definition.gd` / current_checkout / SHA256 `4af68f2e5ec185a750d59aaa24c7cb63fe612cd6a785e7fd39af11f0b5ce74a2`
|
||||
- `scripts/events/event_service.gd` / current_checkout / SHA256 `d58c416d7a1126b36023fa6ba9f02338678bd54426a3b5d04ce511d9a48c0103`
|
||||
- `scripts/ui/event_log_dialog.gd` / current_checkout / SHA256 `62000f559c49c3a58b244b991c10c1738add10702bfa66cb7cb40798cb559290`
|
||||
- `tests/s2/test_facility_service.gd` / current_checkout / SHA256 `4b834f1d9d9ab2ad00cb4a56f5202b70468bfe5f71318dbf816da1e29cc32690`
|
||||
- `tests/s4/test_runtime_relationship_events.gd` / current_checkout / SHA256 `466f9a40b3471a9bb39c670cdd1106e990d297bc8bfff0db557cd63bb74c8ef3`
|
||||
- `tests/s6/test_runtime_snapshot_serialization.gd` / current_checkout / SHA256 `d9106f9defb6cc195b969ff040d24f1f8ceebe055ba66c39d4634a68620cde84`
|
||||
|
||||
## 統合監査注記
|
||||
|
||||
- The two target sources are immutable main Git blobs at 57131ec616ba06a71d3d97eaea738f209f965349. Matches are re-searched from those bytes with main_git_blob provenance.
|
||||
- Read-only Git ancestry determines applicability: descendant HEAD requires working files equal to main blobs; non-descendant HEAD requires base blobs. Git errors reject. Report flags cannot select a mode.
|
||||
- Other current-checkout checks remain strict; work packages remain frozen at the contract base. All unknown/unverified states and 30/88 accounting remain unchanged.
|
||||
- Formal Runner validation and separate independent review remain external requirements; static observations confer no content completion credit.
|
||||
|
||||
## 検証・統合条件
|
||||
|
||||
`python -B tools/check_p13_content_difference.py --verify-only` は記録整合性と欠落・重複・古いpin・誤完成・技術から内容への昇格・unknownのゼロ化・共有参照改変等の拒否を必ず検証する。--negative-checksも互換引数として保持する。workerのローカル診断は正式受入ではない。Runner正式validatorと別セッションの正式Claudeレビュー合格後にのみ統合できる。
|
||||
|
||||
Runtime/native/Windows/engine/full game regressionは記録だけの変更に適用外(製品コード・資産・保存形式・値の変更なし)。この適用外をゲームの合格に転用しない。Kenney・fallback・mockup・コード候補・ファイル存在・状態試験から完成資産を推定しない。
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,464 @@
|
||||
{
|
||||
"task_id": "P13-03",
|
||||
"acceptance_ids": [
|
||||
"P13-03"
|
||||
],
|
||||
"validation_ids": [
|
||||
"p13-difference"
|
||||
],
|
||||
"requirement_ids": [
|
||||
"B-1.6",
|
||||
"B-2.5",
|
||||
"B-8.2",
|
||||
"B-8.3",
|
||||
"B-10.4",
|
||||
"B-10.6"
|
||||
],
|
||||
"facility_ids": [
|
||||
"original_facility_13",
|
||||
"original_facility_14",
|
||||
"original_facility_15",
|
||||
"original_facility_16",
|
||||
"original_facility_24",
|
||||
"original_facility_25",
|
||||
"original_facility_26"
|
||||
],
|
||||
"slot_ids": [
|
||||
"adult_private_room.lv1.front.exterior",
|
||||
"adult_private_room.lv1.front.interior",
|
||||
"adult_private_room.lv1.back.exterior",
|
||||
"adult_private_room.lv1.back.interior",
|
||||
"adult_private_room.lv2.front.exterior",
|
||||
"adult_private_room.lv2.front.interior",
|
||||
"adult_private_room.lv2.back.exterior",
|
||||
"adult_private_room.lv2.back.interior",
|
||||
"adult_private_room.lv3.front.exterior",
|
||||
"adult_private_room.lv3.front.interior",
|
||||
"adult_private_room.lv3.back.exterior",
|
||||
"adult_private_room.lv3.back.interior",
|
||||
"original_facility_14.lv1.front.exterior",
|
||||
"original_facility_14.lv1.front.interior",
|
||||
"original_facility_14.lv1.back.exterior",
|
||||
"original_facility_14.lv1.back.interior",
|
||||
"original_facility_14.lv2.front.exterior",
|
||||
"original_facility_14.lv2.front.interior",
|
||||
"original_facility_14.lv2.back.exterior",
|
||||
"original_facility_14.lv2.back.interior",
|
||||
"original_facility_14.lv3.front.exterior",
|
||||
"original_facility_14.lv3.front.interior",
|
||||
"original_facility_14.lv3.back.exterior",
|
||||
"original_facility_14.lv3.back.interior",
|
||||
"original_facility_15.lv1.front.exterior",
|
||||
"original_facility_15.lv1.front.interior",
|
||||
"original_facility_15.lv1.back.exterior",
|
||||
"original_facility_15.lv1.back.interior",
|
||||
"original_facility_15.lv2.front.exterior",
|
||||
"original_facility_15.lv2.front.interior",
|
||||
"original_facility_15.lv2.back.exterior",
|
||||
"original_facility_15.lv2.back.interior",
|
||||
"original_facility_15.lv3.front.exterior",
|
||||
"original_facility_15.lv3.front.interior",
|
||||
"original_facility_15.lv3.back.exterior",
|
||||
"original_facility_15.lv3.back.interior",
|
||||
"black_market.lv1.front.exterior",
|
||||
"black_market.lv1.front.interior",
|
||||
"black_market.lv1.back.exterior",
|
||||
"black_market.lv1.back.interior",
|
||||
"black_market.lv2.front.exterior",
|
||||
"black_market.lv2.front.interior",
|
||||
"black_market.lv2.back.exterior",
|
||||
"black_market.lv2.back.interior",
|
||||
"black_market.lv3.front.exterior",
|
||||
"black_market.lv3.front.interior",
|
||||
"black_market.lv3.back.exterior",
|
||||
"black_market.lv3.back.interior",
|
||||
"original_facility_24.lv1.front.exterior",
|
||||
"original_facility_24.lv1.front.interior",
|
||||
"original_facility_24.lv1.back.exterior",
|
||||
"original_facility_24.lv1.back.interior",
|
||||
"original_facility_24.lv2.front.exterior",
|
||||
"original_facility_24.lv2.front.interior",
|
||||
"original_facility_24.lv2.back.exterior",
|
||||
"original_facility_24.lv2.back.interior",
|
||||
"original_facility_24.lv3.front.exterior",
|
||||
"original_facility_24.lv3.front.interior",
|
||||
"original_facility_24.lv3.back.exterior",
|
||||
"original_facility_24.lv3.back.interior",
|
||||
"original_facility_25.lv1.front.exterior",
|
||||
"original_facility_25.lv1.front.interior",
|
||||
"original_facility_25.lv1.back.exterior",
|
||||
"original_facility_25.lv1.back.interior",
|
||||
"original_facility_25.lv2.front.exterior",
|
||||
"original_facility_25.lv2.front.interior",
|
||||
"original_facility_25.lv2.back.exterior",
|
||||
"original_facility_25.lv2.back.interior",
|
||||
"original_facility_25.lv3.front.exterior",
|
||||
"original_facility_25.lv3.front.interior",
|
||||
"original_facility_25.lv3.back.exterior",
|
||||
"original_facility_25.lv3.back.interior",
|
||||
"original_facility_26.lv1.front.exterior",
|
||||
"original_facility_26.lv1.front.interior",
|
||||
"original_facility_26.lv1.back.exterior",
|
||||
"original_facility_26.lv1.back.interior",
|
||||
"original_facility_26.lv2.front.exterior",
|
||||
"original_facility_26.lv2.front.interior",
|
||||
"original_facility_26.lv2.back.exterior",
|
||||
"original_facility_26.lv2.back.interior",
|
||||
"original_facility_26.lv3.front.exterior",
|
||||
"original_facility_26.lv3.front.interior",
|
||||
"original_facility_26.lv3.back.exterior",
|
||||
"original_facility_26.lv3.back.interior"
|
||||
],
|
||||
"difference_ids": [
|
||||
"P13-03.event",
|
||||
"P13-03.overlay",
|
||||
"P13-03.history",
|
||||
"P13-03.story",
|
||||
"P13-03.voice",
|
||||
"P13-03.scene"
|
||||
],
|
||||
"source_applicability_records": [
|
||||
{
|
||||
"path": "docs/traceability/original/BASELINE.txt",
|
||||
"sha256": "75e4bdbdeb379c9269553f0c776bdb9cc96e01f2d6aa5ca650d132c63a8aeb1a",
|
||||
"applicability": "current_checkout"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/work_packages.json",
|
||||
"sha256": "bc87ec52b4913e890fb61ad99b641dd693c0b272dbb1fab347d860118e4bd4af",
|
||||
"applicability": "base_git_blob",
|
||||
"commit": "e1a1651e15bbc9a0526ef31d0b2786feb20d8cd1",
|
||||
"scope": "Frozen contract input. Live plan state is maintained separately and is not content completion evidence."
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-09-29/execution/original_facility_mapping.json",
|
||||
"sha256": "df0c933220449c8bb3e0fd942ad6f1dee49075abdd6587c4856022e12e3665cf",
|
||||
"applicability": "current_checkout"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/asset_inventory_reaudit/facility_usage_slots.json",
|
||||
"sha256": "56a031b6430aa9cb408f14b66efc5dd9a779841c0e7c19301945c49c12711491",
|
||||
"applicability": "current_checkout"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/asset_inventory_reaudit/inventory_summary.json",
|
||||
"sha256": "298b37e65c41febe8a2ccdea10bd105ab7a606904f06b16c1659cda6214859b9",
|
||||
"applicability": "current_checkout"
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/decisions.json",
|
||||
"sha256": "ad0673051b0fa601e525f05128e0b11e2dddd9d4bae6a3e0170bbf47da35efe9",
|
||||
"applicability": "current_checkout"
|
||||
},
|
||||
{
|
||||
"path": "autoload/simulation_runtime.gd",
|
||||
"sha256": "4696df4a77feb465a5a3ba8b806569f7bcbe1d03c88289acfb78a3928f307d67",
|
||||
"applicability": "main_git_blob",
|
||||
"commit": "57131ec616ba06a71d3d97eaea738f209f965349",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/adult_private_room.tres",
|
||||
"sha256": "d8501586416b5c57a8b3b3b2afd1c0143428d8a4fa1df7112e995bd36649df6d",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/cafeteria.tres",
|
||||
"sha256": "86d540fe2d78b9dcdbe5a0af6e4a001f4cec54934636ed01deb25a943c79128a",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/black_market.tres",
|
||||
"sha256": "c209d734c82487f6df4c03714618865d6a5f1d2cf991dc0056fe4bbad8f03a42",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/chapel.tres",
|
||||
"sha256": "9b30a7c51712e7bb99c17870d1f03e3429ea9279851d88284545bb2eb5042fcb",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/cleaning_room.tres",
|
||||
"sha256": "ae366cf67cbf117db7989c6b76092eb5a65229b93d35999a40d19b8260f95ad8",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/clinic.tres",
|
||||
"sha256": "339cf22c68d7ab3cb1514b9e8d2ea63dc0772fe93918d70767c11cf7b6ee0e16",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/cold_storage.tres",
|
||||
"sha256": "1aac824147b52b41e124d2ab2ce63c3bac58de2ec7fc447a5806a1cf9fa9ad99",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/general_store.tres",
|
||||
"sha256": "76872e0375648b43f05fdc5581ccabe4aa6a166674c3b523980dd1cf0b6e6dc1",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/guild_counter.tres",
|
||||
"sha256": "93e8736da4aab8a17b1c8e7831c9a7b8de7f32d0ec251aa9aa5c8cf859c8fd7b",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/laundry.tres",
|
||||
"sha256": "2518ea2e5da12cf4f2997502bf50f00dd8145caca153fb3486b44b99881fdab4",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/maintenance_workshop.tres",
|
||||
"sha256": "8bd10332a9f45a252febdc626f22f90507317fb4cff5b18b2526aacd1f1a176b",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/mana_control_room.tres",
|
||||
"sha256": "55e4c52a049ff61ddf3d081ccb990a8572b64bc7cf37d3a0d52ca5a08cc32f25",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/premium_room.tres",
|
||||
"sha256": "6665090e041f36df5809314cd171be228a94bf77d7e93f5b70be648db4705d98",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/private_bath.tres",
|
||||
"sha256": "241b807e7fa3a1b9dc4bda0d2495e637155cdaea89a4234e37a121f00098499c",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/secret_tavern.tres",
|
||||
"sha256": "f0a1372931078fa0f93dd5b9cec6df6b137975479aa706633fdf6a9be4cf1f62",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/staff_dormitory.tres",
|
||||
"sha256": "8d7c7cd6dfe98d137f7fef62e35eb31f82f1ca282216a40df54ac81728101271",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/tea_lounge.tres",
|
||||
"sha256": "77d1ace36c5e84f80c0e6d563ae973c7ff1cd12b56956afd4895cdcdd5771a67",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/underground_guest_room.tres",
|
||||
"sha256": "cdfd0f8cd21812a9972485926dff27daaa6718af16aac1651894728b087bef9e",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/vip_private_salon.tres",
|
||||
"sha256": "1c94a7a70393262fba82112c3f4a0cb67ad22728664f5ca408f450049d3657a7",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/expansion/waste_processing.tres",
|
||||
"sha256": "9954855c7a07e425376a220c589989beb6ec95da3c5331316ef3615a60b45f1d",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/guest_corridor.tres",
|
||||
"sha256": "d77ccf267e20a26ed70527d29e8d54e6fcab1df213f02d5a4e28ead4f705276b",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/guest_elevator.tres",
|
||||
"sha256": "ad4fb3c439ac4ed90fe52f07e29ed7b4ff654c54d1c400c7c8e226da77127af7",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/infrastructure/guest_stairs.tres",
|
||||
"sha256": "757c687b1ebe2a3f237fb28092cd5f01591f15b2bcd1b4e639042a24635a92c6",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/infrastructure/service_stairs.tres",
|
||||
"sha256": "637217d867bcc99669d27c54b6d2c391c82a4a17356ab9a80c897ccaee38622c",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/kitchen.tres",
|
||||
"sha256": "38197aa8a3e90c03a82e9ccdc88bb444af4eeb0349c41a39e0bdd7b188e7d5d3",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/massage_room.tres",
|
||||
"sha256": "75ecf845fb3cfa8d3150f6b0dc90e901953469af512611384b70cc4878d21e85",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/public_bath.tres",
|
||||
"sha256": "8ec259f48ed75c8ab2e5154a1caccf19f6be04331adbe774b877f0a2d8b2f778",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/reception.tres",
|
||||
"sha256": "bed3de120a0e98c539771d1bb189111d095712f8ae25dfdf7cb2983efc0dee9f",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/rescue/infirmary.tres",
|
||||
"sha256": "c3e861533971e369068ae9e42f71b660fa4ab3893c7c1f798fc367893befd943",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/security_station.tres",
|
||||
"sha256": "69f3f518df7714d00c8e954e9c7405aa44b683dd274181cc3da832cc956815b3",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/service_corridor.tres",
|
||||
"sha256": "5d79fbde201d657740efcba924f595bd7075e069b344d708e424dbebbdc2f254",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/service_elevator.tres",
|
||||
"sha256": "35d552d5b96065413feccb50847e3cd7173e673896ce65afba238f90abc25132",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/staff_door.tres",
|
||||
"sha256": "a993058bfd809ccdbbb9a61b9850259d7bf6e60003e57ccfa3972f6c29170752",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/staff_waiting_room.tres",
|
||||
"sha256": "5c7a2f7f7c508102c4ee89401ad6348191b57d1ff65538acb9d450e464a3a46f",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/standard_room.tres",
|
||||
"sha256": "89f0a3a861d66afa4c1338ff1ec919685cf338b93b8da9a2387ce85e7e5bc336",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/tavern.tres",
|
||||
"sha256": "eb494ae6ab0d1b9e88ae0a38944609702e43c81a370a29cfb030af9ae46f523c",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "data/facilities/warehouse.tres",
|
||||
"sha256": "d0fcf0528da66da7b354ab5efaafe2483a7a76e05b324db255700ef73cdfc791",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "scenes/main/main.gd",
|
||||
"sha256": "92677e4ac57ed8d418a4a716bf0874cbbaea79cff893e5163c82ad1f75e7140a",
|
||||
"applicability": "main_git_blob",
|
||||
"commit": "57131ec616ba06a71d3d97eaea738f209f965349",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "scripts/core/save_service.gd",
|
||||
"sha256": "0c158d3e6ee693b89814bf232c954e4757c5ff91dc9df03bb322c3e593e73617",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "scripts/data/facility_catalog.gd",
|
||||
"sha256": "7bb0c5085ddb361d384314cb219620d1483840942bc3f0f46dcb9dfa29d56e29",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "scripts/events/event_definition.gd",
|
||||
"sha256": "4af68f2e5ec185a750d59aaa24c7cb63fe612cd6a785e7fd39af11f0b5ce74a2",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "scripts/events/event_service.gd",
|
||||
"sha256": "d58c416d7a1126b36023fa6ba9f02338678bd54426a3b5d04ce511d9a48c0103",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "scripts/ui/event_log_dialog.gd",
|
||||
"sha256": "62000f559c49c3a58b244b991c10c1738add10702bfa66cb7cb40798cb559290",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "tests/s2/test_facility_service.gd",
|
||||
"sha256": "4b834f1d9d9ab2ad00cb4a56f5202b70468bfe5f71318dbf816da1e29cc32690",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "tests/s4/test_runtime_relationship_events.gd",
|
||||
"sha256": "466f9a40b3471a9bb39c670cdd1106e990d297bc8bfff0db557cd63bb74c8ef3",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
},
|
||||
{
|
||||
"path": "tests/s6/test_runtime_snapshot_serialization.gd",
|
||||
"sha256": "d9106f9defb6cc195b969ff040d24f1f8ceebe055ba66c39d4634a68620cde84",
|
||||
"applicability": "current_checkout",
|
||||
"scope": "Bounded static observation; no executed connection/content acceptance."
|
||||
}
|
||||
],
|
||||
"output_pins": {
|
||||
"docs/plans/original-completion-2026-10-02/execution/p13-03/difference-ledger.json": "d9aa4725e191d9cef194b01695fe18c6c6ecdc5140c7dc0e72d9409dc1606630",
|
||||
"docs/plans/original-completion-2026-10-02/execution/p13-03/DIFFERENCE_LEDGER.md": "1217a2356432cbf833e0baab443ee48a39776a3747e965e4fc3f914066959dcd",
|
||||
"tools/check_p13_content_difference.py": "7b29180c776218138bfe1bf23013102932d853481cff41e7d830f1f5cf5c4d26"
|
||||
},
|
||||
"status": "ready_for_external_validation",
|
||||
"formal_tests": "external_runner_required",
|
||||
"formal_claude_review": "external_independent_review_required",
|
||||
"worker_history": [
|
||||
"Earlier invocation failed because a literal python alias was unavailable; historical failure is not current readiness or formal acceptance."
|
||||
],
|
||||
"command": "{python} -B tools/check_p13_content_difference.py --verify-only",
|
||||
"purpose": "Verify record integrity and negative rejection only; not content acceptance.",
|
||||
"source_applicability": "Exact IDs, source SHA256 and scopes are in difference-ledger.json. Work package base_git_blob, two main_git_blob sources and other current_checkout sources are separately identified.",
|
||||
"required_before_integration": [
|
||||
"Runner p13-difference pass",
|
||||
"separate formal Claude review pass"
|
||||
],
|
||||
"record_readiness": "Canonical records prepared; formal validation and review are external.",
|
||||
"test_applicability": {
|
||||
"runtime": "Not applicable to records-only changes; no game or platform acceptance.",
|
||||
"native": "Not applicable to records-only changes; no game or platform acceptance.",
|
||||
"Windows": "Not applicable to records-only changes; no game or platform acceptance.",
|
||||
"engine": "Not applicable to records-only changes; no game or platform acceptance.",
|
||||
"full_game_regression": "Not applicable to records-only changes; no game or platform acceptance."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,494 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify P13-03 records only. Never writes receipts or accepts game content.
|
||||
|
||||
Runner: python -B tools/check_p13_content_difference.py --verify-only
|
||||
Optional --ledger permits read-only verification of a candidate ledger.
|
||||
"""
|
||||
import argparse
|
||||
import copy
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
OUT = 'docs/plans/original-completion-2026-10-02/execution/p13-03/'
|
||||
PLAN = 'docs/plans/original-completion-2026-10-02/'
|
||||
MAPPING = 'docs/plans/original-completion-2026-09-29/execution/original_facility_mapping.json'
|
||||
SLOTS = PLAN + 'asset_inventory_reaudit/facility_usage_slots.json'
|
||||
SPEC = 'docs/spec/acceptance/P13-03.json'
|
||||
BASE = 'e1a1651e15bbc9a0526ef31d0b2786feb20d8cd1'
|
||||
MAIN = '57131ec616ba06a71d3d97eaea738f209f965349'
|
||||
TARGET_PATHS = ('autoload/simulation_runtime.gd', 'scenes/main/main.gd')
|
||||
SPEC_RAW = '917cf1504bbfc700e0da42b2db496b42486fe3c36c680f301f58cf34c95267b6'
|
||||
SPEC_RUNNER = 'e1255835c1227e02bac42eb99b026b0fcbe69c272f9ed0b36199a2daf8d55c53'
|
||||
VIEWS = ('normal_entry', 'runtime', 'event_state', 'save', 'test')
|
||||
CATEGORIES = {
|
||||
'event': ['B-1.6', 'B-2.5', 'B-8.2', 'B-8.3'],
|
||||
'overlay': ['B-2.5'],
|
||||
'history': ['B-1.6'],
|
||||
'story': ['B-1.6'],
|
||||
'voice': ['B-1.6'],
|
||||
'scene': ['B-1.6'],
|
||||
}
|
||||
|
||||
INTEGRATION_NOTES = [
|
||||
'The two target sources are immutable main Git blobs at ' + MAIN + '. Matches are re-searched from those bytes with main_git_blob provenance.',
|
||||
'Read-only Git ancestry determines applicability: descendant HEAD requires working files equal to main blobs; non-descendant HEAD requires base blobs. Git errors reject. Report flags cannot select a mode.',
|
||||
'Other current-checkout checks remain strict; work packages remain frozen at the contract base. All unknown/unverified states and 30/88 accounting remain unchanged.',
|
||||
'Formal Runner validation and separate independent review remain external requirements; static observations confer no content completion credit.',
|
||||
]
|
||||
|
||||
|
||||
def raw(path):
|
||||
p = Path(path)
|
||||
if p.is_absolute() or '..' in p.parts:
|
||||
raise ValueError('source must be checkout-relative')
|
||||
resolved = (ROOT / p).resolve()
|
||||
if not resolved.is_relative_to(ROOT):
|
||||
raise ValueError('source escapes checkout')
|
||||
return resolved.read_bytes()
|
||||
|
||||
|
||||
def sha(data):
|
||||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
|
||||
def load(path):
|
||||
def unique(pairs):
|
||||
result = {}
|
||||
for key, value in pairs:
|
||||
if key in result:
|
||||
raise ValueError('duplicate JSON key: ' + key)
|
||||
result[key] = value
|
||||
return result
|
||||
return json.loads(raw(path), object_pairs_hook=unique)
|
||||
|
||||
|
||||
def git_blob(commit, path):
|
||||
return subprocess.check_output(['git', 'show', commit + ':' + path], cwd=ROOT)
|
||||
|
||||
|
||||
def main_is_ancestor():
|
||||
result = subprocess.run(['git', 'merge-base', '--is-ancestor', MAIN, 'HEAD'],
|
||||
cwd=ROOT, capture_output=True)
|
||||
if result.returncode not in (0, 1):
|
||||
raise ValueError('Git ancestry check failed: ' + result.stderr.decode(errors='replace'))
|
||||
return result.returncode == 0
|
||||
|
||||
|
||||
def check_target_sources():
|
||||
commit = MAIN if main_is_ancestor() else BASE
|
||||
for path in TARGET_PATHS:
|
||||
if raw(path) != git_blob(commit, path):
|
||||
raise ValueError('stale working source: ' + path)
|
||||
|
||||
|
||||
def source_bytes(path):
|
||||
return git_blob(MAIN, path) if path in TARGET_PATHS else raw(path)
|
||||
|
||||
|
||||
def provenance(path):
|
||||
record = {'path': path, 'sha256': sha(source_bytes(path)),
|
||||
'applicability': 'main_git_blob' if path in TARGET_PATHS else 'current_checkout'}
|
||||
if path in TARGET_PATHS:
|
||||
record['commit'] = MAIN
|
||||
return record
|
||||
|
||||
|
||||
def observation(paths, tokens, note):
|
||||
"""Exact token matches are search observations, never accepted links."""
|
||||
evidence = []
|
||||
for path in paths:
|
||||
lines = source_bytes(path).decode('utf-8').splitlines()
|
||||
matches = [{'line': i + 1, 'text': line} for i, line in enumerate(lines)
|
||||
if any(token in line for token in tokens)]
|
||||
evidence.append({**provenance(path),
|
||||
'searched_tokens': tokens, 'matches': matches,
|
||||
'scope': 'Static search of this file only; no execution or acceptance.'})
|
||||
return {'status': 'unverified', 'accepted': False, 'note': note, 'evidence': evidence}
|
||||
|
||||
|
||||
def expected():
|
||||
check_target_sources()
|
||||
if sha(raw(SPEC)) != SPEC_RAW or sha(raw(SPEC).decode().strip().encode()) != SPEC_RUNNER:
|
||||
raise ValueError('specification hash mismatch')
|
||||
spec = load(SPEC)
|
||||
sources = []
|
||||
for path, pin in spec['source_pins'].items():
|
||||
if path == PLAN + 'work_packages.json':
|
||||
frozen = git_blob(BASE, path)
|
||||
if sha(frozen) != pin:
|
||||
raise ValueError('frozen work package pin mismatch')
|
||||
sources.append({'path': path, 'sha256': pin, 'applicability': 'base_git_blob', 'commit': BASE})
|
||||
sources[-1]['scope'] = 'Frozen contract input. Live plan state is maintained separately and is not content completion evidence.'
|
||||
else:
|
||||
if sha(raw(path)) != pin:
|
||||
raise ValueError('stale required source: ' + path)
|
||||
sources.append({'path': path, 'sha256': pin, 'applicability': 'current_checkout'})
|
||||
mapping = load(MAPPING)
|
||||
slots = load(SLOTS)
|
||||
if len({s['slot_id'] for s in slots}) != len(slots):
|
||||
raise ValueError('duplicate source slot IDs')
|
||||
definitions = sorted(p.relative_to(ROOT).as_posix() for p in (ROOT / 'data/facilities').rglob('*.tres'))
|
||||
definitions_text = {p: raw(p).decode() for p in definitions}
|
||||
catalog = 'scripts/data/facility_catalog.gd'
|
||||
entry = 'scenes/main/main.gd'
|
||||
runtime = 'autoload/simulation_runtime.gd'
|
||||
event = 'scripts/events/event_service.gd'
|
||||
save = 'scripts/core/save_service.gd'
|
||||
test = 'tests/s6/test_runtime_snapshot_serialization.gd'
|
||||
search_paths = [catalog] + definitions
|
||||
facilities = []
|
||||
for index, original in enumerate(mapping, 1):
|
||||
if original['section'] not in ('10.4', '10.6'):
|
||||
continue
|
||||
identity = 'original_facility_%02d' % index
|
||||
# Names and original stable definition IDs are the bounded search basis.
|
||||
tokens = [original['name']]
|
||||
if original['definition_id']:
|
||||
tokens.append(original['definition_id'])
|
||||
matching = [p for p, text in definitions_text.items()
|
||||
if any(t in text for t in tokens)]
|
||||
ids = []
|
||||
for path in matching:
|
||||
found = re.search(r'^id = &"([^"]+)"', definitions_text[path], re.M)
|
||||
if found:
|
||||
ids.append(found.group(1))
|
||||
# No mana_control_room or generic proxy may fill an original identity.
|
||||
if 'mana_control_room' in ids:
|
||||
raise ValueError('proxy mapping is prohibited')
|
||||
facility_slots = [s for s in slots if s['facility_name'] == original['name']]
|
||||
facilities.append({
|
||||
'original_id': identity, 'original': original,
|
||||
'mapping_observation': observation(search_paths, tokens,
|
||||
'Current catalog and all data/facilities definitions searched. No match means missing in this bounded set; historical null is not treated as proof.'),
|
||||
'current_definition_ids': ids,
|
||||
'current_definition_paths': matching,
|
||||
'connections': {
|
||||
'normal_entry': observation([entry, catalog], tokens,
|
||||
'adult_private_room is in the UI list and baseline catalog; black_market is expansion-only. No other original identity match. Static eligibility only; actual construction is unverified.'),
|
||||
'runtime': observation([runtime, catalog] + matching, tokens + ['FacilityCatalog.FACILITY_PATHS'],
|
||||
'Runtime loads ORIGINAL_FACILITY_PATHS, including some files under the expansion directory. It does not load EXPANSION_FACILITY_PATHS or black_market. Generic services do not prove original special behavior.'),
|
||||
'event_state': observation([runtime, event], tokens,
|
||||
'No facility-specific transition established by this search. Generic EventService is not a dedicated content catalog.'),
|
||||
'save': observation([runtime, save], tokens + ['event_service.create_snapshot()', 'save_snapshot'],
|
||||
'Generic snapshot plumbing is a technical lead only. Facility event round-trip and original semantics remain unverified.'),
|
||||
'test': observation([test, 'tests/s2/test_facility_service.gd', 'tests/s4/test_runtime_relationship_events.gd'], tokens,
|
||||
'Selected generic suite sources searched; no formal suite run or dedicated original facility acceptance inferred.')},
|
||||
'media_usage_slots': [{'slot_id': s['slot_id'], 'source_path': SLOTS,
|
||||
'source_sha256': sha(raw(SLOTS)), 'source_record': s,
|
||||
'status': 'unverified_required_slot', 'approved_asset': None,
|
||||
'content_complete': False} for s in facility_slots],
|
||||
'actual_required_asset_count': None, 'actual_required_asset_count_status': 'unknown',
|
||||
'completed_asset_acceptance': 'unverified', 'original_content_completion': 'unverified',
|
||||
'technical_as_content_credit': False})
|
||||
if len(facilities) != 7:
|
||||
raise ValueError('original facility coverage must be seven')
|
||||
nonfacility = []
|
||||
for category, requirements in CATEGORIES.items():
|
||||
nonfacility.append({'difference_id': 'P13-03.' + category, 'category': category,
|
||||
'requirement_ids': requirements, 'authority_path': spec['authority'],
|
||||
'authority_sha256': sha(raw(spec['authority'])),
|
||||
'related_original_sections': ['1.6', '2.5', '8.2', '8.3', '10.4', '10.6', '13', '14'],
|
||||
'content_ids': None, 'content_ids_status': 'unknown', 'quantity': None,
|
||||
'quantity_status': 'unknown', 'completed_asset_acceptance': 'unverified',
|
||||
'original_content_completion': 'unverified', 'technical_as_content_credit': False,
|
||||
'decisions': ['D08', 'D09'],
|
||||
'difference': 'Required original presentation/content is not accepted by generic state processing. Final catalog, variants, production quantities and ownership remain unknown.',
|
||||
'technical_observation': observation([event, 'scripts/events/event_definition.gd', 'scripts/ui/event_log_dialog.gd'],
|
||||
[category], 'Neutral metadata search only; matches are not finished media, history semantics, story, voice or scenes.')})
|
||||
additional = sorted(set(search_paths + [entry, runtime, event, save, test,
|
||||
'tests/s2/test_facility_service.gd', 'tests/s4/test_runtime_relationship_events.gd',
|
||||
'scripts/events/event_definition.gd', 'scripts/ui/event_log_dialog.gd']))
|
||||
sources += [{**provenance(p),
|
||||
'scope': 'Bounded static observation; no executed connection/content acceptance.'} for p in additional]
|
||||
return {'schema_version': 1, 'task_id': 'P13-03', 'acceptance_ids': ['P13-03'],
|
||||
'requirement_ids': spec['package_requirement_ids'], 'validation_ids': ['p13-difference'],
|
||||
'base_commit': BASE, 'spec_raw_sha256': SPEC_RAW, 'spec_runner_text_sha256': SPEC_RUNNER,
|
||||
'scope': spec['scope'], 'sources': sources, 'facilities': facilities,
|
||||
'nonfacility_differences': nonfacility,
|
||||
'unknowns': {'D08': 'unknown', 'D09': 'unknown', 'final_content_ids': None,
|
||||
'final_content_quantity': None, 'final_actual_asset_count': None},
|
||||
'accounting': {'packages': 30, 'delivery_units': 88, 'no_partial_credit': True,
|
||||
'package_completion_inferred': False, 'original_views_edited': False,
|
||||
'content_completion_inferred': False, 'technical_as_content_credit': False},
|
||||
'asset_policy': 'Usage slots are not image counts. Fallback, Kenney pack, mockup, candidate token, file existence and technical tests confer no content credit.',
|
||||
'test_applicability': {name: {'status': 'not_applicable',
|
||||
'reason': 'Records-only change; no product code, assets, save schema or values changed. No game/platform acceptance is claimed.'}
|
||||
for name in ['runtime', 'native', 'Windows', 'engine', 'full_game_regression']},
|
||||
'formal_validation': 'pending_runner', 'formal_claude_review': 'pending_runner',
|
||||
'integration_gate': 'Required p13-difference validator and separate formal Claude review must pass before integration.'}
|
||||
|
||||
|
||||
def verify(candidate, canonical):
|
||||
# Compare every field, including pending/unknown fields: these must stay
|
||||
# explicit and are not skipped as if they were content PASS.
|
||||
if json.dumps(candidate, sort_keys=True, ensure_ascii=False) != json.dumps(canonical, sort_keys=True, ensure_ascii=False):
|
||||
raise ValueError('coverage, source, observation, unknown or accounting mismatch')
|
||||
|
||||
|
||||
def compact(document):
|
||||
"""Lossless shared long-string table, with exact checked references."""
|
||||
strings, identities = {}, {}
|
||||
evidence, evidence_ids = {}, {}
|
||||
contexts, context_ids = {}, {}
|
||||
|
||||
def context(record):
|
||||
signature = json.dumps(record, sort_keys=True, ensure_ascii=False)
|
||||
if signature not in context_ids:
|
||||
identity = 'context_%04d' % (len(contexts) + 1)
|
||||
context_ids[signature] = identity
|
||||
contexts[identity] = visit(record)
|
||||
return context_ids[signature]
|
||||
|
||||
def visit(value):
|
||||
if isinstance(value, str) and len(value) >= 64:
|
||||
if value not in identities:
|
||||
identity = 'text_%04d' % (len(strings) + 1)
|
||||
identities[value] = identity
|
||||
strings[identity] = value
|
||||
return {'text_ref': identities[value]}
|
||||
if isinstance(value, list):
|
||||
return [visit(item) for item in value]
|
||||
if isinstance(value, dict):
|
||||
result = {}
|
||||
for key, item in value.items():
|
||||
if key == 'evidence':
|
||||
refs = []
|
||||
for record in item:
|
||||
signature = json.dumps(record, sort_keys=True, ensure_ascii=False)
|
||||
if signature not in evidence_ids:
|
||||
identity = 'evidence_%04d' % (len(evidence) + 1)
|
||||
evidence_ids[signature] = identity
|
||||
provenance = {k: v for k, v in record.items() if k not in ('searched_tokens', 'matches')}
|
||||
evidence[identity] = {
|
||||
'source_ref': context(provenance),
|
||||
'search_ref': context({'searched_tokens': record['searched_tokens']}),
|
||||
'matches': visit(record['matches'])}
|
||||
refs.append({'evidence_ref': evidence_ids[signature]})
|
||||
result[key] = refs
|
||||
else:
|
||||
result[key] = visit(item)
|
||||
return result
|
||||
return value
|
||||
|
||||
result = visit(document)
|
||||
result['schema_version'] = 2
|
||||
result['shared_text'] = strings
|
||||
result['shared_evidence'] = evidence
|
||||
result['shared_context'] = contexts
|
||||
return result
|
||||
|
||||
|
||||
def expand(document):
|
||||
def visit(value):
|
||||
if isinstance(value, dict):
|
||||
if set(value) == {'text_ref'}:
|
||||
return document['shared_text'][value['text_ref']]
|
||||
if set(value) == {'evidence_ref'}:
|
||||
return visit(document['shared_evidence'][value['evidence_ref']])
|
||||
if set(value) == {'source_ref', 'search_ref', 'matches'}:
|
||||
return {**visit(document['shared_context'][value['source_ref']]),
|
||||
**visit(document['shared_context'][value['search_ref']]),
|
||||
'matches': visit(value['matches'])}
|
||||
return {key: visit(item) for key, item in value.items()
|
||||
if key not in ('shared_text', 'shared_evidence', 'shared_context')}
|
||||
if isinstance(value, list):
|
||||
return [visit(item) for item in value]
|
||||
return value
|
||||
return visit(document)
|
||||
|
||||
|
||||
def negative_checks(canonical, ledger_path=OUT + "difference-ledger.json"):
|
||||
cases = {}
|
||||
mutations = {
|
||||
'tampered_ancestry_flag': lambda d: d.update(main_is_ancestor=False),
|
||||
'tampered_report_flag': lambda d: d.update(source_mode='legacy_fallback'),
|
||||
'facility_omission': lambda d: d['facilities'].pop(),
|
||||
'slot_omission': lambda d: d['facilities'][0]['media_usage_slots'].pop(),
|
||||
'stale_pin': lambda d: d['sources'][0].update(sha256='0' * 64),
|
||||
'duplicate_facility': lambda d: d['facilities'].append(copy.deepcopy(d['facilities'][0])),
|
||||
'duplicate_slot': lambda d: d['facilities'][0]['media_usage_slots'].append(copy.deepcopy(d['facilities'][0]['media_usage_slots'][0])),
|
||||
'false_content_completion': lambda d: d['facilities'][0].update(original_content_completion='completed'),
|
||||
'false_asset_acceptance': lambda d: d['facilities'][0]['media_usage_slots'][0].update(approved_asset='fallback.png', content_complete=True),
|
||||
'technical_as_content': lambda d: d['accounting'].update(technical_as_content_credit=True),
|
||||
'unknown_to_zero': lambda d: d['unknowns'].update(final_content_quantity=0),
|
||||
'nonfacility_omission': lambda d: d['nonfacility_differences'].pop(),
|
||||
'proxy_mapping': lambda d: d['facilities'][-1].update(current_definition_ids=['mana_control_room']),
|
||||
'connection_promotion': lambda d: d['facilities'][0]['connections']['runtime'].update(accepted=True),
|
||||
'false_runner_pass': lambda d: d.update(formal_validation='pass'),
|
||||
'missing_shared_text': lambda d: d['shared_text'].pop(next(iter(d['shared_text']))),
|
||||
'missing_shared_evidence': lambda d: d['shared_evidence'].pop(next(iter(d['shared_evidence']))),
|
||||
'missing_shared_context': lambda d: d['shared_context'].pop(next(iter(d['shared_context']))),
|
||||
'altered_shared_text': lambda d: d['shared_text'].update({next(iter(d['shared_text'])): 'omitted'}),
|
||||
'dangling_reference': lambda d: d['facilities'][0]['connections']['runtime'].update(note={'text_ref': 'missing'}),
|
||||
}
|
||||
for name, mutate in mutations.items():
|
||||
changed = copy.deepcopy(canonical)
|
||||
mutate(changed)
|
||||
try:
|
||||
verify(changed, canonical)
|
||||
except ValueError:
|
||||
cases[name] = 'rejected'
|
||||
else:
|
||||
raise ValueError('negative case was accepted: ' + name)
|
||||
# Inject source bytes and Git results only in memory; no product/Git writes.
|
||||
real_raw, real_blob = raw, git_blob
|
||||
snapshots = {(commit, path): real_blob(commit, path)
|
||||
for commit in (BASE, MAIN) for path in TARGET_PATHS}
|
||||
|
||||
def rejected(name, operation):
|
||||
try:
|
||||
operation()
|
||||
except (ValueError, OSError, subprocess.CalledProcessError):
|
||||
cases[name] = 'rejected'
|
||||
else:
|
||||
raise ValueError('negative case was accepted: ' + name)
|
||||
|
||||
for descendant in (False, True):
|
||||
commit = MAIN if descendant else BASE
|
||||
label = 'merged' if descendant else 'frozen'
|
||||
def working(path):
|
||||
return snapshots[commit, path] if path in TARGET_PATHS else real_raw(path)
|
||||
with patch(__name__ + '.main_is_ancestor', return_value=descendant):
|
||||
with patch(__name__ + '.raw', side_effect=working):
|
||||
verify(compact(expected()), canonical)
|
||||
for target in TARGET_PATHS:
|
||||
def corrupt(path):
|
||||
data = working(path)
|
||||
return data + b'\n# corrupted source' if path == target else data
|
||||
with patch(__name__ + '.raw', side_effect=corrupt):
|
||||
rejected(label + '_stale_' + target, expected)
|
||||
other = BASE if descendant else MAIN
|
||||
def wrong_version(path):
|
||||
return snapshots[other, path] if path in TARGET_PATHS else real_raw(path)
|
||||
with patch(__name__ + '.raw', side_effect=wrong_version):
|
||||
rejected(label + '_wrong_snapshot', expected)
|
||||
def corrupt_blob(version, path):
|
||||
data = real_blob(version, path)
|
||||
return data + b'\n# corrupted blob' if version == MAIN else data
|
||||
with patch(__name__ + '.raw', side_effect=working), patch(__name__ + '.git_blob', side_effect=corrupt_blob):
|
||||
rejected(label + '_corrupt_git_blob', lambda: verify(compact(expected()), canonical))
|
||||
for result in (subprocess.CompletedProcess([], 2, b'', b'Git failure'),
|
||||
subprocess.CompletedProcess([], -1, b'', b'interrupted')):
|
||||
with patch.object(subprocess, 'run', return_value=result):
|
||||
rejected('ancestry_git_error_' + str(result.returncode), expected)
|
||||
with patch.object(subprocess, 'run', side_effect=OSError('Git unavailable')):
|
||||
rejected('ancestry_git_unavailable', expected)
|
||||
with patch(__name__ + '.git_blob', side_effect=subprocess.CalledProcessError(128, ['git', 'show'])):
|
||||
rejected('blob_git_error', expected)
|
||||
|
||||
# Exercise the same read-only alternate input path used by the CLI.
|
||||
alternate = OUT + 'in_memory_candidate.json'
|
||||
ledger_bytes = real_raw(ledger_path)
|
||||
def alternate_raw(path):
|
||||
if path == alternate:
|
||||
return ledger_bytes
|
||||
if path == OUT + 'difference-ledger.json':
|
||||
raise ValueError('default ledger must not be read for alternate input')
|
||||
return real_raw(path)
|
||||
with patch(__name__ + '.raw', side_effect=alternate_raw):
|
||||
verify_records(alternate, canonical)
|
||||
cases['alternate_ledger_valid'] = 'verified_read_only'
|
||||
with patch(__name__ + '.raw', side_effect=lambda path: b'{}' if path == alternate else real_raw(path)):
|
||||
rejected('alternate_ledger_corrupt', lambda: verify_records(alternate, canonical))
|
||||
return cases
|
||||
|
||||
|
||||
def verify_records(ledger_path, canonical):
|
||||
verify(load(ledger_path), canonical)
|
||||
if load(OUT + 'validation.json') != receipt_expected(ledger_path):
|
||||
raise ValueError('receipt mismatch or false formal acceptance')
|
||||
if raw(OUT + 'DIFFERENCE_LEDGER.md').decode() != readable(expand(canonical)):
|
||||
raise ValueError('readable ledger differs from machine ledger')
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--ledger', default=OUT + 'difference-ledger.json',
|
||||
help='Read-only checkout-relative alternate ledger; must match canonical records and the registered receipt hash. No output is written.')
|
||||
parser.add_argument('--negative-checks', action='store_true')
|
||||
parser.add_argument('--verify-only', action='store_true',
|
||||
help='Read-only verification; negative checks are always mandatory.')
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
canonical = compact(expected())
|
||||
verify_records(args.ledger, canonical)
|
||||
result = {'record_integrity': 'pass', 'content_acceptance': 'not_claimed',
|
||||
'formal_review': 'external_runner_required'}
|
||||
result['negative_checks'] = negative_checks(canonical, args.ledger)
|
||||
print(json.dumps(result, ensure_ascii=False))
|
||||
return 0
|
||||
except (ValueError, OSError, KeyError, TypeError, subprocess.CalledProcessError) as error:
|
||||
print(json.dumps({'record_integrity': 'fail', 'error': str(error)}))
|
||||
return 1
|
||||
|
||||
|
||||
def receipt_expected(ledger_path=OUT + 'difference-ledger.json'):
|
||||
ledger = expand(load(ledger_path))
|
||||
return {'task_id': 'P13-03', 'acceptance_ids': ['P13-03'], 'validation_ids': ['p13-difference'],
|
||||
'requirement_ids': ledger['requirement_ids'],
|
||||
'facility_ids': [f['original_id'] for f in ledger['facilities']],
|
||||
'slot_ids': [s['slot_id'] for f in ledger['facilities'] for s in f['media_usage_slots']],
|
||||
'difference_ids': [n['difference_id'] for n in ledger['nonfacility_differences']],
|
||||
'source_applicability_records': ledger['sources'],
|
||||
'output_pins': {p: sha(raw(ledger_path if p == OUT + 'difference-ledger.json' else p)) for p in [OUT + 'difference-ledger.json',
|
||||
OUT + 'DIFFERENCE_LEDGER.md', 'tools/check_p13_content_difference.py']},
|
||||
'status': 'ready_for_external_validation',
|
||||
'formal_tests': 'external_runner_required',
|
||||
'formal_claude_review': 'external_independent_review_required',
|
||||
'worker_history': ['Earlier invocation failed because a literal python alias was unavailable; historical failure is not current readiness or formal acceptance.'],
|
||||
'command': '{python} -B tools/check_p13_content_difference.py --verify-only',
|
||||
'purpose': 'Verify record integrity and negative rejection only; not content acceptance.',
|
||||
'source_applicability': 'Exact IDs, source SHA256 and scopes are in difference-ledger.json. Work package base_git_blob, two main_git_blob sources and other current_checkout sources are separately identified.',
|
||||
'required_before_integration': ['Runner p13-difference pass', 'separate formal Claude review pass'],
|
||||
'record_readiness': 'Canonical records prepared; formal validation and review are external.',
|
||||
'test_applicability': {name: 'Not applicable to records-only changes; no game or platform acceptance.'
|
||||
for name in ['runtime', 'native', 'Windows', 'engine', 'full_game_regression']}}
|
||||
|
||||
|
||||
def readable(d):
|
||||
lines = ['# P13-03 内容差異台帳', '',
|
||||
'記録の提出であり、ゲーム内容・P13パッケージの完成認定ではない。原30パッケージ/88成果、部分点なし。原子・状態台帳は変更しない。', '',
|
||||
'通常入口、Runtime、イベント状態、保存、試験はすべて静的観測・未検証。汎用処理は原施設固有の接続や完成素材を証明しない。', '',
|
||||
'機械台帳のshared_text/text_refとshared_evidence/evidence_refは重複証拠の共有参照。検索語、一致行番号・全文、相対出典パス、SHAを省略せず保持し、チェッカーは全参照と本文を照合する。作業計画は契約baseのGit blobを固定入力として検証する。別管理の現行進捗は内容完成の証拠にしない。', '',
|
||||
'施設の原典IDは旧対応表の1始まりの位置を保持する。現行の data/facilities 全定義とカタログを名前・既存IDで再検索した。マナ制御室をマナ炉に代用しない。', '',
|
||||
'|原典ID|章|原典名|現行定義候補|使用スロット数|完成素材・原内容|',
|
||||
'|---|---|---|---|---|---|']
|
||||
for f in d['facilities']:
|
||||
lines.append('|%s|%s|%s|%s|%d|未検証|' % (f['original_id'], f['original']['section'],
|
||||
f['original']['name'], ', '.join(f['current_definition_ids']) or '対象検索範囲で欠落', len(f['media_usage_slots'])))
|
||||
lines += ['', '風俗個室は通常UIリストとRuntime読込元に候補がある。闇市場は拡張定義のみで通常読込元に含まれない。他の5施設は対象定義集合で対応が見つからない。実行・保存再開・施設固有イベントの受入は未検証。', '',
|
||||
'## 施設別の観測と使用スロット', '']
|
||||
lines += ['共有観測範囲(各施設の具体的検索結果は機械台帳に保持):', '']
|
||||
for view in VIEWS:
|
||||
lines += ['- ' + view + ': ' + d['facilities'][0]['connections'][view]['note']]
|
||||
lines += ['', '共有出典・検索語はshared_contextのsource_ref/search_refから復元する。各施設の各観測は個別に参照し、合格接続を意味しない。', '']
|
||||
for f in d['facilities']:
|
||||
lines += ['### ' + f['original_id'] + ' / ' + f['original']['name'], '']
|
||||
for view in VIEWS:
|
||||
o = f['connections'][view]
|
||||
lines += ['- ' + view + ': ' + o['status'] + '(検索語・一致行本文・出典SHAは機械台帳参照)']
|
||||
lines += ['', '使用スロット(すべて unverified_required_slot、approved_asset=null):', '']
|
||||
lines += ['- `' + s['slot_id'] + '`' for s in f['media_usage_slots']]
|
||||
lines += ['', '実制作資産数はunknown/null。スロット数を画像数に転用しない。', '']
|
||||
lines += ['## 施設外の内容差異', '']
|
||||
for n in d['nonfacility_differences']:
|
||||
lines += ['- `' + n['difference_id'] + '` (' + ', '.join(n['requirement_ids']) + '): ' + n['difference']]
|
||||
lines += ['', 'event/overlay/history/story/voice/scene の内容ID・数量・受入はunknownまたは未検証。D08(内容範囲)/D09(品質・量・担当・権利)は未決定。中立メタデータのみを記録し、場面は制作・描写しない。', '',
|
||||
'## 出典・適用範囲', '', '機械台帳に各観測の検索語・一致行・本文・実SHAを保持する。旧対応表は原典識別に利用し、現行対応は再検索で記録する。素材台帳は使用スロットと候補の証拠のみ。inventory_summaryの290 media files、0 audio files、360 slots、0 approved assetsは既存監査の限定集計であり、最終必要量を示さない。', '']
|
||||
lines += ['- `' + s['path'] + '` / ' + s['applicability'] + ' / SHA256 `' + s['sha256'] + '`' for s in d['sources']]
|
||||
lines += ['', '## 統合監査注記', '']
|
||||
lines += ['- ' + note for note in INTEGRATION_NOTES]
|
||||
lines += ['', '## 検証・統合条件', '',
|
||||
'`python -B tools/check_p13_content_difference.py --verify-only` は記録整合性と欠落・重複・古いpin・誤完成・技術から内容への昇格・unknownのゼロ化・共有参照改変等の拒否を必ず検証する。--negative-checksも互換引数として保持する。workerのローカル診断は正式受入ではない。Runner正式validatorと別セッションの正式Claudeレビュー合格後にのみ統合できる。', '',
|
||||
'Runtime/native/Windows/engine/full game regressionは記録だけの変更に適用外(製品コード・資産・保存形式・値の変更なし)。この適用外をゲームの合格に転用しない。Kenney・fallback・mockup・コード候補・ファイル存在・状態試験から完成資産を推定しない。', '']
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user