P14-03: Versioned shaft-wait saves, keep riders aboard, real-actor proof
- ElevatorService snapshot v2 carries the shaft-wide wait; v1 saves (written
with every elevator dynamic_cost 0) migrate by deriving it on load, and any
v2 mismatch, including all zeros, is rejected atomically. A genuine save
from 50ceca0 is kept as tests/fixtures/p14-03/legacy_rush_v1.
- A guest aboard a cabin no longer decides, leaves or despawns until the
elevator sets it down at a real landing; previously a rider told to leave
vanished from a moving cabin.
- test_route_wait_choice now proves the rush detour and route loss with a
worker who actually walks, every shared rider's arrival cell, service
elevator and stair congestion, legacy migration and a new-PID restart.
- Register completion markers for the seven suites added this session and
bring the P14 ledger in line with P14-02's completion.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
62d1dcecad
commit
a8edd3c3a1
@@ -4,7 +4,10 @@ extends RefCounted
|
||||
## One physical cabin per contiguous shaft. Path connectors expose reachability;
|
||||
## boarding and arrival here remain authoritative for actual movement.
|
||||
## Dispatch is oldest request first, batching one origin/destination at a time.
|
||||
const SNAPSHOT_VERSION := 1
|
||||
## 2: connectors publish the shaft-wide wait as dynamic_cost (P14-03).
|
||||
## 1: legacy saves, where every elevator connector's dynamic_cost was 0.
|
||||
const SNAPSHOT_VERSION := 2
|
||||
const LEGACY_SNAPSHOT_VERSION := 1
|
||||
const PREFIX := "transport."
|
||||
const REQUEST_PREFIX := "transport.trip."
|
||||
const DOOR_MINUTES := 2
|
||||
@@ -371,7 +374,8 @@ func create_snapshot() -> Dictionary:
|
||||
func restore_snapshot(snapshot: Dictionary) -> bool:
|
||||
if _path == null or not _exact_keys(snapshot, [&"version", &"current_minute", &"request_sequence", &"shafts", &"trips"]):
|
||||
return _invalid("Elevator snapshot shape is invalid.")
|
||||
if snapshot[&"version"] != SNAPSHOT_VERSION or not snapshot[&"current_minute"] is int or snapshot[&"current_minute"] < 0 \
|
||||
if not snapshot[&"version"] is int or snapshot[&"version"] not in [LEGACY_SNAPSHOT_VERSION, SNAPSHOT_VERSION] \
|
||||
or not snapshot[&"current_minute"] is int or snapshot[&"current_minute"] < 0 \
|
||||
or not snapshot[&"request_sequence"] is int or snapshot[&"request_sequence"] < 0 \
|
||||
or not snapshot[&"shafts"] is Array or not snapshot[&"trips"] is Array:
|
||||
return _invalid("Elevator snapshot header is invalid.")
|
||||
@@ -466,6 +470,9 @@ func restore_snapshot(snapshot: Dictionary) -> bool:
|
||||
queued += 1
|
||||
for connector: Dictionary in _connector_configs(next_shafts[shaft_id][&"config"]):
|
||||
var expected_wait := maxi(queued - _path.elevator_queue_size(connector[&"id"]), 0) * PathService.ORTHOGONAL_MOVE_COST
|
||||
# Legacy saves never priced the shaft queue; v2 must match exactly.
|
||||
if snapshot[&"version"] == LEGACY_SNAPSHOT_VERSION:
|
||||
expected_wait = 0
|
||||
if int(_path.get_connector(connector[&"id"]).get(&"dynamic_cost", -1)) != expected_wait:
|
||||
return _invalid("Path shaft wait disagrees with queued trips.")
|
||||
var path_snapshot := _path.create_snapshot()
|
||||
@@ -488,6 +495,10 @@ func restore_snapshot(snapshot: Dictionary) -> bool:
|
||||
_trips = next_trips
|
||||
_minute = snapshot[&"current_minute"]
|
||||
_sequence = snapshot[&"request_sequence"]
|
||||
if snapshot[&"version"] == LEGACY_SNAPSHOT_VERSION:
|
||||
# Validated legacy queue: derive the shaft-wide wait once on load.
|
||||
for shaft_id: StringName in _names(_shafts):
|
||||
_refresh_shaft_wait(shaft_id)
|
||||
last_error = ""
|
||||
return true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user