P18-01-CODE: 原本関係モデル・旧値保全・Runtime保存と読取経路

This commit is contained in:
Agent Control Runner
2026-10-15 20:58:05 +09:00
parent b7a7cc01d4
commit 265ce30f81
6 changed files with 138 additions and 3 deletions
@@ -1457,6 +1457,7 @@ func _run() -> void:
_expect(runtime.restore_snapshot(retained), "refused departures survive save and readback")
_expect(runtime.relationship_service.get_original_relationship(&"heroine_anri")[&"configured"], "departure never deletes original record")
_extra_coverage(runtime)
_review6_coverage(runtime)
_representative_saves(runtime)
runtime.free()
clock.free()
@@ -1465,6 +1466,93 @@ func _run() -> void:
quit(_failures)
func _review6_recovery(runtime: Variant, snapshot: Dictionary, accepted: bool) -> void:
var path := "user://p18_review6"
SaveService.delete_save(path)
var input := var_to_bytes(snapshot)
_expect(SaveService.save_snapshot(path, snapshot)[&"ok"], "review6 checksum-valid package written")
var before := var_to_bytes(runtime.create_snapshot())
var service: Variant = runtime.relationship_service
var service_bytes := var_to_bytes(service.create_snapshot())
var result: Dictionary = runtime.load_with_recovery(path)
_expect(result[&"ok"] == accepted, "review6 actual recovery outcome")
if not accepted:
_expect(result[&"code"] == &"RESTORE_FAILED" and not result[&"recovery_report"][&"restore_committed"] and not result[&"recovery_report"][&"forbidden_repairs_applied"], "review6 no forbidden repair")
_expect(runtime.relationship_service == service and var_to_bytes(service.create_snapshot()) == service_bytes, "recovery retains service identity and bytes")
_expect(var_to_bytes(runtime.create_snapshot()) == before, "recovery retains complete authority and clock")
_expect(var_to_bytes(snapshot) == input, "recovery preserves caller bytes")
SaveService.delete_save(path)
func _review6_coverage(runtime: Variant) -> void:
var snapshot: Dictionary = runtime.create_snapshot()
var container: Dictionary = snapshot[&"systems"][&"runtime"][&"relationships"]
container[&"legacy"]["relationships"][0]["route_lock"] = "EXCLUSIVE_LOCKED"
container[&"legacy"]["relationships"][0]["route_id"] = "review6_explicit_route"
container[&"relationships"] = container[&"legacy"]["relationships"].duplicate(true)
_expect(runtime.restore_snapshot(snapshot), "valid exclusive route normal positive control")
_review6_recovery(runtime, snapshot, true)
var bad := snapshot.duplicate(true)
var payload: Dictionary = bad[&"systems"][&"runtime"][&"relationships"]
payload[&"legacy"]["relationships"][0]["route_id"] = ""
payload[&"relationships"] = payload[&"legacy"]["relationships"].duplicate(true)
_reject_runtime(runtime, bad)
_review6_recovery(runtime, bad, false)
var service: Variant = runtime.relationship_service
service._register_threshold_candidate(service.get_relationship(&"aliases"), &"affection", 60, 360, false)
snapshot = runtime.create_snapshot()
var legacy: Dictionary = snapshot[&"systems"][&"runtime"][&"relationships"][&"legacy"]
legacy["threshold_candidates"][-1]["review6_extension"] = {"raw": [7, "keep"]}
var v1 := snapshot.duplicate(true)
v1[&"systems"][&"runtime"][&"relationships"] = legacy.duplicate(true)
_expect(runtime.restore_snapshot(v1), "real producer candidate v1 positive")
var roundtrip: Dictionary = runtime.create_snapshot()
_expect(roundtrip[&"systems"][&"runtime"][&"relationships"][&"legacy"] == legacy, "producer raw types and unknown facts preserved")
_expect(runtime.restore_snapshot(roundtrip), "producer v2 readback positive")
_review6_recovery(runtime, roundtrip, true)
var strings := roundtrip.duplicate(true)
var string_candidate: Dictionary = strings[&"systems"][&"runtime"][&"relationships"][&"legacy"]["threshold_candidates"][-1]
for identity: String in ["candidate_id", "relationship_id", "metric_id"]:
string_candidate[identity] = String(string_candidate[identity])
string_candidate["actor_ids"] = ["heroine_anri", "player"]
_expect(runtime.restore_snapshot(strings), "legacy String identifiers remain valid")
_expect(runtime.create_snapshot() == strings, "String identifiers retained without normalization")
_review6_recovery(runtime, strings, true)
_expect(runtime.restore_snapshot(roundtrip), "return to typed producer positive control")
# Restored raw order is intentional; new monotonic producer ids append in order.
service = runtime.relationship_service
var prior_candidates: Array = service.create_snapshot()[&"legacy"]["threshold_candidates"]
service._register_threshold_candidate(service.get_relationship(&"aliases"), &"affection", 61, 361, false)
var appended: Array = service.create_snapshot()[&"legacy"]["threshold_candidates"]
_expect(appended.slice(0, prior_candidates.size()) == prior_candidates and appended.size() == prior_candidates.size() + 1, "mutation preserves restored raw candidate order and appends producer id")
_expect(runtime.restore_snapshot(roundtrip), "candidate mutation control reset")
var wrong := {
"candidate_id": [null, 9, []], "relationship_id": [null, 9, []],
"metric_id": [null, 9, {}], "deduplication_key": [null, 9, {}],
"threshold": ["60", true, 60.0, null], "created_at": ["360", true, 360.0, null],
"requires_unlock_event": [1, "false", null],
"actor_ids": ["actors", {}, [9, &"player"], []]}
for key: String in wrong:
for value: Variant in wrong[key]:
bad = roundtrip.duplicate(true)
payload = bad[&"systems"][&"runtime"][&"relationships"]
payload[&"legacy"]["threshold_candidates"][-1][key] = value
service = runtime.relationship_service
var before := var_to_bytes(service.create_snapshot())
var input := var_to_bytes(payload)
_expect(not service.restore_snapshot(payload), "candidate wrong type rejected by service")
_expect(var_to_bytes(service.create_snapshot()) == before and var_to_bytes(payload) == input, "candidate service rejection atomic")
_reject_runtime(runtime, bad)
_review6_recovery(runtime, bad, false)
var bad_v1 := bad.duplicate(true)
bad_v1[&"systems"][&"runtime"][&"relationships"] = payload[&"legacy"].duplicate(true)
var legacy_input := var_to_bytes(payload[&"legacy"])
_expect(not service.restore_snapshot(payload[&"legacy"]), "v1 candidate wrong type rejected by service")
_expect(var_to_bytes(service.create_snapshot()) == before and var_to_bytes(payload[&"legacy"]) == legacy_input, "v1 candidate rejection preserves service and input")
_reject_runtime(runtime, bad_v1)
_review6_recovery(runtime, bad_v1, false)
func _reject_runtime(runtime: Variant, candidate: Dictionary) -> void:
var before := var_to_bytes(runtime.create_snapshot())
var service: Variant = runtime.relationship_service