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
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
# P14-03 旧形式セーブの fixture
|
||||
|
||||
`legacy_rush_v1/` は、P14-03 より前の本物のセーブパッケージです。待ち時間を shaft 全体で数えるようにする前の版で書き出しています(ElevatorService snapshot v1、Runtime schema 14)。
|
||||
- 籠Aの1階で12人の客が3階行きを待っています。
|
||||
- 昇降機の接続はすべて `dynamic_cost` が0です。
|
||||
|
||||
## 生成方法(2026-10-20)
|
||||
|
||||
1. 作業ツリーの次の2ファイルを、一時的に `50ceca0` 時点の版へ差し替えました。
|
||||
- `scripts/transport/elevator_service.gd`
|
||||
- `scripts/world/path_service.gd`
|
||||
2. `legacy_rush_writer.gd.txt` を `LEGACY_OUT=user://tests/p14_03_legacy_rush` として実行しました(headless)。出力は次のとおりです。
|
||||
- `LEGACY dynamic costs [0, 0, 0, 0, 0, 0, 0]`
|
||||
- `SAVE true`
|
||||
3. 2ファイルを元に戻しました。git の blob が HEAD と一致することを確認済みです。
|
||||
- elevator: 574ba4f3…
|
||||
- path: 5cc9516f…
|
||||
|
||||
## SHA256
|
||||
|
||||
```
|
||||
978fd98f250ae5a9d3249f22adc3dcf032007dde92ddd10d556e050dd87616d8 journal.log
|
||||
80c251341bd3f2a6c4a659f30e477dd856c9fec7961d5b2dfd98d7e9eb5006ab manifest.json
|
||||
0ef55674eca98b6748ae5ccca85a14b042c1545a143810c9c47b487119895c32 thumbnail.png
|
||||
26171ed8994982ed13fe038d225522044f1049070be53d76a4ed5572a227257d world.bin
|
||||
```
|
||||
|
||||
`tests/transport/test_route_wait_choice.gd` が確認する内容は次のとおりです。
|
||||
- この保存は読み込みに成功し、待ち時間が再計算されて v2 として保存されます。
|
||||
- v1 には現れ得ない非0の待ち費用を含む保存は、原子的に拒否されます。
|
||||
@@ -0,0 +1 @@
|
||||
save_completed 2026-10-20T07:38:59
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"absolute_minute": 1091,
|
||||
"checksum_world": "baa5cb8d4eb3ed651934cca0bc1f26f22fd345dc9886a72ca383c3722438ffb9",
|
||||
"content_pack_ids": [],
|
||||
"created_at_real": "2026-10-20T07:38:59",
|
||||
"day": 1,
|
||||
"display_name": "p14_03_legacy_rush",
|
||||
"enabled_filter_profile": "default",
|
||||
"format_version": 1,
|
||||
"game_version": "0.1.0",
|
||||
"save_id": "p14_03_legacy_rush",
|
||||
"seed": 1403,
|
||||
"uncompressed_size": 197716,
|
||||
"updated_at_real": "2026-10-20T07:38:59"
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 83 B |
BIN
Binary file not shown.
+34
@@ -0,0 +1,34 @@
|
||||
extends SceneTree
|
||||
var n := 0
|
||||
func c(rt, clock, k, p):
|
||||
n += 1
|
||||
var r: CommandResult = rt.submit_command(k, p, &"player", &"", 0, clock.absolute_minute, StringName("p1403.%d" % n))
|
||||
if not r.is_success(): print("FAIL ", k, " ", r.message)
|
||||
return r
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
func _run() -> void:
|
||||
var clock: Variant = load("res://autoload/game_clock.gd").new()
|
||||
var state: Variant = load("res://autoload/game_state.gd").new()
|
||||
var rt: Variant = load("res://autoload/simulation_runtime.gd").new()
|
||||
clock.reset(1, 6, 0); state.reset(); rt.initialize(clock, state, 1403); clock.set_paused(true)
|
||||
c(rt, clock, &"change_resources", {&"deltas": {&"gold": 30000, &"materials": 300}})
|
||||
c(rt, clock, &"build_facility", {&"definition_id": &"guest_elevator", &"origin": Vector3i(0,0,0)})
|
||||
c(rt, clock, &"build_facility", {&"definition_id": &"guest_elevator", &"origin": Vector3i(4,0,0)})
|
||||
clock.advance_minutes(360)
|
||||
c(rt, clock, &"build_facility", {&"definition_id": &"guest_elevator", &"origin": Vector3i(0,2,0)})
|
||||
for x in [2, 3]: c(rt, clock, &"build_facility", {&"definition_id": &"guest_corridor", &"origin": Vector3i(x,1,0)})
|
||||
clock.advance_minutes(360)
|
||||
clock.advance_minutes(10 - int(clock.absolute_minute) % 10 + 1)
|
||||
for i in 12:
|
||||
var gid := StringName("rush_%02d" % i)
|
||||
c(rt, clock, &"spawn_guest", {&"guest_id": gid, &"guest_type_id": &"traveler", &"options": {&"current_cell": Vector3i(0,0,0)}})
|
||||
var t = rt.elevators.request_trip(StringName("guest:%s" % gid), Vector3i(0,0,0), Vector3i(0,3,0), clock.absolute_minute)
|
||||
if not t.ok: print("TRIPFAIL ", t)
|
||||
var dyn := []
|
||||
for row in rt.path_service.create_snapshot()[&"connectors"]:
|
||||
if String(row[&"id"]).begins_with("transport."): dyn.append(int(row[&"dynamic_cost"]))
|
||||
print("LEGACY dynamic costs ", dyn)
|
||||
var out := OS.get_environment("LEGACY_OUT")
|
||||
print("SAVE ", SaveService.save_snapshot(out, rt.create_snapshot())[&"ok"], " ", out)
|
||||
rt.free(); clock.free(); state.free(); quit(0)
|
||||
Reference in New Issue
Block a user