P13-02-CODE1: P13-02 背面対象参照・占有・保存の非描写機構(全原成果の一部、加算なし)

This commit is contained in:
Agent Control Runner
2026-10-17 17:03:48 +09:00
parent 1e8d4ea888
commit e930a1dedf
12 changed files with 1015 additions and 0 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,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.
+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)