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
+43 -3
View File
@@ -17,7 +17,7 @@ signal terminal_state_changed(old_state: StringName, new_state: StringName, reas
const CommandResultType = preload("res://scripts/core/command_result.gd")
const SNAPSHOT_VERSION := 4
const SNAPSHOT_VERSION := 5
const MIN_SUPPORTED_SNAPSHOT_VERSION := 1
const MINUTES_PER_DAY := 1_440
const DEMAND_INTERVAL_MINUTES := 60
@@ -78,6 +78,8 @@ const DAILY_CATEGORIES: Array[StringName] = [
&"construction_cash_flow",
]
const FINANCING_CATEGORIES: Array[StringName] = [&"financing_principal_inflows", &"financing_principal_outflows"]
const DEFAULT_CONFIG := {
&"world_seed": 1,
&"population_cap": 100,
@@ -102,6 +104,8 @@ var _origin_minute := 0
# Historical insolvency evidence is retained without mixing it into new loss streaks.
var _legacy_calendar_last_day := 0
var _legacy_history_last_day := 0
# Closed records from versions 1-4 retain their original principal-excluded basis.
var _legacy_principal_profit_last_day := 0
var _config: Dictionary = DEFAULT_CONFIG.duplicate(true)
var _demand_profiles: Dictionary = {}
@@ -670,6 +674,7 @@ func create_snapshot() -> Dictionary:
&"schema_version": SNAPSHOT_VERSION,
&"legacy_calendar_last_day": _legacy_calendar_last_day,
&"legacy_history_last_day": _legacy_history_last_day,
&"legacy_principal_profit_last_day": _legacy_principal_profit_last_day,
&"origin_minute": _origin_minute,
&"current_minute": current_minute,
&"config": _string_key_dictionary(_config),
@@ -718,6 +723,7 @@ func restore_snapshot(snapshot: Dictionary) -> bool:
# Atomic swap begins only after the entire candidate passed validation.
_legacy_calendar_last_day = int(state[&"legacy_calendar_last_day"])
_legacy_history_last_day = int(state[&"legacy_history_last_day"])
_legacy_principal_profit_last_day = int(state[&"legacy_principal_profit_last_day"])
_origin_minute = int(state[&"origin_minute"])
current_minute = int(state[&"current_minute"])
_config = (state[&"config"] as Dictionary).duplicate(true)
@@ -766,6 +772,8 @@ func validate_invariants() -> Dictionary:
errors.append({&"code": &"INVALID_CONFIG"})
if _population_count < 0 or _population_count > int(_config[&"population_cap"]):
errors.append({&"code": &"INVALID_POPULATION"})
if _legacy_principal_profit_last_day < 0 or _legacy_principal_profit_last_day > _day_summaries.size():
errors.append({&"code": &"INVALID_LEGACY_PRINCIPAL_PROFIT_MARKER"})
if _arrears_total < 0 or _consecutive_insolvency_count < 0:
errors.append({&"code": &"INVALID_INSOLVENCY_STATE"})
if _terminal_state not in [TERMINAL_RUNNING, TERMINAL_BANKRUPT]:
@@ -1531,7 +1539,7 @@ func _normalize_categories(source: Dictionary) -> Dictionary:
return {&"ok": false, &"error": "Daily categories contain duplicate canonical keys."}
for raw_key: Variant in source:
if typeof(raw_key) not in [TYPE_STRING, TYPE_STRING_NAME] \
or StringName(str(raw_key)) not in DAILY_CATEGORIES:
or (StringName(str(raw_key)) not in DAILY_CATEGORIES and StringName(str(raw_key)) not in FINANCING_CATEGORIES):
return {
&"ok": false,
&"error": "Unknown financial category requires explicit classification: %s" % raw_key,
@@ -1546,6 +1554,13 @@ func _normalize_categories(source: Dictionary) -> Dictionary:
&"error": "Daily category '%s' must be a non-negative integer." % category,
}
result[category] = int(value)
for category: StringName in FINANCING_CATEGORIES:
if not source.has(category) and not source.has(String(category)):
continue
var value: Variant = _value(source, category, null)
if not _is_integral_value(value) or int(value) < 0 or int(value) > MAX_FINANCIAL_AMOUNT:
return {&"ok": false, &"error": "Principal financing totals must be non-negative checked integers."}
result[category] = int(value)
return {&"ok": true, &"categories": result}
@@ -1597,6 +1612,11 @@ func _default_daily_apply_result() -> Dictionary:
func _net_profit(categories: Dictionary) -> int:
# Original daily expenses include debt repayment; borrowed principal is not sales.
return _principal_excluded_profit(categories) - int(categories.get(&"financing_principal_outflows", 0))
func _principal_excluded_profit(categories: Dictionary) -> int:
return int(categories.get(&"revenue", 0)) \
- int(categories.get(&"refunds", 0)) \
- int(categories.get(&"cost_of_goods", 0)) \
@@ -1815,6 +1835,8 @@ func _current_snapshot_exact_shape_error(snapshot: Dictionary) -> String:
]
if int(_value(snapshot, &"schema_version", 0)) >= 4:
top_keys.append_array([&"legacy_calendar_last_day", &"legacy_history_last_day"])
if int(_value(snapshot, &"schema_version", 0)) >= 5:
top_keys.append(&"legacy_principal_profit_last_day")
if not _dictionary_has_exact_string_keys(snapshot, top_keys):
return "Operations snapshot has missing or unknown root fields."
@@ -2170,7 +2192,19 @@ func _parse_snapshot(snapshot: Dictionary) -> Dictionary:
for day in range(1, legacy_history + 1):
if not (histories[&"day_summaries"] as Dictionary).has(day):
return {&"ok": false, &"error": "Missing legacy financial history."}
var last_closed_day := 0
for day: int in histories[&"day_summaries"]:
last_closed_day = maxi(last_closed_day, day)
var legacy_principal := last_closed_day
if version >= 5:
var principal_value: Variant = _value(snapshot, &"legacy_principal_profit_last_day", null)
if not _is_integral_value(principal_value):
return {&"ok": false, &"error": "Legacy principal profit marker must be an integer."}
legacy_principal = int(principal_value)
if legacy_principal < 0 or legacy_principal > last_closed_day:
return {&"ok": false, &"error": "Legacy principal profit marker exceeds closed history."}
var state := {
&"legacy_principal_profit_last_day": legacy_principal,
&"legacy_calendar_last_day": legacy_calendar,
&"legacy_history_last_day": legacy_history,
&"origin_minute": restored_origin,
@@ -2206,6 +2240,7 @@ func _parse_snapshot(snapshot: Dictionary) -> Dictionary:
var candidate := OperationsCoordinator.new(state[&"config"])
candidate._legacy_calendar_last_day = legacy_calendar
candidate._legacy_history_last_day = legacy_history
candidate._legacy_principal_profit_last_day = legacy_principal
candidate._origin_minute = restored_origin
candidate.current_minute = restored_minute
candidate._config = (state[&"config"] as Dictionary).duplicate(true)
@@ -2541,7 +2576,8 @@ func _validate_financial_history(errors: Array[Dictionary]) -> void:
if not bool(categories[&"ok"]):
errors.append({&"code": &"INVALID_DAY_CATEGORIES", &"day": day})
continue
var net := _net_profit(categories[&"categories"])
var net := _principal_excluded_profit(categories[&"categories"]) \
if day <= _legacy_principal_profit_last_day else _net_profit(categories[&"categories"])
if net != int(_value(summary, &"net_profit", 0)):
errors.append({&"code": &"NET_PROFIT_MISMATCH", &"day": day})
var difference_value: Variant = _value(summary, &"reconciliation_difference", null)
@@ -3156,3 +3192,7 @@ func _boundary_failure(code: StringName, report: Dictionary) -> CommandResult:
"An operations boundary failed without committing coordinator state.",
{&"boundary": report.duplicate(true)}
)
func is_legacy_principal_profit_history(day: int) -> bool:
return day > 0 and day <= _legacy_principal_profit_last_day