Compare commits

...
29 changed files with 7690 additions and 31 deletions
+48
View File
@@ -20,6 +20,7 @@ const OPERATING_EXPENSE_ACCOUNT := &"OPERATING_EXPENSE"
const AUTHORITY_FINE_ACCOUNT := &"AUTHORITY_FINE_EXPENSE"
const WAGE_EXPENSE_ACCOUNT := &"WAGE_EXPENSE"
const RUNTIME_SNAPSHOT_VERSION := 14
const PeepingRooms := preload("res://scripts/special/peeping_room_service.gd")
const AUTO_PURCHASE_RUNTIME_SNAPSHOT_VERSION := 14
const EVENT_THREAT_RUNTIME_SNAPSHOT_VERSION := 13
const MIMI_PURCHASE_RUNTIME_SNAPSHOT_VERSION := 15
@@ -97,6 +98,7 @@ const DEFENSE_COMMAND_TYPES: Array[StringName] = [
var definition_registry := DefinitionRegistry.new()
var command_queue := CommandQueue.new()
var id_generator := StableIdGenerator.new()
var peeping_room_service := PeepingRooms.new()
var domain_events := DomainEventStream.new()
var world_service := WorldService.new()
var path_service := PathService.new()
@@ -233,6 +235,7 @@ func initialize(clock: SimulationKernel, state: Variant, seed := DEFAULT_WORLD_S
_hired_staff_candidate_ids.clear()
command_queue = CommandQueue.new()
id_generator = StableIdGenerator.new()
peeping_room_service = PeepingRooms.new()
domain_events = DomainEventStream.new()
world_service = WorldService.new()
path_service = PathService.new()
@@ -253,6 +256,7 @@ func initialize(clock: SimulationKernel, state: Variant, seed := DEFAULT_WORLD_S
_initialize_s5_defense()
construction_service = ConstructionService.new(world_service, construction_resource_state)
construction_service.current_minute = _clock.absolute_minute
peeping_room_service.configure(world_service, facility_service, construction_service, path_service, id_generator)
_connect_construction_signals()
var initial_infrastructure_ok := _initialize_infrastructure_services()
_next_command_id = 1
@@ -298,6 +302,8 @@ func initialize(clock: SimulationKernel, state: Variant, seed := DEFAULT_WORLD_S
register_command_executor(&"build_facility", Callable(self, "_execute_build_facility"))
register_command_executor(&"cancel_construction", Callable(self, "_execute_cancel_construction"))
register_command_executor(&"demolish_facility", Callable(self, "_execute_demolish_facility"))
for command_type: StringName in [&"peeping_room_validate", &"peeping_room_place", &"peeping_room_relink", &"peeping_room_record_evidence"]:
register_command_executor(command_type, Callable(self, "_execute_peeping_room"))
register_command_executor(&"set_elevator_operation", Callable(self, "_execute_set_elevator_operation"))
register_command_executor(&"start_excavation", Callable(self, "_execute_start_excavation"))
register_command_executor(&"pause_excavation", Callable(self, "_execute_pause_excavation"))
@@ -565,6 +571,8 @@ func create_snapshot() -> Dictionary:
}
if PurchaseQuoteV2.has_history(owned_systems[&"runtime"]):
owned_systems[&"runtime"][&"runtime_schema_version"] = MIMI_PURCHASE_RUNTIME_SNAPSHOT_VERSION
if not peeping_room_service.is_empty():
owned_systems[&"runtime"][&"special_peeping_rooms"] = peeping_room_service.create_snapshot()
# Every component above returns detached containers. Transfer this fresh
# tree into the envelope instead of deep-copying all component snapshots a
# second time. Keep generic capture's caller-owned-extra contract unchanged.
@@ -666,6 +674,8 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
runtime_current_keys.append(&"facility_cleanliness")
if runtime_schema_version >= AUTO_PURCHASE_RUNTIME_SNAPSHOT_VERSION:
runtime_current_keys.append(&"auto_purchase_plans")
if runtime_data.has(&"special_peeping_rooms"):
runtime_current_keys.append(&"special_peeping_rooms")
if not _dictionary_has_exact_canonical_keys(runtime_data, runtime_current_keys) \
or typeof(runtime_data.get(&"runtime_schema_version", null)) != TYPE_INT \
or typeof(runtime_data.get(&"world_seed", null)) != TYPE_INT \
@@ -1290,6 +1300,16 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
var restored_next_id := int(runtime_data.get(&"next_command_id", 0))
if restored_next_id <= 0:
return false
var restored_peeping_rooms := PeepingRooms.new()
restored_peeping_rooms.configure(restored_world, restored_facilities, restored_construction, restored_path, restored_id_generator)
if runtime_data.has(&"special_peeping_rooms"):
if not runtime_data[&"special_peeping_rooms"] is Dictionary:
return false
for raw_key: Variant in runtime_data:
if raw_key == &"special_peeping_rooms" and typeof(raw_key) != TYPE_STRING_NAME:
return false
if not restored_peeping_rooms.restore_section(runtime_data.get(&"special_peeping_rooms", null), restored_minute):
return false
if not SimulationSnapshot.restore(snapshot, _clock, _state):
return false
world_seed = restored_world_seed
@@ -1297,6 +1317,7 @@ func _restore_snapshot_internal(snapshot: Dictionary, recovery_mode: bool) -> bo
_staffing_projection_enabled = restored_staffing_projection
command_queue = restored_queue
id_generator = restored_id_generator
peeping_room_service = restored_peeping_rooms
domain_events = restored_domain_events
_rng_streams = restored_streams
world_service = restored_world
@@ -5546,6 +5567,7 @@ func _connect_facility_signals() -> void:
return
facility_service.instance_registered.connect(Callable(self, "_on_cleanliness_facility_registered"))
facility_service.instance_unregistered.connect(Callable(self, "_on_cleanliness_facility_unregistered"))
facility_service.instance_unregistered.connect(Callable(self, "_on_peeping_target_removed"))
facility_service.facility_state_changed.connect(Callable(self, "_on_facility_state_changed"))
facility_service.service_started.connect(Callable(self, "_on_service_started"))
facility_service.service_interrupted.connect(Callable(self, "_on_service_interrupted"))
@@ -10817,6 +10839,7 @@ func _on_excavation_completed(report: Dictionary) -> void:
))
func _on_facility_demolished(instance_id: StringName, refund: Dictionary) -> void:
peeping_room_service.target_removed(instance_id)
if not mana_network_service.get_node(instance_id).is_empty():
mana_network_service.unregister_node(instance_id)
if facility_service.has_instance(instance_id):
@@ -10831,6 +10854,31 @@ func _on_facility_demolished(instance_id: StringName, refund: Dictionary) -> voi
0
))
func _on_peeping_target_removed(instance_id: StringName) -> void:
peeping_room_service.target_removed(instance_id)
func _execute_peeping_room(command: SimulationCommand) -> CommandResult:
var payload := command.payload
var report: Dictionary
if command.command_type == &"peeping_room_place":
report = PeepingRooms.result(&"BUILD_DEFINITION_PENDING_D04")
elif command.command_type == &"peeping_room_validate":
if typeof(payload.get(&"origin")) != TYPE_VECTOR3I or typeof(payload.get(&"footprint", Vector2i(2, 1))) != TYPE_VECTOR2I or typeof(payload.get(&"target_instance_id", &"")) not in [TYPE_STRING, TYPE_STRING_NAME]:
report = PeepingRooms.result(&"INVALID_PAYLOAD")
else:
report = peeping_room_service.validate_placement(payload[&"origin"], payload.get(&"footprint", Vector2i(2, 1)), StringName(payload.get(&"target_instance_id", &"")))
else:
var key: StringName = &"target_instance_id" if command.command_type == &"peeping_room_relink" else &"source_event_key"
if typeof(payload.get(&"room_id")) not in [TYPE_STRING, TYPE_STRING_NAME] or typeof(payload.get(key, &"")) not in [TYPE_STRING, TYPE_STRING_NAME]:
report = PeepingRooms.result(&"INVALID_PAYLOAD")
elif command.command_type == &"peeping_room_relink":
report = peeping_room_service.relink(StringName(payload[&"room_id"]), StringName(payload.get(key, &"")))
else:
report = peeping_room_service.record_evidence(StringName(payload[&"room_id"]), StringName(payload.get(key, &"")), _runtime_event_minute())
if report[&"ok"]:
return CommandResult.succeeded(command.command_id, report)
return CommandResult.failed(CommandResult.Code.VALIDATION_FAILED, command.command_id, String(report[&"reason"]), report)
func _on_ledger_transaction_posted(transaction_id: StringName, _entries: Array) -> void:
if _operations_flushing_economy_notifications.has(transaction_id):
return
@@ -3734,6 +3734,61 @@
"path": "docs/spec/acceptance/P23-03.json",
"scope": "component and read-only observation only; native unexecuted; whole unit blocked"
}
},
{
"test": "tests/special/test_peeping_room_geometry.gd",
"template": "Peeping room geometry: <checks> checks, <failures> failures",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "103d85f83e1e97a8637892504264275eef23f172eeec56c94e5c022d81bf6945",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p13-02/CODE1_TASK_SPEC.json",
"scope": "new backend suite marker; native execution pending"
}
},
{
"test": "tests/special/test_peeping_room_reference.gd",
"template": "Peeping room reference: <checks> checks, <failures> failures",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "188b00a60f7aefda69dc4973f1de9c14447a0d4bcdd1257a2eabe7c4782e4caf",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p13-02/CODE1_TASK_SPEC.json",
"scope": "new backend suite marker; native execution pending"
}
},
{
"test": "tests/special/test_peeping_room_evidence.gd",
"template": "Peeping room evidence: <checks> checks, <failures> failures",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "390e0032d14de9a8875ced163a922341ce655744200d78b4ffa776d42c4f8c2a",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p13-02/CODE1_TASK_SPEC.json",
"scope": "new backend suite marker; native execution pending"
}
},
{
"test": "tests/special/test_peeping_room_save.gd",
"template": "Peeping room save: <checks> checks, <failures> failures",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "ba0e7644277477c1821135cae6d6fd533651799c6f9bd8c43ccf45e63b96c63c",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p13-02/CODE1_TASK_SPEC.json",
"scope": "new backend suite marker; native execution pending"
}
},
{
"test": "tests/special/test_peeping_room_runtime.gd",
"template": "Peeping room runtime: <checks> checks, <failures> failures",
"required": true,
"fixed_check_count_used": false,
"source_sha256_at_schema_audit": "30ed2fe11cc6b0353e9a3a6d995cf8690d322858d2c3dbb38ef32fd941072d2d",
"authority": {
"path": "docs/plans/original-completion-2026-10-02/execution/p13-02/CODE1_TASK_SPEC.json",
"scope": "new backend suite marker; native execution pending"
}
}
],
"unknown_roster_suite_policy": "refuse, explicitly review its source/schema before accepting",
@@ -0,0 +1,31 @@
{
"task_id": "P04-01",
"commit": "2dde7596a87c43f7bf0bf704b7479f2fa06a5b1c",
"status": "blocked",
"summary": "The repair29 documents describe the current code accurately but leave the required ordering rules undefined. The D05 candidate's source references match the current product (product1338): FacilityService._prepare_service_for_tick:853-874 checks RELATED_FACILITY_INACTIVE before NO_POWER, and the cited runtime functions are at 5743/7553/8482/8577/8738/9804/11785. The submission itself states that D05 items (a) power vs closure/dependency precedence, (b) destruction vs completion, (c) exit vs completion and (d) which day a 00:00 sale belongs to are pending an owner decision. P04-01 requires the order across 閉店/停電/破壊/退出/課金/シフト交代/00:00決算 to be stated ('順序を明記'). That cannot be met while these mandatory rules are only a recommended 'keep current behavior' candidate that nobody has approved. Several final steps are also unfinished, and CURRENT_STATUS.md says the unit is incomplete (13/88 unchanged). The passing p04-acceptance check is mechanical (it confirms an index exists and does not approve the rules), so it is not enough for pass. The blocker is undecided rules (spec insufficient), which needs an owner decision, so the status is blocked.",
"acceptance_ids": [
"P04-01"
],
"findings": [
{
"severity": "high",
"message": "Mandatory ordering rules are undefined. The order between power stop and closure/dependency, between destruction and completion/charging, between exit and completion, and which day a 00:00 sale belongs to are pending. D05_REMAINING_ORDER_CANDIDATE.md/.json offers only Option A (keep current behavior), which has not been approved. P04-01 requires the order to be stated explicitly ('順序を明記'), and code behavior is not authority, so acceptance cannot be granted. An owner decision is needed (spec insufficient → blocked)."
},
{
"severity": "high",
"message": "Under current behavior, Option (b) allows an incident-driven destruction in the same tick to follow a completion and charge (B4a: 25G charged, then destroyed). Whether this conflicts with the 'no charging while stopped' (停止中課金なし) criterion has not been settled. A D05 destruction rule is required."
},
{
"severity": "medium",
"message": "The checker's destruction_stop rule (tools/check_p04_order_evidence.py:49) points to BASELINE:183, which covers mana depletion, not destruction. The authority reference does not match the domain. The repair is deferred until D05 is approved, so the 破壊 domain still has no valid authority link."
},
{
"severity": "medium",
"message": "No final validation has been run on the final source and checker. Full178 ran with checker f5, not the current a61, and no full1339 run exists. tests/business/test_required_kitchen.gd differs from the version that run used. The support53cb rebind, final source/config/input/environment binding, formal review, integration (P04 first, then support) and any nativeWindows conditions are all still pending."
},
{
"severity": "low",
"message": "S4 NO_POWER evidence comes from a direct disconnect_nodes call and does not represent global mana depletion, which appears only in the B1 combined diagnostic run. The documents say this correctly, but the scope of the power-stop evidence is limited."
}
]
}
@@ -0,0 +1,62 @@
{
"observed_at": "2026-10-17T16:30:38.746525+09:00",
"original_packages": 30,
"original_units": 88,
"formally_completed": 14,
"new_credit": 0,
"plan_id": "P04-01",
"state": "in_progress",
"runner_project": "the-tree-p04-01",
"runner_state": "repair_pending",
"repairs": 29,
"max_repairs": null,
"submitted": "2dde7596a87c43f7bf0bf704b7479f2fa06a5b1c",
"candidate": null,
"worktree_clean_at_observation": true,
"active_worker": false,
"current_main_at_audit": "565fd805079d8c446f29e30c57979242561113ea",
"acceptance_unchanged": {
"domains": [
"閉店",
"停電",
"破壊",
"退出",
"課金",
"シフト交代",
"00:00決算"
],
"safety": [
"停止中課金0",
"二重決算0",
"予約の孤立0"
],
"conditions": "all15 + EV, original frozen rules unchanged",
"required_gates": [
"exact final source/checker applicability",
"required final full regression",
"independent whole review",
"ordinary prepare-integration / integration / final",
"ledger reflection"
]
},
"latest_commander": "ea12167cffff444596c0c36caa700a26",
"latest_formal_review": "275d1fd64fff4d5782c6f7667fc1e031",
"no_duplicate_repair": true,
"remaining": [
"owner choices for destruction order and midnight-sale day, plus explicit disposition of reason label and command/AI exit",
"after actual answers, normal batched checker destruction-authority pin / registry / approval record / stale current metadata correction",
"final gates as listed; previous full178 f5 receipt is not full final checker a61 evidence; no relabeling"
],
"already_corrected_per_actual_opus": [
"raw joins",
"canonical getter contract explanation",
"candidate HEAD fixtures",
"schema2 index",
"S4r28",
"Local8",
"r22 collection"
],
"owner_response_pending": true,
"approval_not_inferred": true,
"whole_acceptance": false
}
@@ -0,0 +1,31 @@
# P04-01 current status — repair29
Worker checks: SOURCE-READY / NOTRUN. No probes or tests were run by this worker.
This canonical table overrides creation-time NOT RUN / pending-execution entries in REPAIR22–28, their status/validation records, and the runbooks (including S4_ROOT_RUN.md). Those files are historical and remain untouched. It does not relabel an old run as execution of repair29.
`B` = `/Users/korizatou114/Projects/TheTree-managed-worktrees/p04-01/.runtime/P04-01/build`.
| Item | Canonical status | Exact-version evidence |
| --- | --- | --- |
| Current native product / main | Root-measured `5f6bc11d` / `9b1a18c1` | Product1338 at B/audit-support/p04-r17-full-inputs-r01/product; current SHA256 inventory in REPAIR29_STATIC_SOURCE.json. Old deb11300 is not current. |
| S4 r28 | Root-measured 4/4 PASS; import/parse/Writer/Reader PIDs49940,50044,50078,50105 all ended; guards0; cleanup0 | B/p04-s4-native-r28; B/audit-support/p04-root-fb8b-s4-r01/native.result.json. Full controls in that same support directory. |
| Local8 | Root-measured PASS | B/audit-support/p04-root-fb8b-local-r01: bulk, negative, applicability, native, series, encoder, join, roles result/stdio records. |
| Collection | Root-measured r22 collected, no native re-run claimed | B/audit-support/p04-raw-collect-r22/MANIFEST.json and s1/s2a/s2b/s3/s4.json. |
| Index | Root-measured schema2, missing_conditions=[], all15 conditions + EV mechanically verified | B/p04-evidence/index.json and generation-invocation.json; local-r01 index/checker output. This is not D05 approval. |
| Registered validation on fb8b7919 | Root-measured PASS,28.095s | B/audit-support/p04-root-fb8b-local-r01/registered-validation.result.json and stdout log. Does not establish final repair29 validation or acceptance. |
| Full178 | Root-measured178 suites /21615 checks PASS used checker f5, **not a61** | B/audit-support/p18-regression-support-final-r01/native-full178/runner-ended.json and source-start.json; exact receipt remains preserved. Checker f5 SHA256 `f5b44827958f2ae352fe5c4bc3a1ffd4211ec7a41fc4c0759c8b954891662324`. |
| Full1339 against a61 | **No such full run exists** | a61 SHA256 `a61c5b496e656f60c66898e42500bc9a2d45f947690ce8f5f19a03984ebbc850`. Local8 and registered validation are separate evidence. |
| Worker repair29 | SOURCE-READY / NOTRUN | Static source/line/registration/SHA256 inspection only. No tests, probes, Git, engine, Runner or agents. |
| Owner D05 | Pending a–d, candidate only | D05_REMAINING_ORDER_CANDIDATE.md/json; A01, dependency hold and18:00 remain approved. |
| Original unit | **Incomplete;13/88 unchanged** | Mechanical PASS does not approve unknown mandatory priorities, replace independent review, or integrate the unit. |
Proof hashes for the exact collection/index/full receipt/validation and current source are in [REPAIR29_STATIC_SOURCE.json](REPAIR29_STATIC_SOURCE.json). Applicable source/config/input/environment joins stay in the immutable schema2 index and raw collection; no raw is normalized, spliced, regenerated or relabelled here.
Product reuse requires exact applicability: the178 suites do not execute the Python checker and the316-file GDScript parse roster excludes it. Static comparison with the preserved full178 selected_source_map found one test-source difference, tests/business/test_required_kitchen.gd (full178 3a9c92f8…, current product5dcc86d6…), and no game-source difference. Preserve the Runner applicability binding for this test; do not claim all1338 selected product hashes match that full178 receipt or byte-identical full1339 validation against a61. Preserve the f5 full178 receipt and all historical partial/full outputs separately.
Remaining Runner steps: independent review of these documents, then Root obtains owner decisions (or explicit non-mandatory rulings) for D05 a–d. Unknown mandatory rules stay pending. Any destruction authority pin/registry or other approved implementation change follows a normal repair. The support53cb normal registered rebind, final full run on the final source/checker, final source/config/input/environment binding, formal independent review and integration remain Runner work. Integration order is **P04 first, then support on main9b (`9b1a18c1`)**. NativeWindows obligations remain individually pending if required. No criterion is waived and no extra original unit is counted.
Known authority/scope gaps: destruction_stop binds BASELINE:183 (mana depletion, not destruction); explicit D05 destruction rule required before normal pin repair. S4 NO_POWER was induced by direct disconnect_nodes; global depletion appears only in B1 combined diagnostic. Preserve these distinctions even though the mechanical index passes.
Changed files in repair29 (all under this directory): ORDER_AUDIT.md; order-audit.json; D05_REMAINING_ORDER_CANDIDATE.md; D05_REMAINING_ORDER_CANDIDATE.json; CHECKER_PROTOCOL.md; EVIDENCE_COLLECTION.md; P04_ORDER_EVIDENCE_PROTOCOL.json; CURRENT_STATUS.md; REPAIR29_STATIC_SOURCE.json. Product/checker/registry, native footprint, staged inputs, raw and historical runbooks are unchanged.
@@ -0,0 +1,130 @@
{
"task_id": "P04-01",
"revision": "repair29",
"status": "approval candidate only; SOURCE-READY / NOTRUN",
"approval": null,
"apply_to_product_or_checker": false,
"review_flow": "Root asks owner after review. This document neither requests approval from worker nor records it.",
"proof_legend": {
"R": "B/audit-support/p04-raw-collect-r22",
"I": "B/p04-evidence/index.json schema2",
"pins": "REPAIR29_STATIC_SOURCE.json; R/MANIFEST.json and I raw_references/versions"
},
"choices": [
{
"id": "a",
"topic": "Power vs closure/dependency",
"status": "pending D05",
"observation": {
"status": "observed-current",
"behavior": "RELATED_FACILITY_INACTIVE selected before NO_POWER; both pause service with no charge.",
"source": "FacilityService _prepare_service_for_tick:853–874, phase FACILITY_COMPLETION after MANA projection",
"proof": "Root-measured R/s4.json isolated NO_POWER; R/s3.json B1 combined RELATED diagnostic; REPAIR29_STATIC_SOURCE.json source pins"
},
"inputs": "Same service and minute, related facility inactive and power unavailable; include direct closure separately under D-034.",
"A": {
"recommended": true,
"rule": "Keep current RELATED-first reason selection.",
"outcome": "Service held, progress/payment paused, reservation and serviceID retained.",
"side_effects": "Reason reports dependency while both causes apply; no new hold limit.",
"dependencies": "Approved dependency hold, D-034 direct closure, existing MANA-before-completion order."
},
"B": {
"rule": "NO_POWER wins reason selection when both conditions fail.",
"outcome": "Same no-charge hold safety; reason reports power.",
"side_effects": "Reason/event and recovery-precedence semantics would change; concrete implementation and exact-version proof require normal repair.",
"dependencies": "Must retain no-charge while either legitimate hold persists; preserve approved dependency reservation/identity behavior."
}
},
{
"id": "b",
"topic": "Destruction",
"status": "pending D05",
"observation": {
"status": "observed-current",
"behavior": "Command destruction in APPLY precedes completion. Incident destruction in INCIDENTS follows it; B4a shows25G charge then destruction in same tick.",
"source": "Runtime _process_tick_commands:5743, _advance_facilities:8482, _advance_defense:8577 / _apply_defense_outcome_boundary:9804",
"proof": "Root-measured R/s3.json B4a/B4b; REPAIR29_STATIC_SOURCE.json"
},
"inputs": "A service due for completion in a minute with command or incident destruction of its facility.",
"A": {
"recommended": true,
"rule": "Keep command-before-completion and incident-after-completion behavior.",
"outcome": "Command destruction prevents completion; incident may follow a valid completion/charge that minute; next-tick broken failure/release remains.",
"side_effects": "Completion and destruction can coexist in one tick as B4a; not a universal no-sale-on-destruction rule.",
"dependencies": "P04 stopped-charge and orphan-reservation safety; explicit D05 destruction authority required."
},
"B": {
"rule": "An incident in the same minute suppresses that minute completion (or voids it if already posted).",
"outcome": "No retained completion/sale for the incident-destruction minute.",
"side_effects": "Would require preemption or atomic reversal of completion, inventory, payment and rewards; no unapproved numbers or refund amounts supplied.",
"dependencies": "Owner must specify the suppress/void transaction semantics; preserve idempotency, no orphan reservations and approved shift/hold rules; normal implementation and new proof required."
}
},
{
"id": "c",
"topic": "Exit",
"status": "pending D05",
"observation": {
"status": "observed-current",
"behavior": "Command exit APPLY before completion/charging; AI PLANNED_EXIT after them; LEAVING despawns later.",
"source": "Runtime _execute_leave_facility_queue:7553; _advance_guest_ai_decisions:8738–8762",
"proof": "Root-measured R/s3.json B2a/B2b/B3 and B1 departure history; source pins REPAIR29_STATIC_SOURCE.json"
},
"inputs": "Exit command or AI exit due at a minute with a completion-ready service. Current AI PLANNED_EXIT applies to DECIDING guests; do not assume it preempts an active service.",
"A": {
"recommended": true,
"rule": "Keep current command/AI distinction and state predicates.",
"outcome": "Command leave/release happens first; eligible AI planned exit follows completion/charging and queue processing.",
"side_effects": "AI due time alone does not universally cancel current-minute completion; later despawn remains separate.",
"dependencies": "D-034, reservation ownership/release, phase6 completion before phase10 AI."
},
"B": {
"rule": "An exit due this minute preempts completion.",
"outcome": "Applicable due exits release/cancel before completion and no completion sale occurs for that preempted service.",
"side_effects": "Changes eligibility for exit and service cancellation; would change simultaneous completion/payment observations.",
"dependencies": "Owner must define applicable due-exit states; preserve no orphan reservation, no duplicate charge and approved dependency/shift behavior; normal repair and exact proof required."
}
},
{
"id": "d",
"topic": "Cost time/day attribution beyond A01 and18:00",
"status": "pending D05",
"observation": {
"status": "observed-current",
"behavior": "Sale dated at post-increment minute. At00:00 TIME_BOUNDARIES settlement/upkeep precede completions;00:00 sales go to new day because daily-close period_end is exclusive.",
"source": "Kernel advance_one_minute:122; Runtime _apply_service_transaction:11785 /11826–11838; coordinator _process_daily_close:1125 /1136",
"proof": "Root-measured R/s2a.json paid midnight/replay; I C; REPAIR29_STATIC_SOURCE.json"
},
"inputs": "Service completes on calendar boundary; account period ends at boundary minute. A01 ownership upkeep and18:00 shift interval remain fixed.",
"A": {
"recommended": true,
"rule": "Keep post-increment sale time and new-day attribution for00:00 sales.",
"outcome": "Closing day excludes boundary-minute completion; new day receives sale.",
"side_effects": "Closing summary is finalized before those sales; upkeep ownership rule unchanged.",
"dependencies": "Exclusive daily-close interval, sale timestamp, idempotent close/replay; P04 mandatory timing/attribution separate from D04/P05 numeric cost math."
},
"B": {
"rule": "Boundary-minute sales belong to closing day.",
"outcome": "Closing day includes those sales.",
"side_effects": "Would require a distinct accounting attribution or revised boundary transaction sequencing; affects daily summaries/reconciliation/replay. No numeric cost policy is invented.",
"dependencies": "Owner must settle attribution mechanics and same-boundary replay; preserve A01 and18:00, all P04 safety criteria; normal repair and exact-version proof required."
}
}
],
"bundle": {
"label": "accept current-behavior A for a-d",
"status": "pending D05",
"recommended": true,
"coupling_notes": [
"a preserves the approved hold and no-charge safety independent of reason priority.",
"b and c use the same completion boundary: commands before, incidents and AI after. Changing either requires separate applicability and replay checks.",
"d relies on TIME_BOUNDARIES before completion; changing attribution can affect the transaction history used by b/c and settlement idempotency.",
"A01 ownership upkeep, dependency hold and18:00 interval are already approved and are excluded from renewed approval.",
"Owner may explicitly rule some remaining items non-mandatory; no such ruling exists here. Unknowns stay pending; mandatory acceptance is never relaxed."
]
},
"authority_gap": "destruction_stop currently binds BASELINE:183, which is mana depletion, not destruction authority. Explicit D05 destruction rule required. Pin/registry repair only after approval through normal repair.",
"power_scope": "S4 NO_POWER uses direct disconnect_nodes; not proof of global depletion, which exists only in B1 combined diagnostic.",
"original_unit_complete": false
}
@@ -0,0 +1,93 @@
# D05 remaining order candidate — repair29
**Approval candidate only. SOURCE-READY / NOTRUN.** Root asks the owner after review. Nothing is applied to product, checker or registry; observation is not approval. A01 midnight ownership upkeep, dependency hold and18:00 are already approved and are not re-asked.
Structured choices: [D05_REMAINING_ORDER_CANDIDATE.json](D05_REMAINING_ORDER_CANDIDATE.json). Source path/line/SHA256 pins: [REPAIR29_STATIC_SOURCE.json](REPAIR29_STATIC_SOURCE.json); phase map: [ORDER_AUDIT.md](ORDER_AUDIT.md). R = B/audit-support/p04-raw-collect-r22; I = B/p04-evidence/index.json. These are Root-measured exact-version proof references, with raw/provenance pins in R/MANIFEST.json, I and the static manifest.
## (a) Power vs closure/dependency — pending D05
**Observed-current:** RELATED_FACILITY_INACTIVE selected before NO_POWER; both pause service with no charge. Source: FacilityService _prepare_service_for_tick:853–874, phase FACILITY_COMPLETION after MANA projection. Proof: Root-measured R/s4.json isolated NO_POWER; R/s3.json B1 combined RELATED diagnostic; REPAIR29_STATIC_SOURCE.json source pins.
**Inputs:** Same service and minute, related facility inactive and power unavailable; include direct closure separately under D-034.
**Option A (recommended; keep current behavior):** Keep current RELATED-first reason selection.
- Outcomes: Service held, progress/payment paused, reservation and serviceID retained.
- Side effects: Reason reports dependency while both causes apply; no new hold limit.
- Dependencies: Approved dependency hold, D-034 direct closure, existing MANA-before-completion order.
**Option B:** NO_POWER wins reason selection when both conditions fail.
- Outcomes: Same no-charge hold safety; reason reports power.
- Side effects: Reason/event and recovery-precedence semantics would change; concrete implementation and exact-version proof require normal repair.
- Dependencies: Must retain no-charge while either legitimate hold persists; preserve approved dependency reservation/identity behavior.
## (b) Destruction — pending D05
**Observed-current:** Command destruction in APPLY precedes completion. Incident destruction in INCIDENTS follows it; B4a shows25G charge then destruction in same tick. Source: Runtime _process_tick_commands:5743, _advance_facilities:8482, _advance_defense:8577 / _apply_defense_outcome_boundary:9804. Proof: Root-measured R/s3.json B4a/B4b; REPAIR29_STATIC_SOURCE.json.
**Inputs:** A service due for completion in a minute with command or incident destruction of its facility.
**Option A (recommended; keep current behavior):** Keep command-before-completion and incident-after-completion behavior.
- Outcomes: Command destruction prevents completion; incident may follow a valid completion/charge that minute; next-tick broken failure/release remains.
- Side effects: Completion and destruction can coexist in one tick as B4a; not a universal no-sale-on-destruction rule.
- Dependencies: P04 stopped-charge and orphan-reservation safety; explicit D05 destruction authority required.
**Option B:** An incident in the same minute suppresses that minute completion (or voids it if already posted).
- Outcomes: No retained completion/sale for the incident-destruction minute.
- Side effects: Would require preemption or atomic reversal of completion, inventory, payment and rewards; no unapproved numbers or refund amounts supplied.
- Dependencies: Owner must specify the suppress/void transaction semantics; preserve idempotency, no orphan reservations and approved shift/hold rules; normal implementation and new proof required.
## (c) Exit — pending D05
**Observed-current:** Command exit APPLY before completion/charging; AI PLANNED_EXIT after them; LEAVING despawns later. Source: Runtime _execute_leave_facility_queue:7553; _advance_guest_ai_decisions:8738–8762. Proof: Root-measured R/s3.json B2a/B2b/B3 and B1 departure history; source pins REPAIR29_STATIC_SOURCE.json.
**Inputs:** Exit command or AI exit due at a minute with a completion-ready service. Current AI PLANNED_EXIT applies to DECIDING guests; do not assume it preempts an active service.
**Option A (recommended; keep current behavior):** Keep current command/AI distinction and state predicates.
- Outcomes: Command leave/release happens first; eligible AI planned exit follows completion/charging and queue processing.
- Side effects: AI due time alone does not universally cancel current-minute completion; later despawn remains separate.
- Dependencies: D-034, reservation ownership/release, phase6 completion before phase10 AI.
**Option B:** An exit due this minute preempts completion.
- Outcomes: Applicable due exits release/cancel before completion and no completion sale occurs for that preempted service.
- Side effects: Changes eligibility for exit and service cancellation; would change simultaneous completion/payment observations.
- Dependencies: Owner must define applicable due-exit states; preserve no orphan reservation, no duplicate charge and approved dependency/shift behavior; normal repair and exact proof required.
## (d) Cost time/day attribution beyond A01 and18:00 — pending D05
**Observed-current:** Sale dated at post-increment minute. At00:00 TIME_BOUNDARIES settlement/upkeep precede completions;00:00 sales go to new day because daily-close period_end is exclusive. Source: Kernel advance_one_minute:122; Runtime _apply_service_transaction:11785 /11826–11838; coordinator _process_daily_close:1125 /1136. Proof: Root-measured R/s2a.json paid midnight/replay; I C; REPAIR29_STATIC_SOURCE.json.
**Inputs:** Service completes on calendar boundary; account period ends at boundary minute. A01 ownership upkeep and18:00 shift interval remain fixed.
**Option A (recommended; keep current behavior):** Keep post-increment sale time and new-day attribution for00:00 sales.
- Outcomes: Closing day excludes boundary-minute completion; new day receives sale.
- Side effects: Closing summary is finalized before those sales; upkeep ownership rule unchanged.
- Dependencies: Exclusive daily-close interval, sale timestamp, idempotent close/replay; P04 mandatory timing/attribution separate from D04/P05 numeric cost math.
**Option B:** Boundary-minute sales belong to closing day.
- Outcomes: Closing day includes those sales.
- Side effects: Would require a distinct accounting attribution or revised boundary transaction sequencing; affects daily summaries/reconciliation/replay. No numeric cost policy is invented.
- Dependencies: Owner must settle attribution mechanics and same-boundary replay; preserve A01 and18:00, all P04 safety criteria; normal repair and exact-version proof required.
## Bundle: accept current-behavior A for a-d
Recommended candidate, not approved.
- a preserves the approved hold and no-charge safety independent of reason priority.
- b and c use the same completion boundary: commands before, incidents and AI after. Changing either requires separate applicability and replay checks.
- d relies on TIME_BOUNDARIES before completion; changing attribution can affect the transaction history used by b/c and settlement idempotency.
- A01 ownership upkeep, dependency hold and18:00 interval are already approved and are excluded from renewed approval.
- Owner may explicitly rule some remaining items non-mandatory; no such ruling exists here. Unknowns stay pending; mandatory acceptance is never relaxed.
destruction_stop currently binds BASELINE:183, which is mana depletion, not destruction authority. Explicit D05 destruction rule required. Pin/registry repair only after approval through normal repair.
S4 NO_POWER uses direct disconnect_nodes; not proof of global depletion, which exists only in B1 combined diagnostic.
P04 timing/attribution remains mandatory; D04/P05 numeric cost math is separate. No acceptance criterion is relaxed. P04 remains incomplete; original13/88 unchanged.
@@ -0,0 +1,7 @@
{
"action": "wait",
"task_id": "P04-01",
"reason": "P04-01: WAIT. Waiting for the owner's Japanese answers on D05 (a) power vs closure/dependency precedence, (b) destruction vs completion, (c) exit vs completion, (d) which day a 00:00 sale belongs to. Do not re-ask, do not request-repair (repair30), do not redo tests.\n\nINDEPENDENT NEXT ORIGINAL UNIT (new contract proposal; no matching project in the 20-project inventory, nothing started here): P13-02 「背面条件と対象参照」.\n- Work: 覗き部屋の対象背面、通路寸断、対象喪失と証拠IDを状態として実装する。\n- Acceptance (unchanged): 対象撤去、重複収集、停止、途中保存で状態と参照が整合する。\n- Package P13 acceptance also applies: special rules hold at build time and run time; invalid placement and actions on lost targets rejected; event state saved; implemented scope reported separately from unmade content.\n- Package deps: P09, P12 (both incomplete; bounded progress is allowed, not unit closure). Decisions D04/D05/D08.\n- Original sources: B-2.5 (built behind VIPルーム/風俗個室/脱衣所 on back layer; its cells are no longer usable as back corridor; 記録係 collects 脅迫ネタ); B-8.3 (VIP/浴場/風俗の裏限定・裏通路を寸断); B-10.6 (覗き部屋 2x1, back-only).\n\nSOURCE GAP (main 2f3884b): no peeping/覗き code, data or tests in scripts/autoload/data/resources/tests/tools.\n- FacilityCatalog (scripts/data/facility_catalog.gd) has no peeping_room.\n- No recorder role; no back-side target reference; no evidence-ID ledger; no target-loss state.\n- Existing targets: public_bath, adult_private_room. VIP suite is undefined (P10-01); vip_private_salon must not substitute.\n- Rejected alternatives:\n - P07-01: weather_timeline has no rain/fog effects or natural generation (D04 values).\n - P12-01: security_station only checks the guard role (simulation_runtime.gd:6631); guard effects need D04 values.\n - P15-02: cleric witness/morale rule needs an undecided definition of \"witness\" plus a D04 magnitude.\n - P16: wages/severance/sale amounts are D04.\n\nMECHANISMS POSSIBLE WITH APPROVED INPUTS vs PENDING:\n- Possible:\n - placement check: room cells must lie entirely behind a single allowed, completed target's FRONT footprint on the BACK layer;\n - corridor blocking as an occupancy rule with no automatic bypass;\n - stable target reference;\n - target removal sets TARGET_LOST; no automatic recovery, explicit relink only (D03 pattern / kitchen relink);\n - idempotent evidence IDs keyed by (room, target, source_event_key);\n - no collection while stopped (NO_POWER/closed/under construction);\n - versioned save section with legacy-absent migration and atomic rejection of malformed data.\n- Pending (record, do not invent):\n - build cost/materials/build_minutes/upkeep (D04); FacilityDefinition requires them, so no normal palette registration;\n - recorder role and staffing, collection trigger/rate (D04/D08/P16);\n - VIP suite target (P10-01);\n - D05 ordering;\n - blackmail use and camera UI (P19/P24).\n\nBRIEF: Add a separate PeepingRoomService connected from the Runtime; no rewrite of the whole runtime.\n- Reuse world_service.cells_for_footprint/validate_occupancy/occupy and construction_service.validate_placement.\n- Copy the weather snapshot-version pattern (simulation_runtime.gd:29/520/663/1248).\n- Hook facility removal so the target is marked lost.\n- Add commands for placement validation, explicit relink and evidence recording.\n- No product values, no content, no Clock/P04 change.\n\nALLOWED PATHS:\n- scripts/special/peeping_room_service.gd (new)\n- autoload/simulation_runtime.gd (bounded connection: save section, removal hook, commands)\n- scripts/core/save_service.gd (only if needed)\n- tests/special/test_peeping_room_*.gd\n- docs/plans/original-completion-2026-10-02/execution/p13-02/**\n\nLOCAL TESTS:\n- Valid public_bath and adult_private_room backs.\n- Rejections: front layer, partial overlap, non-target, incomplete target, VIP pending.\n- Corridor cell conflict and path disconnect.\n- Target demolition leads to TARGET_LOST; rebuilt target does not auto-relink; explicit relink works.\n- Duplicate event key yields a single evidence ID.\n- Stopped room rejects collection.\n- Save/restore round-trip, legacy save without the section, malformed restore leaves state unchanged.\n- Existing suites: construction/world/path, tests/supply/test_supply_save_migration.gd, tests/transport/test_transport_save.gd, tests/environment/test_runtime_weather.gd.\n\nREUSE / FULL REVIEW:\n- No completed P18/P23 rerun.\n- Full regression only on the exact final version, then a separate Claude review and normal integration.\n- No partial credit (formal 14/88 and original 30/88 unchanged); do not claim P13 or the backend complete.\n\nOwner must register the new task contract before any run.",
"codex_model": "gpt-6.1-sol",
"codex_model_reason": "P04-01 itself stays in wait, so no worker runs for it. For the proposed P13-02 batch: one new state service plus a bounded runtime connection. It follows existing patterns (weather snapshot versioning, kitchen explicit relink, world occupancy), uses no numeric balancing and no native code. Sol is sufficient on quality, time and usage. Switch to Astra only if review finds the runtime save-version change crosses many existing save paths."
}
@@ -0,0 +1,148 @@
# P13-02-CODE1 implementation handoff
This is non-graphic state/reference/occupancy/save machinery only. It does not
complete P13-02, grant partial credit, or change the original 30/88 denominator
or formal 14/88 count. Native execution and acceptance are pending.
## Declared scope and verification
Before editing, the worker declared the new service, bounded Runtime hooks,
special tests, narrow runner, marker additions and this documentation. SaveService
was conditional on an exact-key dependency; inspection found
`SupplyAutoPurchaseQuotePlans.valid_runtime_format` has that dependency.
Only allowed paths were edited. No asset, UI, content, model, policy, clock phase,
or P04 change is involved.
The full ignored `build/owner-handoff/ACTUAL_OPUS_RUN_DECISION.json` was read and
left untouched. Base HEAD is `1e8d4ea88876865a72547ff0edf43ed5b0e74c7e`.
The immutable spec was not edited. Its SHA-256 without the terminal newline is
the registered `8ea65f2eefedc772c08170186f5cd03ac017432f4b069ade4f9210d4215c2d43`;
the on-disk file including that newline is
`988d6e18a49372549863cd433432c2852c962fa64b138e490361c023e80249dc`.
Worker verification: Python AST parsing/compilation only, without executing the
runner or importing its dependencies; source/JSON/hash review. GDScript parsing,
all tests, `--prepare-only`, native collection and regression were **not run**.
No check totals or native success receipts are claimed. No git writes, commits,
branches, other agents, integration or Runner operations were performed.
## Service and commands
`PeepingRoomService` is a separate RefCounted service with no content or UI.
All command executors use the existing Runtime queue; queue/history receipts
remain normal Runtime behavior even for rejected/read-only domain commands.
| Command | Preconditions and result |
| --- | --- |
| `peeping_room_validate` | `origin: Vector3i`, optional `footprint: Vector2i` (2x1), optional `target_instance_id: String/StringName`. Pure domain validation. |
| `peeping_room_place` | Always `BUILD_DEFINITION_PENDING_D04`; no occupancy, resource, room or ID mutation. |
| `peeping_room_relink` | Existing `room_id`, explicit nonempty `target_instance_id`; full geometry and ownership validation excluding only the room's exact own occupancy. Leaves `LINKED`, stopped, `RELINKED_PENDING_RESUME`. |
| `peeping_room_record_evidence` | Existing `room_id`, nonblank named `source_event_key`. Uses Runtime minute, never caller-supplied time. Checks stopped, target power, target closure/opening hours, completed construction authority, and lost target in that order. Otherwise rejects with `RECORDER_ELIGIBILITY_PENDING_D04_D08_P16`. Never writes the ledger. |
Malformed command field types return `INVALID_PAYLOAD`. Missing/blank source keys
return `SOURCE_EVENT_KEY_REQUIRED` before operational checks. Loss latches both
`TARGET_LOST` and stopped, so collection after normal demolition returns `STOPPED`
while the room's link/stop reason identifies `TARGET_LOST`. No resume command or
automatic resume is defined. Power/closure guards read actual target conditions;
they do not define special-room power demand, staffing or normal operation.
Placement is exactly 2x1 BACK, fully behind a single completed FRONT
`public_bath` or `adult_private_room`. It checks bounds/excavation, both real
FacilityService and ConstructionService ownership, FRONT cells, World occupancy,
and both World walkability and PathService membership. Exact rejection families:
`WRONG_LAYER`, `WRONG_FOOTPRINT`, `OUT_OF_BOUNDS`, `NOT_EXCAVATED`,
`TARGET_INCOMPLETE`, `TARGET_MISSING`, `PARTIAL_TARGET`, `MULTIPLE_TARGETS`,
`TARGET_MISMATCH`, `TARGET_UNKNOWN`, `TARGET_NOT_ALLOWED`, `TARGET_WRONG_LAYER`,
`CORRIDOR_CONFLICT`, `BACK_OCCUPIED`. The named `vip_suite` request returns
`PENDING_P10_01`; `vip_private_salon` is not an allowed substitute.
Any existing corridor cell conflicts. A proposed cut through a connected corridor
is rejected before mutation, preserving the route; no reroute or bypass is
invented. Accepted fixture cells were already nonwalkable and become occupied
under `special_peeping_room`. No special-room construction weight/cost is assumed.
Runtime demolition and FacilityService unregistration latch loss. Collection also
detects missing FRONT occupancy/identity. Rebuilding the same cells produces a
different construction ID and never silently reattaches rooms. Relink is explicit.
## CONTROLLED_FIXTURE boundary
Only service methods named `controlled_fixture_place`,
`controlled_fixture_set_stopped`, and `controlled_fixture_record_evidence` create
test rooms, enable fixture collection, or write evidence. They are labeled
CONTROLLED_FIXTURE in code and tests. They have no command/palette registration,
and no Runtime executor calls them. Test helpers disclose direct underground
geometry setup and MIMI registration; those do not assert natural unlock/join or
production eligibility. Target construction uses existing definitions/costs/times.
Room IDs come from the existing StableIdGenerator's `peeping_room` counter.
Evidence IDs encode the UTF-8 lengths and hex bytes of the full
`(room_id, target_instance_id, source_event_key)` tuple. This is injective rather
than delimiter concatenation or a hash with possible collisions. Replays return
the existing ID with `duplicated=true` and retain the first minute. Evidence is
only IDs, source key and minute. Room `target_history` retains prior bindings so
relink does not orphan existing opaque evidence.
## Save invariants
Runtime versions remain 14 and 15, with version 15 only for existing v2 purchase
history. Optional canonical StringName key `special_peeping_rooms` has section
version 1 and exact keys `version`, `rooms`, `evidence`. Empty service state emits
no key, preserving original snapshots. Absent sections restore empty only if no
world occupancy uses the special kind or `peeping_room.` prefix. Thus removing
the section from a current room-bearing save is rejected without a version bump.
Restore stages the entire section against staged world, path, facilities,
construction and ID generator before committing any Runtime state. It checks
canonical keys/types, version, duplicate room/evidence identities, deterministic
evidence tuple encoding, bounds/geometry, room/occupancy correspondence in both
directions, generator high-water mark, known historical facility IDs, present
target definition/geometry, loss/stopped coherence, and evidence room/history/time
references. Null/present-empty sections are invalid; absence is the only empty
encoding. Existing pending command/reference and schema migration checks remain.
SaveService validates a present section through the same staged service validator,
then supplies a shallow copy without this one key to the original purchase-format
allowlist. No other keys are removed. The original format 1 (Runtime 1–14),
format 2 (Runtime 15), manifest duplicate 15 and MIMI checks remain unchanged.
## Verification handoff
Five strict suites cover geometry/corridor, removal/relink, evidence/guards,
typed atomic save corruption and physical format 1, and Runtime commands plus
physical MIMI format 2. Tests use `var_to_bytes` for whole Runtime atomicity and
roundtrip checks. New marker rows carry final test source hashes; prior rows and
policy are unchanged. A helper under `tests/special/` is not a discovered suite.
`tools/run_p13_reference_tests.py` defaults to read-only verification of
`$BUILD_OUTPUT_DIR/p13-reference-native`, failing closed without an absolute
environment path. Explicit `--output --collect` is for Root only. The strict flag
parser rejects abbreviations, repeated flags, positional inputs and `=` aliases.
`--prepare-only` is non-native but was not executed by this worker.
The runner imports the existing P18 core by path. Since its three entry functions
hardcode their label and seven/nine counts, a bounded AST adapter changes only
protocol/runner identities, those explicit roster cardinalities, and diagnostic
labels. It checks the exact adaptation-site counts and fails closed on drift.
All confinement, inventory, JSON, sealing, source/engine/marker/policy binding,
process, diagnostic, profile and cleanup gates are reused. It neither copies the
whole runner nor modifies P18/helpers. The whole selected source map binds both
runner sources. Phase count derives from `len(ROSTER) + 2`.
Roster includes all five new suites and existing construction/world/path/runtime
construction, supply migration, transport save, Runtime weather, snapshot
serialization, save lifecycle and MIMI purchase suites. Receipts retain
`formal_acceptance=false` and `original_unit_complete=false`.
Root must perform serialized native collection with the allocation/private
profile, then registered `p13-reference` validation, a separate actual Opus
review, and the final exact-version required regression. Only those steps can
establish execution results.
## Still pending, without invented values
D04 build/upkeep/build minutes and other product numbers; recorder staffing and
natural triggers/rates D04/D08/P16; VIP suite P10-01; D05 transaction decisions
(no tick-phase changes here); P19 evidence use and P24 camera UI; normal palette
registration/construction/operation and natural production evidence; whole P13
acceptance, final review/integration, and applicable native Windows conditions.
@@ -0,0 +1,65 @@
{
"id": "P13-02-CODE1",
"parent_original_delivery_unit": "P13-02",
"parent_work": "覗き部屋の対象背面、通路寸断、対象喪失と証拠IDを状態として実装する。",
"parent_acceptance": "対象撤去、重複収集、停止、途中保存で状態と参照が整合する。",
"original_denominator": {
"packages": 30,
"units": 88,
"formal_complete_at_registration": 14,
"partial_credit": false
},
"whole_parent_acceptance": false,
"scope": "Non-graphic state/reference/occupancy/save machinery connected to real Runtime; no sexual depiction, camera content or blackmail action; this registered batch is not the whole original unit.",
"authority": [
{
"ref": "BASELINE:52-53",
"text": "Target FRONT VIP room/private room/changing area BACK; occupied room cells cannot be back corridor; recorder collects evidence."
},
{
"ref": "BASELINE:167-174",
"text": "VIP suite/public bath/private room explicitly peeping-compatible; restricted behind these target types and cuts back corridor."
},
{
"ref": "BASELINE:199-209",
"text": "Peeping room 2x1 BACK. Current public_bath/adult_private_room target definitions exist; missing VIP suite must remain missing, vip_private_salon is not a substitute."
}
],
"implementation_requirements": [
"Introduce separate PeepingRoomService, bounded real Runtime wiring; no whole runtime rewrite.",
"Validate 2x1 BACK footprint entirely behind one allowed completed FRONT target, integrate existing construction/world occupancy rules; reject wrong layer, partial/multi-target overlap, unknown/missing/incomplete target and corridor conflicts.",
"Stable room/target identity with target removal/loss detection; reconstructed different target is not silently the old identity; explicit validated relink only, preserving stopped/no-auto-resume rules.",
"Idempotent evidence IDs bound to stable room/target/source event key; replay cannot duplicate or alias another target. Opaque state records only.",
"Collection rejects stopped/no-power/closed/under-construction/lost-target cases; do not create undefined natural trigger/rate/staffing eligibility.",
"Versioned Runtime snapshot section; genuinely legacy absent section migrates empty; current-schema missing/malformed/unknown/wrong-reference/duplicate data reject atomically with original whole Runtime untouched. Preserve all existing schema migrations and pending references.",
"No free production placement, bypassed build costs or arbitrary content-event injection exposed through new commands. Unknown build/upkeep/staff/collection values remain unset and unavailable; backend tests may use clearly labeled controlled fixtures. Normal palette registration and naturally collected production evidence are pending. Define command preconditions precisely; construction costs/definition and recorder eligibility cannot be silently invented.",
"Reuse existing guarded native harness logic for a strict narrow runner and add new test marker registrations without weakening prior marker/policy behavior. Do not rerun full regression during implementation."
],
"required_local_coverage": [
"public_bath and adult_private_room valid geometry; VIP unavailable not substituted",
"wrong FRONT, partial/multiple target footprint, incomplete/missing target; corridor/path occupancy conflict/disconnection",
"target demolition/loss, rebuild different identity, explicit relink; reject collection after removal",
"same event replay one evidence ID; different room/target keys distinct and stable",
"stopped/no-power/closed/under-construction collection rejection",
"roundtrip exact typed state; legacy absence; current missing/malformed version/references/duplicates atomic unchanged",
"Runtime command/removal/save integration; existing construction/world/path/supply-save/transport-save/weather migrations impact coverage"
],
"pending_not_invented": [
"D04 build/upkeep/build_minutes and related numbers",
"recorder role staffing and natural collection trigger/rate D04/D08/P16",
"VIP suite P10-01",
"D05 unresolved transaction rules; no tick-phase changes",
"P19 use of evidence and P24 camera UI",
"normal construction/operation/full parent acceptance, final whole review and applicable Windows conditions"
],
"workflow": [
"Actual Opus commander confirms registered run and model; Runner worker only edits allowed paths.",
"Worker static/local preparation only; Root owns serialized native collection in allocation build with private profile and guarded process/cleanup receipts.",
"Registered validation reads/verifies complete native evidence, exact current selected source and marker/policy/engine/input/environment binding. Zero exit alone is not acceptance.",
"Separate actual Opus review, final exact-version required regression and ordinary integration/final; any backend completion never adds parent original-unit credit."
],
"model_proposal": {
"codex": "gpt-6.1-sol",
"selected_by_actual_opus_run": "e65d48f5a7294378a81bb58dea00c605"
}
}
@@ -0,0 +1,49 @@
{
"scope": "Authoritative limited-case factual clarification after separate Opus review. Original primary files kept unchanged, no new gameplay/OS execution",
"source": {
"S": "fe44f550750acbf5c510346e7cacbea2ccbdd184",
"M": "565fd805079d8c446f29e30c57979242561113ea",
"Q": "42989fd90f5f83db86f846eb42b5cf2d847461a5",
"T": "905d844d523529862259d1b7a210fd1e7964f054"
},
"actual_review_run": "b4160dbc2bca407598d2fc2e22bff24f",
"actual_pause_seconds": 89.116049,
"actual_clock_samples": 824,
"sample_count_scope": "824 clock/paused-state samples, not 847 (which was sequence span); none of the per-sample rows contains a full-model digest",
"model_identity_scope": {
"checkpoints": {
"paused_before_menu": 2254,
"new_slot_dialog": 2565,
"cancelled": 2797
},
"digest": "077b7b8106f2448586e2ca9617e7c5525f7a7f90a71d12928a089cbe7ef1d633",
"binary_sha256": "7a166acfe98c39dc4432058b054e66aaa5f28485dc78ae9b406d8fa2b35204f3",
"continuous_model_identity_not_proven": true
},
"focus_scope": {
"root_viewport_focus_owner_unchanged": "/root/Main/@MarginContainer@13/@VBoxContainer@14/TopBar/@HBoxContainer@15/@Button@42",
"dialog_label_focused_on_open": true,
"dialog_label_unfocused_after_cancel": true,
"restoration_mechanism_proven": false
},
"input_scope": {
"actual_CUA_clicks": 7,
"root_mouse_rows": 7,
"embedded_popup_and_dialog_native_mouse_rows": false,
"embedded_action_evidence": "Actual tool-time windows + actual production menu3/cancel callbacks, not a native-parent mouse ACK",
"CUA_log": "exact semantic transcription after close, not a machine-emitted CUA log; first6 before hashes null; after hashes preserved; CUA screen byte files not in local material",
"independent_pixels": "five actual viewport PNGs inspected by Opus, never claimed as CUA images"
},
"schema_scope": {
"original8_denominator_unchanged": true,
"whole_verify": "honest incomplete rejection at placement group, no modal coverage loop inside fullverify",
"supported_record_primitives": "Root checked nonopaque fields/provenance/monotonic receipt range; later exact pointer probe documented separately",
"correction_file": "SUPPLEMENT_ACTUAL_POINTER_PROBE.json"
},
"private_data_scope": "empty pending queue; fresh-profile manual package absent; no existing-save preservation or nonempty pending case inferred",
"normal_exit": "owned syntax21759 and OS21770 exited0, all reader/source/default-player/cleanup guards0; both fresh profiles fully retained then cleaned",
"remaining_original_conditions": "all8 unaccepted; whole formal review/full roster/normal integration-final/Windows and all unexecuted cases stay required",
"original_formal_units": 14,
"new_credit": 0,
"at_unix_ns": 1792221809906511000
}
@@ -0,0 +1,17 @@
# 現在と次の成果単位(2026-10-17)
正式完了は14/88成果、30パッケージ。今回の限定ケースによる完了加算は0。
P24-02はin_progress、Runner提出fe44f550750acbf5c510346e7cacbea2ccbdd184、通常統合候補なし。実main565fd805との準備合成Q42989fd9/T905d844dで通常OS操作を採取した。Qは証拠採取用で、正式統合候補ではない。
通常メニューから別名保存ダイアログを開き、取消して再開し、通常ウィンドウ終了した。824回の時刻・停止サンプル(89.116049秒)で停止を確認し、3節目のモデルが一致した。独立Claude Opus5.5セッションb4160dbc2bca407598d2fc2e22bff24fはこの限定範囲でpass、critical/high/medium0。全8原条件のレビューではなく、フォーカス復元機構・既存保存・非空コマンド列の保全は証明していない。厳密な限界は同梱のAUTHORITATIVE_NARROW_CASE_CLARIFICATIONS.jsonを正とする。
P24残件は全8原条件、配置と無効ドロップ、確認・復元、IME、倍率、ダイアログ背後の有効対象、吹出し・ログ・代替操作、重要警告の自然発生、最終全回帰・正式独立レビュー・通常統合final・同一Windows等。重要警告はP18/P19/P21等の実装に依存するため、限定プローブだけを積み増さない。原条件を縮小しない。
次の優先候補はOpus実判断6004541957cd42cf9bae1868df1a31c8が選定したP04-01「同時発生の更新規約」。閉店・停電・破壊・退出・課金・交代・00:00決算の全7領域について、停止中課金0・二重精算0・孤立予約0を満たし、全15条件+EVの版付き証拠、必要検証、独立した全体レビュー、通常統合final、台帳反映まで必要。P06等の基盤で既存証拠が多い点を選定理由とする。
選定判断に含まれたaccd時点の不足推定を現状態へ読み替える。実Runner再確認ではP04提出は2dde7596、repair29、未稼働、worktree差分0。登録validationはpassでも正式レビュー275d1fd6はD05残4規則未確定などにより不合格。再修正や再試験はまだ起動していない。最新29の実差分と原条件をOpusへ提示し、既修正箇所を再実装せず、残4規則の必須性・具体的選択肢・独立して進める残修正を再判断中。既存2承認を維持し、未回答を承認扱いにしない。
古いP04文書の13/88や旧mainは作成時点の履歴であり、現時点の正式数・適用版として再利用しない。全条件が揃うまでP04も完了加算しない。
最新再判断ea12167c:raw結合・getter・HEAD fixture等は既に修正29までに是正済み。重複修正を起動しない。残る規則の具体的選択肢をユーザーへ提示した。回答後に破壊根拠pin/承認記録/現況説明を1回にまとめて通常修正し、必要な最終ゲートへ進む。回答を推定せず、記録のみによる完了加算もしない。
@@ -0,0 +1,34 @@
{
"created_unix_ns": 1792222099990910000,
"files": [
{
"file": "AUTHORITATIVE_NARROW_CASE_CLARIFICATIONS.json",
"source": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/coordinator-os-scenario-20261017-r01/AUTHORITATIVE_NARROW_CASE_CLARIFICATIONS.json",
"sha256": "fd83e2edd4ac00bc9f8c568f6283ee47af43f91ef06336d36d775508a96682a5",
"bytes": 2833
},
{
"file": "ACTUAL_OPUS_LIMITED_REVIEW.json",
"source": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/coordinator-os-scenario-20261017-r01/ACTUAL_ONE_SCENARIO_INDEPENDENT_REVIEW_RESULT_MIRRORED_R02.json",
"sha256": "f9feeb5b18d3e67c2b6bd72d130068e856c9145cde89951519169549c2985e16",
"bytes": 141526
},
{
"file": "ACTUAL_OPUS_NEXT_UNIT_SELECTION.json",
"source": "/Users/korizatou114/Library/Application Support/agent-control/the-tree-p24-02-operations/runs/6004541957cd42cf9bae1868df1a31c8/result.json",
"sha256": "777c7f73e43df8801adfc29b9b0facb0474dba79fc5e8f11883d79e6ab3a8c92",
"bytes": 7523
},
{
"file": "FRESH_BINDING_AND_SOURCE_APPLICABILITY.json",
"source": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/coordinator-os-scenario-20261017-r01/FRESH_BINDING_AND_SOURCE_APPLICABILITY.json",
"sha256": "f01469d2d8a985750ca4103591067b63db7a319c015b493ad6635640247a3102",
"bytes": 307105
}
],
"raw_capture_preserved_at": "/Users/korizatou114/Projects/TheTree-managed-worktrees/p24-02-operations/.runtime/P24-02/build/audit-support/p24-os-normal-r01/capture",
"formal_credit": 0,
"original_packages": 30,
"original_units": 88,
"original_complete": 14
}
@@ -254,6 +254,6 @@
"validate_facility_value_contracts.py": "91640e2a76cd6cc9186f7b85c0bf379b24b6cac0d48962815235ee628e7ae43e",
"validate_plan.py": "23678227d9b3c556f1bd903f4b5b3147c4a82ce5085e10055481026803451b80",
"validator_update_checks.json": "f997d0f3de2cea29550840b1d5cb23647d64f81329de46758551e2b6c8fecc27",
"work_packages.json": "238c01a360ac9d8554d7f12586f3b34925b37365a04aacc477877b807e76c16a"
"work_packages.json": "cd70846e0701396a3492cbab95aed9a3272cb108a08f9920b9c28e46c21e7361"
}
}
@@ -3598,7 +3598,7 @@
},
"legacy_state": "in_progress",
"state_scope": "package-level; completed means whole package accepted; partial implementation is not completion",
"current_summary": "現行1338sourceでS1/S2a/S2b/S3実測と正式復元を収集済み。実Opus/Astra18が動的raw収集/各series検証を実装し、Rootも実data・新規拒否fixture・既存Cをfile-onlyで各exit0再確認、既存Cブロック全bytes不変。担当が全体未達を理由にblocked応答したため未commitコードを全保持し通常repair19へ継続、goal停止なし。残3条件は停電/18:00の既存raw参照と保存getter型説明・厳密適用性を補正し、A実HEAD/tree/FS結合・旧fixture整合を実装する。getter追加APIの配列型差分を旧説明が網羅していなかった点はnoticeで訂正、正式全Runtime型付き復元一致の実測は保持。全原15+EV/7領域/安全性3結果/30-88/部分点0、必須whole・独立wholereview・通常integration/final未達、原成果加点0。",
"current_summary": "次に閉じる優先候補。実Runnerは提出2dde7596・修正29・repair_pending・未稼働、worktree差分0。実Opus ea12167cが最新29を再監査し、旧台帳のraw結合/getter/HEAD fixture等は既修正と確認、重複repairを起動しない。登録validationはpassでも正式レビュー275d1fd6はD05規則未確定等で不合格。破壊順序・00:00売上帰属と理由表示/退出の明文化を具体案で確認中。既承認2規則維持。全15+EV/7領域/安全性3結果/全条件・必須最終全回帰・独立wholeレビュー・通常integration/finalは維持。正式14/88、今回加算0。",
"remaining_deliverables": [
{
"id": "P04-01",
@@ -3851,38 +3851,41 @@
"sha256_at_integration": "dfd9665ec1a8922201ce325c70505e7bf2d880a044daa49dddd92241007a438f",
"scope": "S3 bounded raw proof only; six actual native cases/formal22 slots/176phase pairs/16clock replay pairs; no whole original credit",
"linked_at_jst": "2026-10-16T04:54:54.811581+09:00"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01-current-recheck-20261017/CURRENT_ACCEPTANCE_STATUS.json",
"sha256": "908111f64a3d6c206504e26e76c721a0a97864238f6f6bb6604ac7b8e31ce7bf",
"scope": "Actual latest29 state and Opus re-audit supersede stale repair19 remaining work; zero formal credit"
}
],
"current_summary": "現行1338sourceでS1/S2a/S2b/S3実測と正式復元を収集済み。実Opus/Astra18が動的raw収集/各series検証を実装し、Rootも実data・新規拒否fixture・既存Cをfile-onlyで各exit0再確認、既存Cブロック全bytes不変。担当が全体未達を理由にblocked応答したため未commitコードを全保持し通常repair19へ継続、goal停止なし。残3条件は停電/18:00の既存raw参照と保存getter型説明・厳密適用性を補正し、A実HEAD/tree/FS結合・旧fixture整合を実装する。getter追加APIの配列型差分を旧説明が網羅していなかった点はnoticeで訂正、正式全Runtime型付き復元一致の実測は保持。全原15+EV/7領域/安全性3結果/30-88/部分点0、必須whole・独立wholereview・通常integration/final未達、原成果加点0。",
"current_summary": "次に閉じる優先候補。実Runnerは提出2dde7596・修正29・repair_pending・未稼働、worktree差分0。実Opus ea12167cが最新29を再監査し、旧台帳のraw結合/getter/HEAD fixture等は既修正と確認、重複repairを起動しない。登録validationはpassでも正式レビュー275d1fd6はD05規則未確定等で不合格。破壊順序・00:00売上帰属と理由表示/退出の明文化を具体案で確認中。既承認2規則維持。全15+EV/7領域/安全性3結果/全条件・必須最終全回帰・独立wholeレビュー・通常integration/finalは維持。正式14/88、今回加算0。",
"remaining_conditions": [
"原7種更新順序・証拠対応の原本/承認済み仕様への全条件適合性と規約凍結を最終独立受入する",
"承認D05の依存先休業pause/resume日跨ぎと正式SaveService/別PID復元はmain5f6bc11で実測済み。既存証拠と残の原7領域全条件への適合性・独立whole受入を残す。直接休業D-034と区別する。",
"承認18:00完了後交代/同分再送/実00:00決算、夜番不在/残業に加え、停電+直接休業/退出/元忍耐自然枯渇/破壊の原残境界と正式22slot再生をS3 accdで収集済み。全原条件raw結合・適用性・独立whole受入は未達。",
"既存39証拠等の適用版・入力・設定・環境を照合して不足境界だけ検証。全条件独立受入と通常統合/final/台帳反映。D05他領域は具体的根拠を確認し一括解決/一括停止にしない"
"owner choices for destruction order and midnight-sale day, plus explicit disposition of reason label and command/AI exit",
"after actual answers, normal batched checker destruction-authority pin / registry / approval record / stale current metadata correction",
"final gates as listed; previous full178 f5 receipt is not full final checker a61 evidence; no relabeling"
],
"progress_summary": "現行1338sourceでS1/S2a/S2b/S3実測と正式復元を収集済み。実Opus/Astra18が動的raw収集/各series検証を実装し、Rootも実data・新規拒否fixture・既存Cをfile-onlyで各exit0再確認、既存Cブロック全bytes不変。担当が全体未達を理由にblocked応答したため未commitコードを全保持し通常repair19へ継続、goal停止なし。残3条件は停電/18:00の既存raw参照と保存getter型説明・厳密適用性を補正し、A実HEAD/tree/FS結合・旧fixture整合を実装する。getter追加APIの配列型差分を旧説明が網羅していなかった点はnoticeで訂正、正式全Runtime型付き復元一致の実測は保持。全原15+EV/7領域/安全性3結果/30-88/部分点0、必須whole・独立wholereview・通常integration/final未達、原成果加点0。",
"progress_summary": "次に閉じる優先候補。実Runnerは提出2dde7596・修正29・repair_pending・未稼働、worktree差分0。実Opus ea12167cが最新29を再監査し、旧台帳のraw結合/getter/HEAD fixture等は既修正と確認、重複repairを起動しない。登録validationはpassでも正式レビュー275d1fd6はD05規則未確定等で不合格。破壊順序・00:00売上帰属と理由表示/退出の明文化を具体案で確認中。既承認2規則維持。全15+EV/7領域/安全性3結果/全条件・必須最終全回帰・独立wholeレビュー・通常integration/finalは維持。正式14/88、今回加算0。",
"remaining_gaps": [
"既存CとS1/S2a/S2b/S3のraw収集/各series検証は実装済み、Root実data/新fixture/C各exit0。停電はS3実power flagと復旧前後、18:00はnative-first-current actual-nativeの正しい生証拠へ結合する。全原15+EV適用性を揃える。",
"save_restoreの正式全Runtime var_to_bytes一致は保持。追加API rawgetterに既存source _to_snapshot_variantが配列型制約も変換する点を旧説明が見落としたため、原frozen条件とsource定義のcanonical契約へ厳密に照合し訂正する。JSON-only/盲目的正規化/原基準緩和は禁止。",
"Aの実候補HEAD/tree/FS照合、旧MAIN/metadata数固定とcandidate_tree自己申告の穴、旧negative/applicability fixture失敗を直す。C全bodyと改ざん拒否は保持。",
"原7領域/安全性3結果/全条件と必須whole検証・別セッション独立wholeレビュー・通常integration/final・台帳反映を完結する。原成果加点0。"
"owner choices for destruction order and midnight-sale day, plus explicit disposition of reason label and command/AI exit",
"after actual answers, normal batched checker destruction-authority pin / registry / approval record / stale current metadata correction",
"final gates as listed; previous full178 f5 receipt is not full final checker a61 evidence; no relabeling"
],
"updated_at_jst": "2026-10-16T05:25:51.943207+09:00",
"current_recheck": "execution/p04-01-current-recheck-20261015/CURRENT_ACCEPTANCE_STATUS.json",
"policy_candidate": "execution/p04-01-current-recheck-20261015/D05_POLICY_CANDIDATE.md",
"updated_at_jst": "2026-10-17T16:30:38.746525+09:00",
"current_recheck": "execution/p04-01-current-recheck-20261017/CURRENT_ACCEPTANCE_STATUS.json",
"policy_candidate": "execution/p04-01-current-recheck-20261017/D05_REMAINING_ORDER_CANDIDATE.md",
"owner_policy_update": {
"approved": true,
"reference": "docs/plans/original-completion-2026-10-02/execution/p04-01-current-recheck-20261015/D05_OWNER_APPROVAL.json",
"scope": "two owner policy selections only; no acceptance credit",
"remaining": "condition-specific evidence applicability, missing boundaries, independent review, ordinary integration/final",
"actual_commander": "execution/p04-01-current-recheck-20261015/OPUS_REPAIR18_FULL_INPUT_CONTINUATION_DECISION.json",
"runner_state": "repair_ready",
"repairs": 19,
"worker_model": "gpt-6-astra",
"actual_commander": "execution/p04-01-current-recheck-20261017/ACTUAL_OPUS_LATEST29_DECISION.json",
"runner_state": "repair_pending",
"repairs": 29,
"worker_model": null,
"model_selected_by": "actual Claude Opus 5.5 run decision",
"run_decision": "execution/p04-01-current-recheck-20261015/OPUS_REPAIR18_FULL_INPUT_CONTINUATION_DECISION.json",
"submitted": "accd07c91d4e34d9b7c7fc20e389df2424b167e1",
"registered_validation": "0689f0070bd54d4f8b5849bb63bb36a8",
"run_decision": null,
"submitted": "2dde7596a87c43f7bf0bf704b7479f2fa06a5b1c",
"registered_validation": "91d92e164b164bb091ae90e384da5636",
"root_work_continues": true,
"native_shift_proof": "execution/p04-01-current-recheck-20261015/ROOT_APPROVED_SHIFT_CURRENT_RESULT.json",
"incomplete_checkpoint": "execution/p04-01-current-recheck-20261015/REPAIR7_PRESERVED_WORK.json",
@@ -3891,7 +3894,7 @@
"formal_dependency_proof": "execution/p04-01-current-recheck-20261015/ROOT_APPROVED_DEPENDENCY_FORMAL_RESULT.json",
"timeout_adapter": "execution/p04-01-current-recheck-20261015/OWNER_P04_LLM_TIMEOUT_ADAPTER.json",
"actual_run": null,
"current_scope": "Preserved executable R; next actual Opus direction for missing raw joins/getter type correction and real candidate A/fixtures. No new registered validation of unchanged accd.",
"current_scope": "Latest29 audited; no worker or repair launched. Owner D05 answers pending; normal bounded authority/record correction only after actual answer. Existing two approvals unchanged.",
"paid_shift_midnight_formal_proof": "execution/p04-01-current-recheck-20261015/ROOT_PAID_SHIFT_MIDNIGHT_FORMAL_RESULT.json",
"same_minute_formal_proof": "execution/p04-01-current-recheck-20261015/ROOT_SAME_MINUTE_RESEND_FORMAL_RESULT.json",
"corrected_c_bundle": "execution/p04-01-current-recheck-20261015/ROOT_CORRECTED_C_BUNDLE_LOCAL_PASS.json",
@@ -3902,9 +3905,21 @@
"execution/p04-01-current-recheck-20261015/ROOT_S2B_NATIVE_R02_RESULT.json",
"execution/p04-01-current-recheck-20261015/ROOT_S2B_NATIVE_R01_RESULT.json",
"execution/p04-01-current-recheck-20261015/ROOT_S2A_NATIVE_R03_RESULT.json"
]
],
"historical_runner_context_before_current_reaudit": {
"runner_state": "repair_ready",
"repairs": 19,
"submitted": "accd07c91d4e34d9b7c7fc20e389df2424b167e1",
"registered_validation": "0689f0070bd54d4f8b5849bb63bb36a8",
"worker_model": "gpt-6-astra",
"actual_commander": "execution/p04-01-current-recheck-20261015/OPUS_REPAIR18_FULL_INPUT_CONTINUATION_DECISION.json",
"run_decision": "execution/p04-01-current-recheck-20261015/OPUS_REPAIR18_FULL_INPUT_CONTINUATION_DECISION.json",
"current_scope": "Preserved executable R; next actual Opus direction for missing raw joins/getter type correction and real candidate A/fixtures. No new registered validation of unchanged accd."
}
},
"historical_initial_recheck": "execution/p04-01-current-recheck-20261015/recheck.json"
"historical_initial_recheck": "execution/p04-01-current-recheck-20261015/recheck.json",
"submitted_commit": "2dde7596a87c43f7bf0bf704b7479f2fa06a5b1c",
"normal_integration_candidate": null
},
{
"id": "P04-02",
@@ -8011,8 +8026,22 @@
"title": "背面条件と対象参照",
"work": "覗き部屋の対象背面、通路寸断、対象喪失と証拠IDを状態として実装する。",
"acceptance": "対象撤去、重複収集、停止、途中保存で状態と参照が整合する。",
"state": "planned",
"evidence": []
"state": "in_progress",
"evidence": [
{
"path": "docs/plans/original-completion-2026-10-02/execution/p13-02/CODE1_TASK_SPEC.json",
"sha256": "988d6e18a49372549863cd433432c2852c962fa64b138e490361c023e80249dc",
"scope": "Actual Opus-selected bounded implementation contract preparation; no tests or whole acceptance credit"
}
],
"progress_summary": "実Opus e65d48f5がP04回答に依存しない実装対象として選定。現mainにない背面配置/対象喪失/証拠ID重複防止/保存機構をRuntimeへ接続するCODE1契約を準備。担当sol指定。未承認建設値・記録係/自然収集契機・VIP未定義・D05/カメラUI等は捏造せず残す。通常建設/自然営業/全原条件は未受入、正式14/88で加算0。",
"current_summary": "実Opus e65d48f5がP04回答に依存しない実装対象として選定。現mainにない背面配置/対象喪失/証拠ID重複防止/保存機構をRuntimeへ接続するCODE1契約を準備。担当sol指定。未承認建設値・記録係/自然収集契機・VIP未定義・D05/カメラUI等は捏造せず残す。通常建設/自然営業/全原条件は未受入、正式14/88で加算0。",
"updated_at_jst": "2026-10-17T16:38:25.025337+09:00",
"current_execution": "docs/plans/original-completion-2026-10-02/execution/p13-02/CODE1_TASK_SPEC.json",
"remaining_gaps": [
"CODE1実装・必要な局所/影響検証・独立レビュー・通常統合finalは未実行。登録機構は元成果の全条件/通常Runtime/画面/保存受入を代替しない。",
"未承認建設/維持/収集数値・記録係条件、VIP施設、自然収集トリガ、D05取引規則、P19/P24接続と完成資産、原P13-02全条件の受入を残す。"
]
},
{
"id": "P13-03",
@@ -16235,7 +16264,7 @@
},
"legacy_state": "in_progress",
"state_scope": "package-level; completed means whole package accepted; partial implementation is not completion",
"current_summary": "提出bd3a134(修正使用済み4・上限なし)を同一Runnerで正式提出し保持branchへpush。GUI成果を保持してOpus判断でCodex6.1-solへ非UIのみ引継ぎ、countによる必須roster欠損容認とenv偽HEADを修正。実compile/保全/diff確認合格、局所9試験は実exit0+3入力SHA一致で再利用。別Opus限定静的review95cffd7 pass、重大/高/中0・low5、全8受入の加点0。実合成Q4bf9a1b/treea0667b9(M51e8657)を実4競合のS内容で準備、source1368/必須roster180はいずれも未実行。厳密Root合成契約・条件別artifact対応・実UI/OS/警告上流・最終全回帰/全8review/通常統合/Windowsが残る。 P24-03既完了とP24全体の完成は別。",
"current_summary": "提出fe44f55保持。実main565/Q429/T905で通常OSメニュー→別名保存→取消→再開→通常終了を採取。824停止サンプル89.116049秒、3節目モデル一致、実Opus b416限定review pass(重大/高/中0)。既存保存・非空待機列・focus復元機構・全8は未証明。原成果加算0。上流未実装に依存する警告等を残し、次に閉じる優先候補をP04-01へ切替。",
"remaining_deliverables": [
{
"id": "P24-01",
@@ -16388,10 +16417,15 @@
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-readiness-repair6-20261017/CURRENT_ACCEPTANCE_AND_NEXT_GATE.json",
"sha256": "ad38069fb28ca3218b31bc75673a308ee29b49ac1e30eefb4009d94e0d3b26c4",
"scope": "Current source6 limited review/actual S-Q post-submit reproduction/native import326parse/3 affected suites; all8 unaccepted, no unit credit"
},
{
"path": "docs/plans/original-completion-2026-10-02/execution/p24-02/normal-os-case-20261017/AUTHORITATIVE_NARROW_CASE_CLARIFICATIONS.json",
"sha256": "fd83e2edd4ac00bc9f8c568f6283ee47af43f91ef06336d36d775508a96682a5",
"scope": "One real normal-OS case / limited separate Opus review only; all8 unaccepted, no unit credit"
}
],
"updated_at_jst": "2026-10-17T15:19:09.416187+09:00",
"progress_summary": "提出fe44f55(同一Runner・修正6・上限なし)を保持branchへpush。Opus選定AstraがmovingHEAD基準と非OS証拠/段階循環の2中指摘を修正。実Sと実Qの各2局所試験を提出後に実行し全0、別Opus3cd2285限定レビューpass(重大/高/中0、low5)。実合成M54/Qefd/T1cでimport・326構文・影響3スイート171チェック合格、所有5PID終了、保全/cleanupエラー0。全8は未受入、正式加算0。実通常OS/型付き証拠のend-to-end・上流生産トリガ・最終全回帰/全8review/通常integration-finalが残る。",
"updated_at_jst": "2026-10-17T16:30:38.746525+09:00",
"progress_summary": "提出fe44f55保持。実main565/Q429/T905で通常OSメニュー→別名保存→取消→再開→通常終了を採取。824停止サンプル89.116049秒、3節目モデル一致、実Opus b416限定review pass(重大/高/中0)。既存保存・非空待機列・focus復元機構・全8は未証明。原成果加算0。上流未実装に依存する警告等を残し、次に閉じる優先候補をP04-01へ切替。",
"remaining_gaps": [
"placement_and_invalid_drop: Local native coverage passed. Ordinary OS valid/invalid placement and assignment/drop, actual explanation, valid-target behind-modal attempts and click equivalence with model/ledger/selection proof remain.",
"modal_and_pause_resume: Defense visibility callback and native operation/pause/cancel checks passed. Real valid-target positive control, all required normal modal/focus/pending/save identity and distinct-process continuity remain.",
@@ -16402,7 +16436,7 @@
"japanese_input_and_scale: Current ordinary OS IME composition/cancel/confirm/invalid input, Japanese persisted save, distinct-process load and required scale/focus/clipping remain. Same Windows release device requirements remain explicitly separate and unaccepted.",
"final_validation_review: Source/composition guard and twoMedium corrections passed limited review; actual newS/Q post-submit stdlib proof and native import/326parse/3 affected suites passed. Real typed OS/runtime/command/roster artifact assembly and schema end-to-end positive, exact final full180-or-current roster once, whole8 formal Opus review, normal candidate/integration/final remain. Rebind actual current M/Q before formal gates; oldQ is never relabelled."
],
"current_execution": "docs/plans/original-completion-2026-10-02/execution/p24-02/root-readiness-repair6-20261017/CURRENT_ACCEPTANCE_AND_NEXT_GATE.json",
"current_execution": "docs/plans/original-completion-2026-10-02/execution/p24-02/normal-os-case-20261017/CURRENT_AND_NEXT.md",
"submitted_commit": "fe44f550750acbf5c510346e7cacbea2ccbdd184",
"normal_integration_candidate": null
},
+7
View File
@@ -1048,6 +1048,13 @@ static func _snapshot_package_format(snapshot: Dictionary) -> int:
if not runtime_data is Dictionary: return FORMAT_VERSION # no owned Runtime authority
var version: Variant = runtime_data.get(&"runtime_schema_version", 1)
if typeof(version) != TYPE_INT: return -1
if runtime_data.has(&"special_peeping_rooms"):
var section_clock: Variant = snapshot.get(&"clock")
if not section_clock is Dictionary or typeof(section_clock.get(&"absolute_minute")) != TYPE_INT: return -1
if not preload("res://scripts/special/peeping_room_service.gd").valid_runtime_section(runtime_data, section_clock[&"absolute_minute"]): return -1
# Keep PurchaseQuotePlansV2's exact original allowlist and all format rules.
runtime_data = runtime_data.duplicate()
runtime_data.erase(&"special_peeping_rooms")
if version >= 1 and version <= 14:
return -1 if PurchaseQuoteV2.has_history(runtime_data) else FORMAT_VERSION
if version != 15: return -1
+271
View File
@@ -0,0 +1,271 @@
class_name PeepingRoomService
extends RefCounted
## Non-graphic state/reference machinery; production definitions remain pending.
const SECTION_VERSION := 1
const ALLOWED_TARGETS := [&"public_bath", &"adult_private_room"]
const OCCUPANCY_KIND := &"special_peeping_room"
const ID_PREFIX := &"peeping_room"
const ROOM_KEYS := [&"room_id", &"origin", &"footprint", &"cells", &"target_instance_id", &"target_definition_id", &"target_history", &"link_state", &"stopped", &"stop_reason"]
const EVIDENCE_KEYS := [&"evidence_id", &"room_id", &"target_instance_id", &"source_event_key", &"minute"]
var _rooms: Dictionary = {}
var _evidence: Dictionary = {}
var _world: WorldService
var _facilities: FacilityService
var _construction: ConstructionService
var _path: PathService
var _ids: StableIdGenerator
func configure(world: WorldService, facilities: FacilityService, construction: ConstructionService, path: PathService, ids: StableIdGenerator) -> void:
_world = world
_facilities = facilities
_construction = construction
_path = path
_ids = ids
static func result(reason: StringName = &"OK") -> Dictionary:
return {&"ok": reason == &"OK", &"reason": reason}
func is_empty() -> bool:
return _rooms.is_empty() and _evidence.is_empty()
func get_room(room_id: StringName) -> Dictionary:
return (_rooms.get(room_id, {}) as Dictionary).duplicate(true)
## Pure validation. own_room is supplied internally only for explicit relink/restore.
func validate_placement(origin: Vector3i, footprint: Vector2i = Vector2i(2, 1), target_id: StringName = &"", own_room: StringName = &"") -> Dictionary:
if origin.z != WorldService.LAYER_BACK: return result(&"WRONG_LAYER")
if footprint != Vector2i(2, 1): return result(&"WRONG_FOOTPRINT")
if target_id == &"vip_suite": return result(&"PENDING_P10_01")
var cells := _world.cells_for_footprint(origin, footprint)
var targets: Array[StringName] = []
var missing := false
for cell: Vector3i in cells:
if not _world.is_in_bounds(cell): return result(&"OUT_OF_BOUNDS")
if cell.y < 0 and not _world.is_excavated(cell): return result(&"NOT_EXCAVATED")
var front := Vector3i(cell.x, cell.y, WorldService.LAYER_FRONT)
if _world.get_occupant_kind(front) == &"construction": return result(&"TARGET_INCOMPLETE")
var occupant := _world.get_occupant(front)
if occupant.is_empty(): missing = true
elif occupant not in targets: targets.append(occupant)
if targets.size() > 1: return result(&"MULTIPLE_TARGETS")
if missing: return result(&"TARGET_MISSING" if targets.is_empty() else &"PARTIAL_TARGET")
var resolved_id := targets[0]
if not target_id.is_empty() and target_id != resolved_id: return result(&"TARGET_MISMATCH")
var target := _facilities.get_instance(resolved_id)
if target == null: return result(&"TARGET_UNKNOWN")
if target.definition_id not in ALLOWED_TARGETS: return result(&"TARGET_NOT_ALLOWED")
if target.origin.z != WorldService.LAYER_FRONT: return result(&"TARGET_WRONG_LAYER")
var built := _construction.get_facility(resolved_id)
if built.is_empty(): return result(&"TARGET_INCOMPLETE")
if built.get(&"definition_id") != target.definition_id: return result(&"TARGET_MISMATCH")
for cell: Vector3i in cells:
var front := Vector3i(cell.x, cell.y, WorldService.LAYER_FRONT)
if front not in target.occupied_cells or front not in built[&"occupied_cells"]: return result(&"PARTIAL_TARGET")
# Reject cutting an existing corridor; never construct an implicit bypass.
if _world.is_walkable(cell) or _path.has_cell(cell): return result(&"CORRIDOR_CONFLICT")
var occupancy := _world.validate_occupancy(cells)
if not occupancy[&"ok"]:
if own_room.is_empty() or _world.get_entity_cells(own_room) != cells or _world.get_entity_kind(own_room) != OCCUPANCY_KIND:
return result(&"BACK_OCCUPIED")
var report := result()
report.merge({&"cells": cells, &"target_instance_id": resolved_id, &"target_definition_id": target.definition_id})
return report
## CONTROLLED_FIXTURE: tests only. No Runtime executor or palette calls this.
func controlled_fixture_place(origin: Vector3i, target_id: StringName = &"") -> Dictionary:
var report := validate_placement(origin, Vector2i(2, 1), target_id)
if not report[&"ok"]: return report
var room_id := _ids.next_id(ID_PREFIX)
if room_id.is_empty(): return result(&"ID_EXHAUSTED")
if not _world.occupy(room_id, report[&"cells"], OCCUPANCY_KIND): return result(&"BACK_OCCUPIED")
_rooms[room_id] = {&"room_id": room_id, &"origin": origin, &"footprint": Vector2i(2, 1),
&"cells": report[&"cells"].duplicate(), &"target_instance_id": report[&"target_instance_id"],
&"target_definition_id": report[&"target_definition_id"],
&"target_history": [report[&"target_instance_id"]], &"link_state": &"LINKED",
&"stopped": true, &"stop_reason": &"CONTROLLED_FIXTURE"}
report[&"room_id"] = room_id
return report
func target_removed(target_id: StringName) -> void:
for room: Dictionary in _rooms.values():
if room[&"target_instance_id"] == target_id:
room[&"link_state"] = &"TARGET_LOST"
room[&"stopped"] = true
room[&"stop_reason"] = &"TARGET_LOST"
func detect_target_loss() -> void:
for room: Dictionary in _rooms.values():
if room[&"link_state"] == &"TARGET_LOST": continue
if not _target_still_present(room): target_removed(room[&"target_instance_id"])
func _target_still_present(room: Dictionary) -> bool:
var target := _facilities.get_instance(room[&"target_instance_id"])
if target == null or target.definition_id != room[&"target_definition_id"]: return false
for cell: Vector3i in room[&"cells"]:
if _world.get_occupant(Vector3i(cell.x, cell.y, WorldService.LAYER_FRONT)) != target.instance_id: return false
return true
func relink(room_id: StringName, target_id: StringName) -> Dictionary:
if not _rooms.has(room_id): return result(&"ROOM_MISSING")
if target_id.is_empty(): return result(&"TARGET_MISSING")
var room: Dictionary = _rooms[room_id]
var report := validate_placement(room[&"origin"], room[&"footprint"], target_id, room_id)
if not report[&"ok"]: return report
room[&"target_instance_id"] = target_id
room[&"target_definition_id"] = report[&"target_definition_id"]
if target_id not in room[&"target_history"]: room[&"target_history"].append(target_id)
room[&"link_state"] = &"LINKED"
room[&"stopped"] = true
room[&"stop_reason"] = &"RELINKED_PENDING_RESUME"
return result()
func _collection_precondition(room_id: StringName, source_event_key: StringName, minute: int) -> Dictionary:
if String(source_event_key).strip_edges().is_empty(): return result(&"SOURCE_EVENT_KEY_REQUIRED")
if minute < 0: return result(&"INVALID_MINUTE")
if not _rooms.has(room_id): return result(&"ROOM_MISSING")
detect_target_loss()
var room: Dictionary = _rooms[room_id]
# Required precedence: stopped, power, closed, construction, lost target.
if room[&"stopped"]: return result(&"STOPPED")
var target := _facilities.get_instance(room[&"target_instance_id"])
if target != null:
if not target.power_available: return result(&"NO_POWER")
if not target.operator_open or not target.is_within_opening_hours(minute): return result(&"CLOSED")
if _construction.get_facility(target.instance_id).is_empty(): return result(&"UNDER_CONSTRUCTION")
if room[&"link_state"] == &"TARGET_LOST" or target == null: return result(&"TARGET_LOST")
return result()
func record_evidence(room_id: StringName, source_event_key: StringName, minute: int) -> Dictionary:
var report := _collection_precondition(room_id, source_event_key, minute)
return report if not report[&"ok"] else result(&"RECORDER_ELIGIBILITY_PENDING_D04_D08_P16")
## CONTROLLED_FIXTURE: explicit test state, never a production resume command.
func controlled_fixture_set_stopped(room_id: StringName, stopped: bool) -> bool:
if not _rooms.has(room_id): return false
detect_target_loss()
var room: Dictionary = _rooms[room_id]
if not stopped and room[&"link_state"] == &"TARGET_LOST": return false
room[&"stopped"] = stopped
room[&"stop_reason"] = &"CONTROLLED_FIXTURE" if stopped else &""
return true
## CONTROLLED_FIXTURE: sole ledger write entry point, opaque event keys only.
func controlled_fixture_record_evidence(room_id: StringName, source_event_key: StringName, minute: int) -> Dictionary:
var report := _collection_precondition(room_id, source_event_key, minute)
if not report[&"ok"]: return report
var target_id: StringName = _rooms[room_id][&"target_instance_id"]
var evidence_id := _evidence_id(room_id, target_id, source_event_key)
var duplicated := _evidence.has(evidence_id)
if not duplicated:
_evidence[evidence_id] = {&"evidence_id": evidence_id, &"room_id": room_id,
&"target_instance_id": target_id, &"source_event_key": source_event_key, &"minute": minute}
return {&"ok": true, &"reason": &"OK", &"evidence_id": evidence_id, &"duplicated": duplicated}
static func _evidence_id(room_id: StringName, target_id: StringName, event_key: StringName) -> StringName:
# Length-prefixed UTF-8 hex is injective; delimiters in input cannot alias.
var pieces: Array[String] = []
for value: StringName in [room_id, target_id, event_key]:
var bytes := String(value).to_utf8_buffer()
pieces.append("%d:%s" % [bytes.size(), bytes.hex_encode()])
return StringName("peeping_evidence:" + ":".join(pieces))
func create_snapshot() -> Dictionary:
var rooms: Array[Dictionary] = []
var evidence: Array[Dictionary] = []
var keys := _rooms.keys()
keys.sort()
for key: StringName in keys: rooms.append(_rooms[key].duplicate(true))
keys = _evidence.keys()
keys.sort()
for key: StringName in keys: evidence.append(_evidence[key].duplicate(true))
return {&"version": SECTION_VERSION, &"rooms": rooms, &"evidence": evidence}
static func _exact(value: Variant, keys: Array) -> bool:
if not value is Dictionary or value.size() != keys.size(): return false
for key: Variant in value:
if typeof(key) != TYPE_STRING_NAME or key not in keys: return false
return true
## Save format 15 has a fixed purchase-key allowlist outside this task's scope.
## Validate this independent section before passing only the original keys to it.
static func valid_runtime_section(data: Dictionary, minute: int) -> bool:
if not data.get(&"special_peeping_rooms") is Dictionary: return false
for key: Variant in data:
if key == &"special_peeping_rooms" and typeof(key) != TYPE_STRING_NAME: return false
for key: StringName in [&"world", &"path", &"facilities", &"construction", &"id_generator"]:
if not data.get(key) is Dictionary: return false
var world := WorldService.new()
var path := PathService.new()
var facilities := FacilityService.new()
var ids := StableIdGenerator.new()
if not world.restore_snapshot(data[&"world"]) or not path.restore_snapshot(data[&"path"]) or not facilities.restore_snapshot(data[&"facilities"]) or not ids.restore_snapshot(data[&"id_generator"]): return false
var construction := ConstructionService.new(world)
if not construction.restore_snapshot(data[&"construction"]): return false
var service := PeepingRoomService.new()
service.configure(world, facilities, construction, path, ids)
return service.restore_section(data[&"special_peeping_rooms"], minute)
## Staged restore validates both directions of world ownership before committing.
func restore_section(section: Variant, minute: int) -> bool:
var rooms: Dictionary = {}
var evidence: Dictionary = {}
if section != null:
if not _exact(section, [&"version", &"rooms", &"evidence"]): return false
if typeof(section[&"version"]) != TYPE_INT or section[&"version"] != SECTION_VERSION: return false
if not section[&"rooms"] is Array or not section[&"evidence"] is Array: return false
if section[&"rooms"].is_empty(): return false # absence represents empty state
var known: Array = _facilities.create_snapshot()[&"known_instance_ids"]
for raw: Variant in section[&"rooms"]:
if not _exact(raw, ROOM_KEYS): return false
for key: StringName in [&"room_id", &"target_instance_id", &"target_definition_id", &"link_state", &"stop_reason"]:
if typeof(raw[key]) != TYPE_STRING_NAME: return false
var room_id: StringName = raw[&"room_id"]
var suffix := String(room_id).trim_prefix("peeping_room.")
if suffix.length() != 12 or not suffix.is_valid_int() or int(suffix) <= 0 or String(room_id) != "peeping_room.%012d" % int(suffix): return false
if int(suffix) > _ids.get_counter(ID_PREFIX) or rooms.has(room_id): return false
if typeof(raw[&"origin"]) != TYPE_VECTOR3I or typeof(raw[&"footprint"]) != TYPE_VECTOR2I: return false
if raw[&"origin"].z != WorldService.LAYER_BACK or raw[&"footprint"] != Vector2i(2, 1): return false
var cells := _world.cells_for_footprint(raw[&"origin"], raw[&"footprint"])
if not raw[&"cells"] is Array or raw[&"cells"] != cells: return false
for cell: Variant in raw[&"cells"]:
if typeof(cell) != TYPE_VECTOR3I: return false
if _world.get_entity_cells(room_id) != cells or _world.get_entity_kind(room_id) != OCCUPANCY_KIND: return false
for cell: Vector3i in cells:
if _world.is_walkable(cell) or _path.has_cell(cell): return false
if raw[&"target_definition_id"] not in ALLOWED_TARGETS: return false
if typeof(raw[&"stopped"]) != TYPE_BOOL or not raw[&"target_history"] is Array: return false
var history := {}
for target: Variant in raw[&"target_history"]:
if typeof(target) != TYPE_STRING_NAME or String(target) not in known or history.has(target): return false
history[target] = true
if not history.has(raw[&"target_instance_id"]): return false
var current_target := _facilities.get_instance(raw[&"target_instance_id"])
if current_target != null and current_target.definition_id != raw[&"target_definition_id"]: return false
if raw[&"link_state"] == &"TARGET_LOST":
if not raw[&"stopped"] or raw[&"stop_reason"] != &"TARGET_LOST" or _target_still_present(raw): return false
elif raw[&"link_state"] == &"LINKED":
if not validate_placement(raw[&"origin"], raw[&"footprint"], raw[&"target_instance_id"], room_id)[&"ok"]: return false
if _facilities.get_instance(raw[&"target_instance_id"]).definition_id != raw[&"target_definition_id"]: return false
if raw[&"stopped"]:
if raw[&"stop_reason"] not in [&"CONTROLLED_FIXTURE", &"RELINKED_PENDING_RESUME"]: return false
elif raw[&"stop_reason"] != &"": return false
else: return false
rooms[room_id] = raw.duplicate(true)
for raw: Variant in section[&"evidence"]:
if not _exact(raw, EVIDENCE_KEYS): return false
for key: StringName in [&"evidence_id", &"room_id", &"target_instance_id", &"source_event_key"]:
if typeof(raw[key]) != TYPE_STRING_NAME or raw[key].is_empty(): return false
if String(raw[&"source_event_key"]).strip_edges().is_empty(): return false
if typeof(raw[&"minute"]) != TYPE_INT or raw[&"minute"] < 0 or raw[&"minute"] > minute: return false
if not rooms.has(raw[&"room_id"]) or raw[&"target_instance_id"] not in rooms[raw[&"room_id"]][&"target_history"]: return false
var expected := _evidence_id(raw[&"room_id"], raw[&"target_instance_id"], raw[&"source_event_key"])
if expected != raw[&"evidence_id"] or evidence.has(expected): return false
evidence[expected] = raw.duplicate(true)
for occupied: Dictionary in _world.create_snapshot()[&"occupancies"]:
if occupied[&"kind"] == OCCUPANCY_KIND or String(occupied[&"entity_id"]).begins_with("peeping_room."):
if not rooms.has(occupied[&"entity_id"]): return false
_rooms = rooms
_evidence = evidence
return true
+59
View File
@@ -0,0 +1,59 @@
extends SceneTree
## CONTROLLED_FIXTURE. No production placement, recorder or eligibility claim.
const Rooms := preload("res://scripts/special/peeping_room_service.gd")
var checks := 0
var failures := 0
var fixtures: Array[Dictionary] = []
func _initialize() -> void:
call_deferred("_run")
func expect(ok: bool, label: String) -> void:
checks += 1
if not ok:
failures += 1
push_error(label)
func fixture(build_bath := true) -> Dictionary:
var clock: Variant = load("res://autoload/game_clock.gd").new()
var state: Variant = load("res://autoload/game_state.gd").new()
var runtime: Variant = load("res://autoload/simulation_runtime.gd").new()
clock.reset(1, 6, 0)
state.reset()
expect(runtime.initialize(clock, state, 1302)[&"valid"], "CONTROLLED_FIXTURE real Runtime initializes")
clock.set_paused(true)
runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
var f := {&"clock": clock, &"state": state, &"runtime": runtime, &"target": &"", &"origin": Vector3i(-6, 1, 1)}
fixtures.append(f)
if build_bath:
var built: CommandResult = runtime.submit_command(&"build_facility", {&"definition_id": &"public_bath", &"origin": Vector3i(-6, 0, 0)})
expect(built.is_success(), "real paid public bath construction")
clock.advance_minutes(runtime.definition_registry.get_facility(&"public_bath").build_minutes)
for target: FacilityInstance in runtime.facility_service.get_instances():
if target.definition_id == &"public_bath": f[&"target"] = target.instance_id
expect(not f[&"target"].is_empty(), "completed FRONT target has real stable identity")
return f
func place(f: Dictionary, origin: Variant = null) -> StringName:
var report: Dictionary = f[&"runtime"].peeping_room_service.controlled_fixture_place(f[&"origin"] if origin == null else origin)
expect(report[&"ok"], "CONTROLLED_FIXTURE only room placement: " + String(report[&"reason"]))
return report.get(&"room_id", &"")
func enable_fixture(f: Dictionary, room: StringName) -> void:
var runtime: Variant = f[&"runtime"]
expect(runtime.peeping_room_service.controlled_fixture_set_stopped(room, false), "CONTROLLED_FIXTURE explicitly enables ledger exercise")
expect(runtime.facility_service.set_operational_status(f[&"target"], {&"power_available": true, &"operator_open": true}, f[&"clock"].absolute_minute).is_success(), "CONTROLLED_FIXTURE target conditions")
func rejects_atomically(runtime: Variant, snapshot: Dictionary) -> bool:
var before := var_to_bytes(runtime.create_snapshot())
return not runtime.restore_snapshot(snapshot) and before == var_to_bytes(runtime.create_snapshot())
func finish(label: String) -> void:
for f: Dictionary in fixtures:
f[&"runtime"].free()
f[&"clock"].free()
f[&"state"].free()
fixtures.clear()
print("%s: %d checks, %d failures" % [label, checks, failures])
quit(1 if failures else 0)
@@ -0,0 +1,40 @@
extends "res://tests/special/peeping_room_fixture.gd"
func _run() -> void:
var f := fixture()
var runtime: Variant = f[&"runtime"]
var room := place(f)
var other := place(f, Vector3i(-4, 1, 1))
var service: Variant = runtime.peeping_room_service
var minute: int = f[&"clock"].absolute_minute
expect(service.record_evidence(room, &"", minute)[&"reason"] == &"SOURCE_EVENT_KEY_REQUIRED", "named source key required first")
expect(service.controlled_fixture_record_evidence(room, &"fixture.event", minute)[&"reason"] == &"STOPPED", "initial stopped state rejects even fixture ledger")
enable_fixture(f, room)
enable_fixture(f, other)
var target: FacilityInstance = runtime.facility_service.get_instance(f[&"target"])
target.power_available = false
target.operator_open = false
expect(service.record_evidence(room, &"fixture.event", minute)[&"reason"] == &"NO_POWER", "power rejection precedes closed")
target.power_available = true
expect(service.record_evidence(room, &"fixture.event", minute)[&"reason"] == &"CLOSED", "closed target rejects")
target.operator_open = true
# CONTROLLED_FIXTURE temporarily omit construction authority, leaving live target.
var empty_construction := ConstructionService.new(runtime.world_service)
service.configure(runtime.world_service, runtime.facility_service, empty_construction, runtime.path_service, runtime.id_generator)
expect(service.record_evidence(room, &"fixture.event", minute)[&"reason"] == &"UNDER_CONSTRUCTION", "uncompleted construction authority rejects collection")
service.configure(runtime.world_service, runtime.facility_service, runtime.construction_service, runtime.path_service, runtime.id_generator)
var before := var_to_bytes(service.create_snapshot())
expect(service.record_evidence(room, &"fixture.event", minute)[&"reason"] == &"RECORDER_ELIGIBILITY_PENDING_D04_D08_P16", "production collection never invents eligibility")
expect(before == var_to_bytes(service.create_snapshot()), "production collection leaves ledger unchanged")
var first: Dictionary = service.controlled_fixture_record_evidence(room, &"fixture.event", minute)
var replay: Dictionary = service.controlled_fixture_record_evidence(room, &"fixture.event", minute + 1)
expect(first[&"ok"] and not first[&"duplicated"] and replay[&"duplicated"] and replay[&"evidence_id"] == first[&"evidence_id"], "tuple replay returns exactly one stable ID")
var second: Dictionary = service.controlled_fixture_record_evidence(other, &"fixture.event", minute)
var third: Dictionary = service.controlled_fixture_record_evidence(room, &"fixture:event:日本語", minute)
expect(second[&"evidence_id"] != first[&"evidence_id"] and third[&"evidence_id"] != first[&"evidence_id"], "different room/key distinct, delimiter and UTF-8 input supported")
expect(service.create_snapshot()[&"evidence"].size() == 3, "replay adds no ledger record")
var snapshot: Dictionary = runtime.create_snapshot()
expect(runtime.restore_snapshot(snapshot), "active fixture evidence restores")
var restored: Dictionary = runtime.peeping_room_service.controlled_fixture_record_evidence(room, &"fixture.event", minute)
expect(restored[&"duplicated"] and restored[&"evidence_id"] == first[&"evidence_id"], "evidence stable across restore")
finish("Peeping room evidence")
@@ -0,0 +1,62 @@
extends "res://tests/special/peeping_room_fixture.gd"
func _run() -> void:
var f := fixture()
var runtime: Variant = f[&"runtime"]
var service: Variant = runtime.peeping_room_service
var origin: Vector3i = f[&"origin"]
var before := var_to_bytes(runtime.create_snapshot())
expect(service.validate_placement(origin)[&"ok"], "public bath entirely behind one completed FRONT target")
expect(service.validate_placement(Vector3i(-6, 1, 0))[&"reason"] == &"WRONG_LAYER", "FRONT room rejected")
expect(service.validate_placement(origin, Vector2i(1, 2))[&"reason"] == &"WRONG_FOOTPRINT", "rotated footprint rejected")
expect(service.validate_placement(origin, Vector2i(2, 1), &"vip_suite")[&"reason"] == &"PENDING_P10_01", "VIP unavailable, never substituted")
expect(service.validate_placement(Vector3i(-1, 1, 1))[&"reason"] == &"PARTIAL_TARGET", "partial target rejected")
expect(service.validate_placement(Vector3i(8, 1, 1))[&"reason"] == &"TARGET_MISSING", "missing target rejected")
expect(service.validate_placement(origin, Vector2i(2, 1), &"missing")[&"reason"] == &"TARGET_MISMATCH", "named reference must match FRONT occupant")
expect(before == var_to_bytes(runtime.create_snapshot()), "geometry validation is pure across whole Runtime")
# Complete real second bath; the 2x1 footprint at the boundary spans targets.
expect(runtime.submit_command(&"build_facility", {&"definition_id": &"public_bath", &"origin": Vector3i(0, 0, 0)}).is_success(), "second paid target starts")
expect(service.validate_placement(Vector3i(0, 1, 1))[&"reason"] == &"TARGET_INCOMPLETE", "construction reservation is not a completed target")
f[&"clock"].advance_minutes(runtime.definition_registry.get_facility(&"public_bath").build_minutes)
expect(service.validate_placement(Vector3i(-1, 1, 1))[&"reason"] == &"MULTIPLE_TARGETS", "multiple FRONT target footprints rejected")
# A real path joining both sides through the proposed footprint must survive.
for x in range(-7, -3): runtime.world_service.set_walkable(Vector3i(x, 1, 1), true)
expect(runtime.rebuild_path_graph_from_world(), "CONTROLLED_FIXTURE corridor graph rebuild")
var path_before: Array = runtime.path_service.find_path(Vector3i(-7, 1, 1), Vector3i(-4, 1, 1))
expect(not path_before.is_empty(), "proposed footprint lies across a connected corridor")
expect(service.validate_placement(origin)[&"reason"] == &"CORRIDOR_CONFLICT", "would disconnect BACK corridor: reject with no bypass")
expect(runtime.path_service.find_path(Vector3i(-7, 1, 1), Vector3i(-4, 1, 1)) == path_before, "rejected cut preserves route")
for x in range(-7, -3): runtime.world_service.set_walkable(Vector3i(x, 1, 1), false)
expect(service.validate_placement(origin)[&"reason"] == &"CORRIDOR_CONFLICT", "stale path authority also rejects conflict")
expect(runtime.rebuild_path_graph_from_world(), "corridor fixture removed explicitly")
var room := place(f)
expect(service.validate_placement(origin)[&"reason"] == &"BACK_OCCUPIED", "dedicated room occupancy blocks overlap")
expect(runtime.world_service.get_entity_kind(room) == Rooms.OCCUPANCY_KIND, "dedicated cross-reference occupancy kind")
_private_geometry()
finish("Peeping room geometry")
func _private_geometry() -> void:
var f := fixture(false)
var runtime: Variant = f[&"runtime"]
# CONTROLLED_FIXTURE underground geometry only: no unlock/normal palette claim.
var bounds: Dictionary = runtime.world_service.get_bounds()
bounds[&"min_y"] = -1
expect(runtime.world_service.expand_bounds(bounds), "CONTROLLED_FIXTURE underground bounds")
var definition: FacilityDefinition = runtime.definition_registry.get_facility(&"adult_private_room")
for x in range(2):
var cell := Vector3i(x, -1, 0)
runtime.world_service.set_excavated(cell, true)
runtime.world_service.set_support(cell, definition.weight_per_cell, true)
var started: CommandResult = runtime.construction_service.start_construction(definition, Vector3i(0, -1, 0))
expect(started.is_success(), "CONTROLLED_FIXTURE paid real adult_private_room definition")
f[&"clock"].advance_minutes(definition.build_minutes)
var service: Variant = runtime.peeping_room_service
expect(service.validate_placement(Vector3i(0, -1, 1))[&"ok"], "adult_private_room valid completed geometry")
var target_id: StringName = runtime.world_service.get_occupant(Vector3i(0, -1, 0))
var target: FacilityInstance = runtime.facility_service.get_instance(target_id)
if target != null:
target.definition_id = &"vip_private_salon"
expect(service.validate_placement(Vector3i(0, -1, 1))[&"reason"] == &"TARGET_NOT_ALLOWED", "salon is not VIP suite substitute")
target.definition_id = &"adult_private_room"
runtime.facility_service.unregister_instance(target_id)
expect(service.validate_placement(Vector3i(0, -1, 1))[&"reason"] == &"TARGET_UNKNOWN", "world occupant without actual FacilityService target rejected")
@@ -0,0 +1,37 @@
extends "res://tests/special/peeping_room_fixture.gd"
func _run() -> void:
var f := fixture()
var runtime: Variant = f[&"runtime"]
var room := place(f)
enable_fixture(f, room)
var old_target: StringName = f[&"target"]
var old_evidence: Dictionary = runtime.peeping_room_service.controlled_fixture_record_evidence(room, &"fixture.event", f[&"clock"].absolute_minute)
expect(old_evidence[&"ok"], "fixture evidence before removal")
expect(runtime.submit_command(&"demolish_facility", {&"instance_id": old_target}).is_success(), "real Runtime demolition")
var lost: Dictionary = runtime.peeping_room_service.get_room(room)
expect(lost[&"link_state"] == &"TARGET_LOST" and lost[&"stopped"], "target removal immediately marks lost and stopped")
expect(runtime.peeping_room_service.record_evidence(room, &"fixture.after_loss", f[&"clock"].absolute_minute)[&"reason"] == &"STOPPED", "collection rejected after loss with prescribed stopped precedence")
expect(not runtime.peeping_room_service.controlled_fixture_set_stopped(room, false), "lost target cannot resume even through fixture")
var lost_snapshot: Dictionary = runtime.create_snapshot()
expect(runtime.restore_snapshot(lost_snapshot), "lost reference roundtrip retains historical identity")
expect(var_to_bytes(lost_snapshot) == var_to_bytes(runtime.create_snapshot()), "lost snapshot exact typed roundtrip")
expect(runtime.submit_command(&"build_facility", {&"definition_id": &"public_bath", &"origin": Vector3i(-6, 0, 0)}).is_success(), "rebuild at same geometry starts")
f[&"clock"].advance_minutes(runtime.definition_registry.get_facility(&"public_bath").build_minutes)
var new_target: StringName = runtime.world_service.get_occupant(Vector3i(-6, 0, 0))
expect(new_target != old_target, "rebuild receives different target identity")
expect(runtime.peeping_room_service.get_room(room)[&"target_instance_id"] == old_target, "no implicit relink on geometry reuse")
var rejected: CommandResult = runtime.submit_command(&"peeping_room_relink", {&"room_id": room, &"target_instance_id": old_target})
expect(not rejected.is_success(), "explicit old target relink rejected")
expect(runtime.submit_command(&"peeping_room_relink", {&"room_id": room, &"target_instance_id": new_target}).is_success(), "explicit new target full validation")
var linked: Dictionary = runtime.peeping_room_service.get_room(room)
expect(linked[&"stopped"] and linked[&"stop_reason"] == &"RELINKED_PENDING_RESUME", "explicit relink never auto resumes")
f[&"target"] = new_target
enable_fixture(f, room)
var new_evidence: Dictionary = runtime.peeping_room_service.controlled_fixture_record_evidence(room, &"fixture.event", f[&"clock"].absolute_minute)
expect(new_evidence[&"ok"] and new_evidence[&"evidence_id"] != old_evidence.get(&"evidence_id"), "same room/event on different target never aliases")
var linked_snapshot: Dictionary = runtime.create_snapshot()
expect(runtime.restore_snapshot(linked_snapshot) and var_to_bytes(linked_snapshot) == var_to_bytes(runtime.create_snapshot()), "relinked ledger keeps both historical target bindings")
expect(runtime.facility_service.unregister_instance(new_target).is_success(), "equivalent FacilityService removal path")
expect(runtime.peeping_room_service.get_room(room)[&"link_state"] == &"TARGET_LOST", "unregister signal also invalidates target")
finish("Peeping room reference")
@@ -0,0 +1,58 @@
extends "res://tests/special/peeping_room_fixture.gd"
func _run() -> void:
var f := fixture()
var runtime: Variant = f[&"runtime"]
# Direct executor invocation distinguishes read-only domain state from queue receipts.
var validation := SimulationCommand.new()
validation.command_type = &"peeping_room_validate"
validation.payload = {&"origin": f[&"origin"]}
var before := var_to_bytes(runtime.create_snapshot())
expect(runtime._execute_peeping_room(validation).is_success(), "read-only validator executor")
expect(before == var_to_bytes(runtime.create_snapshot()), "validator changes no whole Runtime bytes")
var public_validation: CommandResult = runtime.submit_command(&"peeping_room_validate", validation.payload)
expect(public_validation.is_success(), "registered validation command runs through real queue")
var domain_before := [runtime.world_service.create_snapshot(), runtime.economy_service.create_snapshot(), runtime.id_generator.create_snapshot(), runtime.peeping_room_service.create_snapshot()]
var unavailable: CommandResult = runtime.submit_command(&"peeping_room_place", validation.payload)
expect(not unavailable.is_success() and unavailable.details[&"reason"] == &"BUILD_DEFINITION_PENDING_D04", "production placement unavailable with precise reason")
expect(var_to_bytes(domain_before) == var_to_bytes([runtime.world_service.create_snapshot(), runtime.economy_service.create_snapshot(), runtime.id_generator.create_snapshot(), runtime.peeping_room_service.create_snapshot()]), "placement adds no room, occupancy, cost or ID (normal queue receipt only)")
var room := place(f)
enable_fixture(f, room)
var blocked: CommandResult = runtime.submit_command(&"peeping_room_record_evidence", {&"room_id": room, &"source_event_key": &"fixture.command"})
expect(not blocked.is_success() and blocked.details[&"reason"] == &"RECORDER_ELIGIBILITY_PENDING_D04_D08_P16", "registered evidence command cannot reach ledger")
var missing: CommandResult = runtime.submit_command(&"peeping_room_record_evidence", {&"room_id": room})
expect(not missing.is_success() and missing.details[&"reason"] == &"SOURCE_EVENT_KEY_REQUIRED", "public command requires named key")
var malformed: CommandResult = runtime.submit_command(&"peeping_room_validate", {&"origin": [0, 1, 1]})
expect(not malformed.is_success() and malformed.details[&"reason"] == &"INVALID_PAYLOAD", "wrong payload type safely rejected")
expect(runtime.peeping_room_service.create_snapshot()[&"evidence"].is_empty(), "commands cannot inject arbitrary content events")
var fixture_command: CommandResult = runtime.submit_command(&"controlled_fixture_place", validation.payload)
expect(not fixture_command.is_success(), "no fixture command registration")
_mimi_format(f)
finish("Peeping room runtime")
func _mimi_format(f: Dictionary) -> void:
var runtime: Variant = f[&"runtime"]
const Quote := preload("res://scripts/supply/supply_purchase_quote_v2.gd")
expect(runtime.submit_command(&"build_facility", {&"definition_id": &"warehouse", &"origin": Vector3i(2, 0, 1)}).is_success(), "paid warehouse for independent existing MIMI format path")
f[&"clock"].advance_minutes(runtime.definition_registry.get_facility(&"warehouse").build_minutes)
var warehouse: StringName = &""
for facility: FacilityInstance in runtime.facility_service.get_instances():
if facility.definition_id == &"warehouse": warehouse = facility.instance_id
expect(not warehouse.is_empty(), "completed real warehouse")
var mimi := StaffRuntime.new().configure(Quote.MIMI, &"porter", {&"employment_kind": StaffRuntime.EmploymentKind.UNIQUE})
expect(runtime.staff_service.register_staff(mimi).is_success(), "CONTROLLED_FIXTURE existing MIMI unique registration, no natural join claim")
expect(runtime.submit_command(&"set_staff_work_assignment", {&"staff_id": Quote.MIMI, &"facility_id": warehouse, &"template_id": &"NIGHT"}).is_success(), "existing persistent MIMI assignment")
expect(runtime.submit_command(&"purchase_supplies", {&"warehouse_id": warehouse, &"item_id": SupplyCatalog.RAW_FOOD, &"quantity": 1}).is_success(), "existing real v2 paid purchase")
var snapshot: Dictionary = runtime.create_snapshot()
expect(snapshot[&"systems"][&"runtime"][&"runtime_schema_version"] == 15 and snapshot[&"systems"][&"runtime"].has(&"special_peeping_rooms"), "v2 purchase history and special section coexist")
expect(runtime.restore_snapshot(snapshot) and var_to_bytes(snapshot) == var_to_bytes(runtime.create_snapshot()), "v15 optional section exact typed restore")
var directory := "user://tests/p13_reference_mimi_%d" % OS.get_process_id()
expect(SaveService.save_snapshot(directory, snapshot)[&"ok"], "physical v15 save accepts validated extension without loosening purchase allowlist")
var loaded := SaveService.load_snapshot(directory)
expect(loaded[&"ok"], "physical MIMI section save loads")
if loaded[&"ok"]:
expect(loaded[&"manifest"]["format_version"] == 2 and loaded[&"manifest"]["runtime_schema_version"] == 15, "format2 manifest still exactly15")
expect(runtime.restore_snapshot(loaded[&"snapshot"]), "MIMI package restore reaches same staged section validator")
var bad := snapshot.duplicate(true)
bad[&"systems"][&"runtime"][&"special_peeping_rooms"][&"version"] = 2
expect(not SaveService.save_snapshot(directory + "_bad", bad)[&"ok"], "save-format adapter rejects malformed optional section")
+66
View File
@@ -0,0 +1,66 @@
extends "res://tests/special/peeping_room_fixture.gd"
func _run() -> void:
var f := fixture()
var runtime: Variant = f[&"runtime"]
var empty: Dictionary = runtime.create_snapshot()
expect(not empty[&"systems"][&"runtime"].has(&"special_peeping_rooms"), "empty service does not alter existing snapshot keys")
expect(runtime.restore_snapshot(empty) and var_to_bytes(empty) == var_to_bytes(runtime.create_snapshot()), "pre-extension v14 absence exact roundtrip")
var legacy := empty.duplicate(true)
legacy[&"systems"][&"runtime"][&"runtime_schema_version"] = 13
legacy[&"systems"][&"runtime"].erase(&"auto_purchase_plans")
expect(runtime.restore_snapshot(legacy) and runtime.peeping_room_service.is_empty(), "genuine v13 absent section migrates empty")
expect(runtime.restore_snapshot(empty), "restore canonical baseline before controlled room")
var room := place(f)
enable_fixture(f, room)
expect(runtime.peeping_room_service.controlled_fixture_record_evidence(room, &"fixture.save", f[&"clock"].absolute_minute)[&"ok"], "controlled evidence before mid-state save")
expect(runtime.submit_command(&"peeping_room_relink", {&"room_id": room, &"target_instance_id": f[&"target"]}, &"player", room, 0, f[&"clock"].absolute_minute + 1).is_success(), "future explicit relink remains pending at checkpoint")
var snapshot: Dictionary = runtime.create_snapshot()
expect(snapshot[&"systems"][&"runtime"][&"runtime_schema_version"] == 14, "extension never bumps Runtime version")
expect(runtime.restore_snapshot(snapshot) and var_to_bytes(snapshot) == var_to_bytes(runtime.create_snapshot()), "exact typed room/evidence whole Runtime roundtrip")
var directory := "user://tests/p13_reference_save_%d" % OS.get_process_id()
var saved := SaveService.save_snapshot(directory, snapshot)
expect(saved[&"ok"], "actual SaveService writes section in format 1")
var loaded := SaveService.load_snapshot(directory)
expect(loaded[&"ok"], "actual SaveService reads section")
if loaded[&"ok"]:
expect(loaded[&"manifest"]["format_version"] == 1, "existing format mapping unchanged")
expect(runtime.restore_snapshot(loaded[&"snapshot"]), "loaded physical package reaches Runtime validation")
expect(var_to_bytes(snapshot) == var_to_bytes(runtime.create_snapshot()), "physical save retains all typed fields")
for mutation in range(18):
var bad := snapshot.duplicate(true)
var data: Dictionary = bad[&"systems"][&"runtime"]
var section: Dictionary = data[&"special_peeping_rooms"]
match mutation:
0: data.erase(&"special_peeping_rooms")
1: data[&"special_peeping_rooms"] = null
2: section[&"version"] = 2
3: section[&"version"] = 1.0
4: section[&"unknown"] = true
5: section.erase(&"evidence")
6: section[&"rooms"].append(section[&"rooms"][0].duplicate(true))
7: section[&"evidence"].append(section[&"evidence"][0].duplicate(true))
8: section[&"rooms"][0][&"target_instance_id"] = &"missing.target"
9: section[&"rooms"][0][&"target_definition_id"] = &"adult_private_room"
10: section[&"rooms"][0][&"origin"] = Vector3i(8, 1, 1)
11: section[&"rooms"][0][&"stopped"] = 1
12: section[&"evidence"][0][&"room_id"] = &"peeping_room.999999999999"
13: section[&"evidence"][0][&"source_event_key"] = &"aliased.event"
14: section[&"evidence"][0][&"minute"] = f[&"clock"].absolute_minute + 1
15: data[&"id_generator"]["counters"]["peeping_room"] = 0
16:
section.erase(&"version")
section["version"] = 1
17:
section[&"rooms"][0][&"link_state"] = &"TARGET_LOST"
section[&"rooms"][0][&"stopped"] = true
section[&"rooms"][0][&"stop_reason"] = &"TARGET_LOST"
expect(rejects_atomically(runtime, bad), "malformed/current missing/reference/duplicate rejection atomic case %d" % mutation)
var orphan := empty.duplicate(true)
orphan[&"systems"][&"runtime"][&"world"] = snapshot[&"systems"][&"runtime"][&"world"].duplicate(true)
expect(rejects_atomically(runtime, orphan), "world-owned room without any section rejects atomically")
var removed_world := snapshot.duplicate(true)
removed_world[&"systems"][&"runtime"][&"world"] = empty[&"systems"][&"runtime"][&"world"].duplicate(true)
expect(rejects_atomically(runtime, removed_world), "section-owned room without world occupancy rejects atomically")
expect(runtime.restore_snapshot(empty) and runtime.peeping_room_service.is_empty(), "absent legacy section clears previous nonempty service on valid load")
finish("Peeping room save")
+164
View File
@@ -0,0 +1,164 @@
#!/usr/bin/env python3
"""P13 reference evidence: read-only verification by default; collection is Root-only."""
import argparse
import ast
import inspect
import json
import os
from pathlib import Path
import shutil
import sys
sys.dont_write_bytecode = True
import run_all_tests as shared
PROTOCOL = 'guarded-p13-reference-v1'
NEW_TESTS = [
'tests/special/test_peeping_room_geometry.gd',
'tests/special/test_peeping_room_reference.gd',
'tests/special/test_peeping_room_evidence.gd',
'tests/special/test_peeping_room_save.gd',
'tests/special/test_peeping_room_runtime.gd',
]
ROSTER = NEW_TESTS + [
'tests/s1/test_construction_service.gd',
'tests/s1/test_world_service.gd',
'tests/s1/test_path_service.gd',
'tests/s1/test_runtime_world_construction.gd',
'tests/supply/test_supply_save_migration.gd',
'tests/transport/test_transport_save.gd',
'tests/environment/test_runtime_weather.gd',
'tests/s6/test_runtime_snapshot_serialization.gd',
'tests/s6/test_runtime_save_lifecycle.gd',
'tests/supply/test_mimi_purchase_quote.gd',
]
def protocol_core():
"""Reuse P18's complete guarded core without editing or copying its runner.
P18 predates configurable protocol/roster constants. Specialize ONLY its
three entry functions' identity literals and explicit roster cardinalities.
All proof gates and pure helpers are the imported original functions.
Fail closed if an upstream function changes any of these adapter sites.
Both runner sources remain bound by the whole selected source map.
"""
core = shared.module('p13_p18_core', shared.HERE / 'run_p18_relationship_tests.py')
namespace = dict(vars(core), ROSTER=ROSTER, __file__=__file__)
replacements = {
'guarded-p18-v2': PROTOCOL,
'tools/run_p18_relationship_tests.py': 'tools/run_p13_reference_tests.py',
'exact seven unique tests': 'exact unique P13 roster',
'exact nine phases': 'exact P13 phase count',
'all nine captured engines': 'all P13 captured engines',
}
cardinalities = {
'len(set(ROSTER)) == 7': 'len(set(ROSTER)) == len(ROSTER)',
'len(phases) == 9': 'len(phases) == len(ROSTER) + 2',
"len(tests) == 7": 'len(tests) == len(ROSTER)',
}
class Specialize(ast.NodeTransformer):
def __init__(self):
self.identities = 0
self.counts = 0
self.summary = 0
def visit_Constant(self, node):
if isinstance(node.value, str) and node.value in replacements:
self.identities += 1
return ast.copy_location(ast.Constant(replacements[node.value]), node)
return node
def visit_Compare(self, node):
expression = ast.unparse(node)
if expression in cardinalities:
self.counts += 1
return ast.copy_location(ast.parse(cardinalities[expression], mode='eval').body, node)
return self.generic_visit(node)
def visit_Dict(self, node):
for index, key in enumerate(node.keys):
if isinstance(key, ast.Constant) and key.value == 'actual_suites':
shared.require(isinstance(node.values[index], ast.Constant)
and node.values[index].value == 7, 'upstream suite summary unchanged')
node.values[index] = ast.parse('len(ROSTER)', mode='eval').body
self.summary += 1
return self.generic_visit(node)
expected = {'collect': (2, 0, 0), 'seal': (1, 0, 0), 'verify': (6, 3, 1)}
for name, counts in expected.items():
adapter = Specialize()
tree = adapter.visit(ast.parse(inspect.getsource(getattr(core, name))))
shared.require((adapter.identities, adapter.counts, adapter.summary) == counts,
'unchanged upstream adaptation sites: ' + name)
exec(compile(ast.fix_missing_locations(tree), str(shared.HERE / 'run_p18_relationship_tests.py'), 'exec'), namespace)
return namespace
def main(argv=None):
argv = list(sys.argv[1:] if argv is None else argv)
parser = argparse.ArgumentParser(description=__doc__, allow_abbrev=False)
parser.add_argument('--output')
modes = parser.add_mutually_exclusive_group()
modes.add_argument('--collect', action='store_true', help='Root only; fresh native collection')
modes.add_argument('--prepare-only', action='store_true')
seen, index = set(), 0
while index < len(argv):
flag = argv[index]
shared.require(flag in ('--output', '--collect', '--prepare-only', '--help')
and flag not in seen, 'unknown, duplicate or malformed flag')
seen.add(flag)
if flag == '--output':
index += 1
shared.require(index < len(argv) and argv[index] and not argv[index].startswith('--'), 'output value required')
index += 1
args = parser.parse_args(argv)
shared.require(not args.collect or args.output is not None, 'Root collection requires explicit --output')
if args.output is None:
base = os.environ.get('BUILD_OUTPUT_DIR')
shared.require(bool(base) and Path(base).is_absolute(), 'absolute BUILD_OUTPUT_DIR required')
args.output = str(Path(base) / 'p13-reference-native')
args.timeout = 1200 # unchanged guarded core timeout; not a product value
core = protocol_core()
root = shared.HERE.parent
out = core['plain_path'](args.output)
refs = shared.source_refs(root)
shared.require(len(set(ROSTER)) == len(ROSTER) and set(ROSTER).issubset(shared.roster(root)), 'complete unique discovered roster')
markers = shared.module('p13_exact_markers', shared.HERE / 'strict_test_markers.py')
contract_path = root / 'docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json'
contract_sha = shared.sha(contract_path)
contracts = markers.load_contracts(contract_path)
shared.require(all(name in contracts for name in ROSTER), 'complete marker roster')
policy = shared.read(shared.SUPPORT / 'suite-policy.json')
shared.policy_coverage(ROSTER, refs, policy)
for test in ROSTER:
shared.phase_policy(test, Path(refs[test]['path']), policy['suite_policies'])
for test in NEW_TESTS:
shared.require(contracts[test]['source_sha256_at_schema_audit'] == refs[test]['sha256'], 'new strict source-hashed marker')
parse_paths = ['res://' + name for name in sorted(refs) if name.endswith('.gd')]
if args.prepare_only:
ancestor = out.parent
while not ancestor.exists():
ancestor = ancestor.parent
free = shutil.disk_usage(ancestor).free
size = sum(pin['bytes'] for pin in refs.values())
print(json.dumps(dict(protocol=PROTOCOL, roster=ROSTER, source_files=len(refs),
source_bytes=size, free_bytes=free, conservative_required_bytes=size + shared.MIN_SPACE,
capacity_available=free >= size + shared.MIN_SPACE, parse_paths=len(parse_paths),
future_native_phases=len(ROSTER) + 2, actual_checks=None, engines=0, stages=0,
formal_acceptance=False, original_unit_complete=False)))
return 0
if args.collect:
shared.require(not out.exists() and out.parent.is_dir(), 'fresh output with existing parent required')
shared.require(not out.is_relative_to(root), 'private collection outside source tree')
return core['collect'](args, root, out, refs, markers, contracts, policy, contract_path, contract_sha, parse_paths)
return core['verify'](out, refs, markers, contracts, policy, contract_sha, parse_paths)
if __name__ == '__main__':
try:
raise SystemExit(main())
except (AssertionError, OSError, ValueError, KeyError, TypeError) as error:
print(type(error).__name__ + ': ' + str(error), file=sys.stderr)
raise SystemExit(1)