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
+36 -1
View File
@@ -23,6 +23,8 @@ var _transaction_ids: Dictionary = {}
var _idempotency_keys: Dictionary = {}
var _next_transaction_sequence := 1
var _pending_transaction_notifications: Dictionary = {}
# Transient nested observer boundary; never serialized as gameplay state.
var _notification_scopes: Array[Array] = []
func _init(account_definitions: Dictionary = {}) -> void:
@@ -308,7 +310,10 @@ func post(
_next_transaction_sequence = generated_sequence + 1
var posted_entries := get_transaction_entries(effective_id)
if emit_notification:
transaction_posted.emit(effective_id, posted_entries)
if _notification_scopes.is_empty():
transaction_posted.emit(effective_id, posted_entries)
else:
_notification_scopes.back().append(effective_id)
else:
_pending_transaction_notifications[effective_id] = true
return CommandResultType.succeeded(0, {
@@ -318,6 +323,36 @@ func post(
})
## Retain ordinary post semantics while postponing observer delivery through a
## complete event effect/cost boundary. Explicit emit_notification=false remains
## owned by its existing caller, including Operations and supply transactions.
func notification_scope_depth() -> int:
return _notification_scopes.size()
func begin_notification_scope() -> void:
_notification_scopes.append([])
func end_notification_scope() -> void:
assert(not _notification_scopes.is_empty(), "Balanced notification scope required.")
if _notification_scopes.is_empty():
return
var queued: Array = _notification_scopes.pop_back()
if not _notification_scopes.is_empty():
_notification_scopes.back().append_array(queued)
return
var seen: Dictionary = {}
for raw_id: Variant in queued:
var transaction_id := StringName(raw_id)
# Restoring a ledger removes rolled-back IDs. A failure branch can reuse
# an ID; deliver the surviving final receipt once in insertion order.
if seen.has(transaction_id) or not _transaction_ids.has(transaction_id):
continue
seen[transaction_id] = true
transaction_posted.emit(transaction_id, get_transaction_entries(transaction_id))
func has_pending_transaction_notification(transaction_id: StringName) -> bool:
return _pending_transaction_notifications.has(transaction_id)