Save The Tree implementation and acceptance work in progress

Preserve production code, regression fixtures, audio assets and provenance, test infrastructure, and the original-completion plan and progress ledger. Final game and Windows acceptance remain pending; excluded local artifacts and native experiments are not part of this snapshot.
This commit is contained in:
Takeshi
2026-10-11 15:58:00 +09:00
parent 39f6068461
commit b84bade045
235 changed files with 495831 additions and 312 deletions
+134
View File
@@ -27,6 +27,8 @@ func _run() -> void:
_test_missing_actor_releases_lock_and_cost()
_test_content_replacement_boundary()
_test_transaction_policies()
_test_failed_rollback_is_fatal()
_test_failed_cost_release_retains_tokens()
_test_event_snapshot_round_trip_and_atomicity()
_test_event_recovery_lock_scope_and_strict_filter_parse()
if _failures == 0:
@@ -439,3 +441,135 @@ func _expect(condition: bool, label: String) -> void:
else:
_failures += 1
push_error(" not ok %s" % label)
func _test_failed_rollback_is_fatal() -> void:
var cases: Array[Dictionary] = [
{&"name":&"rollback",&"policy":EventDefinitionType.TransactionPolicy.ROLLBACK_ALL},
{&"name":&"branch",&"policy":EventDefinitionType.TransactionPolicy.BRANCH_FAILURE},
{&"name":&"automatic",&"policy":EventDefinitionType.TransactionPolicy.BRANCH_FAILURE,&"auto":true},
{&"name":&"commit",&"policy":EventDefinitionType.TransactionPolicy.ROLLBACK_ALL,&"commit":true},
{&"name":&"skip_self",&"policy":EventDefinitionType.TransactionPolicy.SKIP_FAILED,&"self":true},
{&"name":&"rollback_self",&"policy":EventDefinitionType.TransactionPolicy.ROLLBACK_ALL,&"self":true},
{&"name":&"branch_self",&"policy":EventDefinitionType.TransactionPolicy.BRANCH_FAILURE,&"self":true},
]
for row: Dictionary in cases:
var calls: Array[StringName] = []
var participant := {&"value":0,&"branch":0,&"released":0}
var service := EventServiceType.new().configure_callbacks(
Callable(),
func(action: EventAction, phase: StringName, _context: Dictionary, token: Variant) -> Dictionary:
if phase == &"validate": return {&"ok":true}
if phase == &"rollback":
calls.append(action.action_id)
if action.action_id == &"second": return {&"ok":false,&"error":"explicit participant refusal"}
participant[&"value"] = int(token)
return {&"ok":true}
if action.action_id == &"fallback": participant[&"branch"] += 1
if bool(action.payload.get(&"fail",false)):
if row.get(&"self",false): participant[&"value"] += 7
return {&"ok":false,&"fatal":bool(row.get(&"self",false)),&"error":"explicit failed apply"}
var previous: int = participant[&"value"]
participant[&"value"] += int(action.payload.get(&"delta",0))
return {&"ok":true,&"token":previous},
func(_cost: Dictionary, _context: Dictionary) -> Dictionary: return {&"ok":true,&"token":&"reserved"},
func(_token: Variant, _context: Dictionary) -> Dictionary:
participant[&"released"] += 1
return {&"ok":true},
func(_token: Variant, _context: Dictionary) -> Dictionary: return {&"ok":not bool(row.get(&"commit",false)),&"error":"explicit commit refusal"}
)
var event_id := StringName("failed.rollback."+String(row[&"name"]))
var actions: Array = [_delta_action(&"first",2),_delta_action(&"second",3)]
if not row.get(&"commit",false): actions.append(_failing_action(&"fail"))
var definition := _choice_definition(event_id,10,row[&"policy"],actions,{&"gold":1})
definition.failure_actions = [_delta_action(&"fallback",4)]
if row.get(&"auto",false):
definition.foreground = false
definition.choices = []
definition.automatic_actions.assign(actions)
_expect(service.register_definition(definition).is_success(),"rollback refusal definition registers")
var instance_id := StringName(String(event_id)+".instance")
var result: CommandResult
if row.get(&"auto",false):
_expect(service.enqueue_candidate(event_id,[],0,{&"event_instance_id":instance_id}).is_success(),"automatic rollback refusal enqueue")
result = service.start_next_event(0)
else: result = _run_choice(service,event_id,instance_id)
_expect(not result.is_success() and bool(result.details.get(&"fatal",false)),"refused rollback or failed self restoration propagates fatal outcome")
_expect(service.get_instance(instance_id).state == EventInstanceType.State.ERROR and service.pause_requested,"fatal event stops at ERROR with pause requested")
_expect(participant[&"branch"] == 0,"no fallback executes on unverified rollback")
if row[&"policy"] == EventDefinitionType.TransactionPolicy.SKIP_FAILED:
_expect(calls.is_empty() and participant[&"value"] == 12,"skip policy stops on fatal self restoration without further actions")
else:
_expect(calls == [&"second",&"first"] and participant[&"value"] == 0,"all prior restorations attempted in reverse order despite refusal")
if not row.get(&"auto",false):
_expect(participant[&"released"] == 1,"fatal choice releases reservation once")
var instance: EventInstance = service.get_instance(instance_id)
var before: Dictionary = service.create_snapshot()
var replay := service.submit_choice(instance_id,instance.choice_instance_id,&"accept",0)
_expect(replay.is_replay and not replay.is_success() and bool(replay.details.get(&"fatal",false)),"fatal outcome is cached for choice replay")
_expect(var_to_bytes(before) == var_to_bytes(service.create_snapshot()) and participant[&"released"] == 1,"fatal replay does not mutate event state or release twice")
_expect(service.validate_invariants()[&"ok"],"fatal event lock and queue invariants remain valid")
func _test_failed_cost_release_retains_tokens() -> void:
for mode: StringName in [&"action", &"commit", &"cancel", &"missing", &"finish", &"no_releaser"]:
var calls: Array[StringName] = []
var state := {&"value": 0, &"available": true, &"refuse": true}
var service := EventServiceType.new().configure_callbacks(
func(_actor: StringName) -> bool: return state[&"available"],
func(action: EventAction, phase: StringName, _context: Dictionary, token: Variant) -> Dictionary:
if phase == &"apply":
if bool(action.payload.get(&"fail", false)): return {&"ok": false, &"error": "explicit apply refusal"}
var before := int(state[&"value"])
state[&"value"] += int(action.payload.get(&"delta", 0))
return {&"ok": true, &"token": before}
if phase == &"rollback": state[&"value"] = int(token)
return {&"ok": true},
func(cost: Dictionary, _context: Dictionary) -> Dictionary: return {&"ok": true, &"token": cost.duplicate(true)},
func(token: Variant, _context: Dictionary) -> Dictionary:
calls.append(StringName(str(token.get(&"gold", 0))))
return {&"ok": not state[&"refuse"], &"error": "explicit release refusal"},
func(_token: Variant, _context: Dictionary) -> Dictionary: return {&"ok": mode != &"commit", &"error": "explicit commit refusal"}
)
var actions: Array = [_delta_action(&"primary", 4)]
if mode in [&"action", &"no_releaser"]: actions.append(_failing_action(&"fail"))
var definition := _choice_definition(StringName("release_" + mode), 10, EventDefinitionType.TransactionPolicy.ROLLBACK_ALL, actions, {&"gold": 100})
definition.choices.append(EventChoiceType.new().configure(&"other", &"other", [], {&"gold": 200}, {}, []))
_expect(service.register_definition(definition).is_success(), "%s release definition registers" % mode)
service.enqueue_candidate(definition.event_id, [&"actor"], 0, {&"event_instance_id": &"release_instance"})
var started := service.start_next_event(0)
var instance := service.get_instance(&"release_instance")
_expect(service.reserve_choice_cost(instance.event_instance_id, &"accept", 0).is_success(), "%s actual reservation created" % mode)
if mode in [&"action", &"commit", &"cancel", &"missing", &"finish"]:
_expect(service.reserve_choice_cost(instance.event_instance_id, &"other", 0).is_success(), "%s second reservation created" % mode)
if mode == &"no_releaser": service._cost_releaser = Callable()
var result: CommandResult
if mode == &"cancel":
result = service.cancel_event(instance.event_instance_id)
elif mode == &"missing":
state[&"available"] = false
service.audit_actor_availability(1)
else:
result = service.submit_choice(instance.event_instance_id, started.details[&"choice_instance_id"], &"accept", 0)
if result != null:
_expect(not result.is_success() and result.details.get(&"fatal", false), "%s release failure cannot report success" % mode)
_expect(instance.state == EventInstanceType.State.ERROR and service.pause_requested, "%s release failure stops as ERROR" % mode)
_expect(service.get_actor_locks().is_empty() and service.get_foreground_instance() == null, "%s releases event ownership" % mode)
var expected_ids: Array[StringName] = [&"accept"]
if mode in [&"action", &"commit", &"cancel", &"missing"]: expected_ids.append(&"other")
if mode == &"finish": expected_ids = [&"other"]
_expect(instance.reserved_costs.keys().size() == expected_ids.size(), "%s retains every refused token only" % mode)
for id: StringName in expected_ids:
_expect(instance.reserved_costs.has(id), "%s retains token %s" % [mode, id])
var expected_calls := 2 if mode in [&"action", &"commit", &"cancel", &"missing"] else 0 if mode == &"no_releaser" else 1
_expect(calls.size() == expected_calls, "%s attempts each release once" % mode)
_expect(state[&"value"] == (4 if mode == &"finish" else 0), "%s retains actual action outcome" % mode)
var snapshot := service.create_snapshot()
var restored := EventServiceType.new()
restored.register_definition(definition)
_expect(restored.restore_snapshot(snapshot) and restored.create_snapshot() == snapshot, "%s ERROR with unreleased tokens restores whole" % mode)
_expect(restored.validate_invariants()[&"ok"], "%s retained ERROR token invariants pass" % mode)
if mode not in [&"cancel", &"missing"]:
var before := service.create_snapshot()
var replay := service.submit_choice(instance.event_instance_id, started.details[&"choice_instance_id"], &"accept", 0)
_expect(not replay.is_success() and replay.is_replay and service.create_snapshot() == before and calls.size() == expected_calls, "%s failure cache replay never refunds again" % mode)