Record original-alignment implementation and traceability checkpoint

Capture current source, content data, tests, asset licenses, and original-specification traceability. Original implementation remains incomplete. The accepted matching UI generation passed 154 suites and 12,253 checks, with eight rendered staff-contract screens reviewed. Latest native Windows and full-original acceptance remain outstanding.
This commit is contained in:
Takeshi
2026-09-30 23:52:24 +09:00
parent 6077e02ebe
commit 5dde0c5ec2
490 changed files with 54051 additions and 809 deletions
+271 -68
View File
@@ -17,13 +17,13 @@ signal terminal_state_changed(old_state: StringName, new_state: StringName, reas
const CommandResultType = preload("res://scripts/core/command_result.gd")
const SNAPSHOT_VERSION := 3
const SNAPSHOT_VERSION := 4
const MIN_SUPPORTED_SNAPSHOT_VERSION := 1
const MINUTES_PER_DAY := 1_440
const DEMAND_INTERVAL_MINUTES := 60
const ARRIVAL_INTERVAL_MINUTES := 30
const MORNING_MINUTE_OF_DAY := 360
const FIRST_DAILY_CLOSE_MINUTE := MORNING_MINUTE_OF_DAY + MINUTES_PER_DAY
const FIRST_DAILY_CLOSE_MINUTE := MINUTES_PER_DAY
const KEY_SEPARATOR := "\u001f"
const MAX_START_MINUTE := 360
const MAX_TRACKED_DAYS := 31
@@ -98,6 +98,11 @@ var last_error := ""
var _origin_minute := 0
# Old saves finish their open 06:00 period once, then use midnight.
# Historical insolvency evidence is retained without mixing it into new loss streaks.
var _legacy_calendar_last_day := 0
var _legacy_history_last_day := 0
var _config: Dictionary = DEFAULT_CONFIG.duplicate(true)
var _demand_profiles: Dictionary = {}
var _arrival_carry: Dictionary = {}
@@ -111,6 +116,7 @@ var _processed_arrival_minutes: Dictionary = {}
var _population_count := 0
var _arrears_total := 0
# Serialized field name retained for compatibility; new closes count net losses.
var _consecutive_insolvency_count := 0
var _terminal_state: StringName = TERMINAL_RUNNING
var _next_arrival_plan_sequence := 1
@@ -129,6 +135,7 @@ var _notification_queue: Array[Dictionary] = []
var _notification_delivery_deferred := false
var _initialization_valid := true
var _midnight_boundary := Callable()
var _daily_close_boundary := Callable()
var _arrival_boundary := Callable()
var _morning_boundary := Callable()
@@ -163,11 +170,13 @@ func _init(config: Dictionary = {}) -> void:
func configure_callbacks(
daily_close_boundary: Callable = Callable(),
arrival_boundary: Callable = Callable(),
morning_boundary: Callable = Callable()
morning_boundary: Callable = Callable(),
midnight_boundary: Callable = Callable()
) -> OperationsCoordinator:
_daily_close_boundary = daily_close_boundary
_arrival_boundary = arrival_boundary
_morning_boundary = morning_boundary
_midnight_boundary = midnight_boundary
return self
@@ -548,6 +557,19 @@ func can_start_construction_or_investment() -> Dictionary:
}
## Compact, defensive projection for the continuously visible operations HUD.
func get_dashboard_summary() -> Dictionary:
var latest_day := -1
for day: int in _day_summaries:
latest_day = maxi(latest_day, day)
var summaries: Array[Dictionary] = []
if latest_day >= 0:
var latest: Dictionary = _day_summaries[latest_day]
summaries.append({&"day":latest[&"day"], &"net_profit":latest[&"net_profit"]})
return {&"terminal_state":_terminal_state, &"consecutive_insolvency_count":_consecutive_insolvency_count,
&"legacy_history_last_day":_legacy_history_last_day, &"day_summaries":summaries}
func get_day_summary(day: int) -> Dictionary:
if not _day_summaries.has(day):
return {}
@@ -598,7 +620,8 @@ func create_snapshot() -> Dictionary:
if _notification_delivery_deferred or not _notification_queue.is_empty():
last_error = "Deferred Operations notifications must be resolved before snapshotting."
return {}
var internal_report := _variant_tree_report({
var field_cache: Dictionary = {}
var internal_report := _snapshot_root_report({
&"config": _config,
&"demand_profiles": _demand_profiles,
&"arrival_carry": _arrival_carry,
@@ -608,7 +631,7 @@ func create_snapshot() -> Dictionary:
&"morning_reports": _morning_reports,
&"alerts": _alerts,
&"quarantine_report": _quarantine_report,
})
}, field_cache, true)
var shape_error := _internal_snapshot_shape_error()
if not bool(internal_report[&"ok"]) or not shape_error.is_empty():
last_error = "Operations state cannot be serialized: %s" % [
@@ -636,20 +659,27 @@ func create_snapshot() -> Dictionary:
var saved_mornings: Array[Dictionary] = []
for day: int in _sorted_int_keys(_morning_reports):
saved_mornings.append((_morning_reports[day] as Dictionary).duplicate(true))
saved_mornings.append(_morning_reports[day])
var saved_days: Array[Dictionary] = []
for day: int in _sorted_int_keys(_day_summaries):
saved_days.append(_day_summaries[day])
# These borrowed containers never leave this synchronous method. The final
# canonical conversion recursively creates owned dictionaries and arrays.
var raw_snapshot := {
&"schema_version": SNAPSHOT_VERSION,
&"legacy_calendar_last_day": _legacy_calendar_last_day,
&"legacy_history_last_day": _legacy_history_last_day,
&"origin_minute": _origin_minute,
&"current_minute": current_minute,
&"config": _string_key_dictionary(_config),
&"demand_profiles": saved_profiles,
&"arrival_carry": saved_carry,
&"demand_history": _demand_history.duplicate(true),
&"arrival_reports": _arrival_reports.duplicate(true),
&"day_summaries": get_day_summaries(),
&"demand_history": _demand_history,
&"arrival_reports": _arrival_reports,
&"day_summaries": saved_days,
&"morning_reports": saved_mornings,
&"alerts": _alerts.duplicate(true),
&"alerts": _alerts,
&"processed_demand_minutes": _sorted_int_keys(_processed_demand_minutes),
&"processed_arrival_minutes": _sorted_int_keys(_processed_arrival_minutes),
&"population_count": _population_count,
@@ -666,13 +696,13 @@ func create_snapshot() -> Dictionary:
&"deferred_boundary_minute": _deferred_boundary_minute,
&"pause_reason": String(_pause_reason),
&"external_quarantined": _external_quarantined,
&"quarantine_report": _quarantine_report.duplicate(true),
&"quarantine_report": _quarantine_report,
}
var tree_report := _variant_tree_report(raw_snapshot)
var tree_report := _snapshot_root_report(raw_snapshot, field_cache, false)
if not bool(tree_report[&"ok"]):
last_error = "Operations state cannot be serialized: %s" % tree_report[&"code"]
return {}
return _to_snapshot_variant(raw_snapshot)
return tree_report[&"value"]
func restore_snapshot(snapshot: Dictionary) -> bool:
@@ -686,6 +716,8 @@ func restore_snapshot(snapshot: Dictionary) -> bool:
return false
var state: Dictionary = parsed[&"state"]
# 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"])
_origin_minute = int(state[&"origin_minute"])
current_minute = int(state[&"current_minute"])
_config = (state[&"config"] as Dictionary).duplicate(true)
@@ -840,9 +872,15 @@ func validate_invariants() -> Dictionary:
func _process_minute_boundaries(minute: int, counts: Dictionary) -> CommandResult:
# Fixed 06:00 boundary order: prior operating-day finance, morning
# operations, demand, arrivals. The first 06:00 opens Day 1; the first close
# occurs at Day 2 06:00 after a complete 24-hour operating period.
# Migrated 06:00 financial periods retain their original payroll/history.
# Calendar-midnight obligations still execute atomically at 00:00. Their
# external receipt owns idempotency when a later boundary in this minute fails.
if minute % MINUTES_PER_DAY == 0 and not _is_daily_close_boundary(minute) and _midnight_boundary.is_valid():
var midnight := _run_boundary_transaction(_midnight_boundary, {&"boundary_minute": minute}, {&"ok": true})
if not bool(midnight[&"ok"]):
return _transaction_boundary_failure(midnight, &"MIDNIGHT_UPKEEP", minute, &"MIDNIGHT_UPKEEP_FAILED")
# Finance precedes demand/arrivals at midnight. Morning work stays at 06:00.
# During legacy migration, the final 06:00 close also precedes morning work.
if _is_daily_close_boundary(minute):
var close := _process_daily_close(minute)
if not close.is_success():
@@ -1086,7 +1124,7 @@ func _process_daily_close(boundary_minute: int) -> CommandResult:
&"operation": &"DAILY_CLOSE",
&"day": completed_day,
&"boundary_minute": boundary_minute,
&"period_start_minute": boundary_minute - MINUTES_PER_DAY,
&"period_start_minute": get_financial_period_start(completed_day),
&"period_end_minute_exclusive": boundary_minute,
&"idempotency_key": "daily-close:%d" % completed_day,
&"prior_arrears_total": _arrears_total,
@@ -1097,7 +1135,7 @@ func _process_daily_close(boundary_minute: int) -> CommandResult:
&"GENERATE_FACILITY_PROFIT_LOSS",
&"DETECT_ANOMALIES",
&"BUILD_DAY_SUMMARY",
&"EVALUATE_ARREARS_AND_BANKRUPTCY",
&"EVALUATE_LOSS_STREAK_AND_BANKRUPTCY",
],
}
var transaction := _run_boundary_transaction(
@@ -1141,14 +1179,15 @@ func _process_daily_close(boundary_minute: int) -> CommandResult:
previous_profit = int((_day_summaries[completed_day - 1] as Dictionary)[&"net_profit"])
var rolling := _rolling_profit_with(net_profit)
var arrears := int((result[&"settlement"] as Dictionary)[&"arrears_total"])
var consecutive := _consecutive_insolvency_count + 1 if arrears > 0 else 0
var prior_streak := 0 if completed_day == _legacy_history_last_day + 1 else _consecutive_insolvency_count
var consecutive := prior_streak + 1 if net_profit < 0 else 0
var future_terminal := _terminal_state
if consecutive >= int(_config[&"bankruptcy_close_count"]):
future_terminal = TERMINAL_BANKRUPT
var reconciliation_difference := int(result[&"reconciliation_difference"])
var summary := {
&"day": completed_day,
&"period_start_minute": boundary_minute - MINUTES_PER_DAY,
&"period_start_minute": get_financial_period_start(completed_day),
&"period_end_minute_exclusive": boundary_minute,
&"closed_at": boundary_minute,
&"category_totals": category_totals,
@@ -1181,6 +1220,9 @@ func _process_daily_close(boundary_minute: int) -> CommandResult:
&"difference": reconciliation_difference,
&"automatic_correction": false,
})
if net_profit < 0:
_append_alert({&"code": &"LOSS_STREAK", &"minute": boundary_minute,
&"day": completed_day, &"net_profit": net_profit, &"consecutive_count": consecutive})
if arrears > 0:
_append_alert({
&"code": &"ARREARS_REMAIN",
@@ -1201,7 +1243,7 @@ func _process_daily_close(boundary_minute: int) -> CommandResult:
})
_queue_notification(
&"terminal",
[old_state, _terminal_state, &"CONSECUTIVE_INSOLVENCY"]
[old_state, _terminal_state, &"CONSECUTIVE_LOSSES"]
)
_queue_notification(&"daily", [summary.duplicate(true)])
return _success(summary)
@@ -1771,8 +1813,10 @@ func _current_snapshot_exact_shape_error(snapshot: Dictionary) -> String:
&"deferred_boundary_minute", &"pause_reason", &"external_quarantined",
&"quarantine_report",
]
if int(_value(snapshot, &"schema_version", 0)) >= 4:
top_keys.append_array([&"legacy_calendar_last_day", &"legacy_history_last_day"])
if not _dictionary_has_exact_string_keys(snapshot, top_keys):
return "Operations v3 snapshot has missing or unknown root fields."
return "Operations snapshot has missing or unknown root fields."
var profiles: Variant = _value(snapshot, &"demand_profiles", null)
var carry: Variant = _value(snapshot, &"arrival_carry", null)
@@ -1782,33 +1826,33 @@ func _current_snapshot_exact_shape_error(snapshot: Dictionary) -> String:
var mornings: Variant = _value(snapshot, &"morning_reports", null)
if not profiles is Array or not carry is Array or not demand_history is Array \
or not arrivals is Array or not days is Array or not mornings is Array:
return "Operations v3 snapshot history collections are malformed."
return "Operations snapshot history collections are malformed."
for raw_profile: Variant in profiles:
if not raw_profile is Dictionary or not _dictionary_has_exact_string_keys(
raw_profile,
[&"facility_tag", &"guest_class", &"time_band", &"components",
&"demand_index", &"last_evaluated_at"]
):
return "Operations v3 demand profile has missing or unknown fields."
return "Operations demand profile has missing or unknown fields."
for raw_carry: Variant in carry:
if not raw_carry is Dictionary or not _dictionary_has_exact_string_keys(
raw_carry, [&"facility_tag", &"guest_class", &"time_band", &"numerator"]
):
return "Operations v3 arrival carry row has missing or unknown fields."
return "Operations arrival carry row has missing or unknown fields."
for raw_report: Variant in demand_history:
if not raw_report is Dictionary or not _dictionary_has_exact_string_keys(
raw_report, [&"minute", &"values"]
):
return "Operations v3 demand history row has missing or unknown fields."
return "Operations demand history row has missing or unknown fields."
var values: Variant = (raw_report as Dictionary).get(&"values", null)
if not values is Array:
return "Operations v3 demand history values are malformed."
return "Operations demand history values are malformed."
for raw_value: Variant in values:
if not raw_value is Dictionary or not _dictionary_has_exact_string_keys(
raw_value,
[&"facility_tag", &"guest_class", &"time_band", &"demand_index"]
):
return "Operations v3 demand history value has missing or unknown fields."
return "Operations demand history value has missing or unknown fields."
for raw_report: Variant in arrivals:
if not raw_report is Dictionary or not _dictionary_has_exact_string_keys(
raw_report,
@@ -1816,18 +1860,18 @@ func _current_snapshot_exact_shape_error(snapshot: Dictionary) -> String:
&"plans", &"total_count", &"population_after", &"capacity_remaining",
&"carry_capped"]
):
return "Operations v3 arrival report has missing or unknown fields."
return "Operations arrival report has missing or unknown fields."
var plans: Variant = (raw_report as Dictionary).get(&"plans", null)
var capped: Variant = (raw_report as Dictionary).get(&"carry_capped", null)
if not plans is Array or not capped is Array:
return "Operations v3 arrival report collections are malformed."
return "Operations arrival report collections are malformed."
for raw_plan: Variant in plans:
if not raw_plan is Dictionary or not _dictionary_has_exact_string_keys(
raw_plan,
[&"plan_id", &"minute", &"facility_tag", &"guest_class", &"time_band",
&"demand_index", &"count", &"guest_ids"]
):
return "Operations v3 arrival plan has missing or unknown fields."
return "Operations arrival plan has missing or unknown fields."
for raw_capped: Variant in capped:
if not raw_capped is Dictionary or not _dictionary_has_exact_string_keys(
raw_capped, [&"facility_tag", &"guest_class", &"discarded_numerator"]
@@ -1918,7 +1962,7 @@ func _parse_snapshot(snapshot: Dictionary) -> Dictionary:
var version := int(version_value)
if version < MIN_SUPPORTED_SNAPSHOT_VERSION or version > SNAPSHOT_VERSION:
return {&"ok": false, &"error": "Unsupported operations snapshot version."}
if version == SNAPSHOT_VERSION:
if version >= 3:
var exact_shape_error := _current_snapshot_exact_shape_error(snapshot)
if not exact_shape_error.is_empty():
return {&"ok": false, &"error": exact_shape_error}
@@ -2106,7 +2150,29 @@ func _parse_snapshot(snapshot: Dictionary) -> Dictionary:
if typeof(quarantine_value) != TYPE_BOOL or not quarantine_report_value is Dictionary:
return {&"ok": false, &"error": "External quarantine snapshot state is malformed."}
var legacy_history := 0
var legacy_calendar := 0
if version < 4:
for day: int in histories[&"day_summaries"]:
legacy_history = maxi(legacy_history, day)
legacy_calendar = legacy_history + 1
else:
var calendar_value: Variant = _value(snapshot, &"legacy_calendar_last_day", null)
var history_value: Variant = _value(snapshot, &"legacy_history_last_day", null)
if not _is_integral_value(calendar_value) or not _is_integral_value(history_value):
return {&"ok": false, &"error": "Invalid legacy calendar markers."}
legacy_calendar = int(calendar_value)
legacy_history = int(history_value)
if legacy_history < 0 or legacy_calendar < 0 or legacy_calendar > MAX_TRACKED_DAYS + 1 \
or (legacy_calendar != 0 and legacy_calendar != legacy_history + 1) \
or (legacy_calendar == 0 and legacy_history != 0):
return {&"ok": false, &"error": "Invalid legacy calendar transition."}
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 state := {
&"legacy_calendar_last_day": legacy_calendar,
&"legacy_history_last_day": legacy_history,
&"origin_minute": restored_origin,
&"current_minute": restored_minute,
&"config": normalized_config[&"config"],
@@ -2138,6 +2204,8 @@ func _parse_snapshot(snapshot: Dictionary) -> Dictionary:
# Validate the fully assembled state using a temporary instance without
# copying any callback into save data.
var candidate := OperationsCoordinator.new(state[&"config"])
candidate._legacy_calendar_last_day = legacy_calendar
candidate._legacy_history_last_day = legacy_history
candidate._origin_minute = restored_origin
candidate.current_minute = restored_minute
candidate._config = (state[&"config"] as Dictionary).duplicate(true)
@@ -2459,7 +2527,7 @@ func _validate_financial_history(errors: Array[Dictionary]) -> void:
var expected_close := _daily_close_minute_for_day(day)
if int(_value(summary, &"day", 0)) != day \
or int(_value(summary, &"closed_at", -1)) != expected_close \
or int(_value(summary, &"period_start_minute", -1)) != expected_close - MINUTES_PER_DAY \
or int(_value(summary, &"period_start_minute", -1)) != get_financial_period_start(day) \
or int(_value(summary, &"period_end_minute_exclusive", -1)) != expected_close \
or expected_close <= _origin_minute \
or expected_close > maximum_committed_minute:
@@ -2520,7 +2588,10 @@ func _validate_financial_history(errors: Array[Dictionary]) -> void:
or int(_value(settlement_value, &"arrears_total", -2)) != expected_arrears \
or not _variant_tree_report(settlement_value)[&"ok"]:
errors.append({&"code": &"SETTLEMENT_ARREARS_MISMATCH", &"day": day})
expected_consecutive = expected_consecutive + 1 if expected_arrears > 0 else 0
if day == _legacy_history_last_day + 1:
expected_consecutive = 0
var failed_close := expected_arrears > 0 if day <= _legacy_history_last_day else net < 0
expected_consecutive = expected_consecutive + 1 if failed_close else 0
if int(_value(summary, &"consecutive_insolvency_count", -1)) != expected_consecutive:
errors.append({&"code": &"INSOLVENCY_COUNT_MISMATCH", &"day": day})
if expected_consecutive >= int(_config[&"bankruptcy_close_count"]):
@@ -2614,6 +2685,7 @@ func _validate_partial_boundary_prefix(minute: int, errors: Array[Dictionary]) -
func _validate_alerts_and_pause(errors: Array[Dictionary]) -> void:
var imbalance_by_day: Dictionary = {}
var arrears_by_day: Dictionary = {}
var losses_by_day: Dictionary = {}
var bankrupt_count := 0
var quarantine_count := 0
for alert: Dictionary in _alerts:
@@ -2625,6 +2697,16 @@ func _validate_alerts_and_pause(errors: Array[Dictionary]) -> void:
&"LEDGER_IMBALANCE":
var day := int(_value(alert, &"day", 0))
imbalance_by_day[day] = int(imbalance_by_day.get(day, 0)) + 1
&"LOSS_STREAK":
var day := int(_value(alert, &"day", 0))
losses_by_day[day] = int(losses_by_day.get(day, 0)) + 1
var summary: Dictionary = _day_summaries.get(day, {})
if summary.is_empty() or day <= _legacy_history_last_day \
or int(_value(alert, &"net_profit", 0)) >= 0 \
or _value(alert, &"minute", null) != summary.get(&"closed_at") \
or _value(alert, &"net_profit", null) != summary.get(&"net_profit") \
or _value(alert, &"consecutive_count", null) != summary.get(&"consecutive_insolvency_count"):
errors.append({&"code": &"INVALID_LOSS_ALERT", &"day": day})
&"ARREARS_REMAIN":
var day := int(_value(alert, &"day", 0))
arrears_by_day[day] = int(arrears_by_day.get(day, 0)) + 1
@@ -2641,6 +2723,9 @@ func _validate_alerts_and_pause(errors: Array[Dictionary]) -> void:
var imbalanced := int(_value(summary, &"reconciliation_difference", 0)) != 0
if int(imbalance_by_day.get(day, 0)) != int(imbalanced):
errors.append({&"code": &"IMBALANCE_ALERT_MISMATCH", &"day": day})
var new_loss := day > _legacy_history_last_day and int(_value(summary, &"net_profit", 0)) < 0
if int(losses_by_day.get(day, 0)) != int(new_loss):
errors.append({&"code": &"LOSS_ALERT_MISMATCH", &"day": day})
var has_arrears := int(_value(summary, &"arrears_total", 0)) > 0
if int(arrears_by_day.get(day, 0)) != int(has_arrears):
errors.append({&"code": &"ARREARS_ALERT_MISMATCH", &"day": day})
@@ -2725,16 +2810,32 @@ func _minute_has_scheduled_boundary(minute: int) -> bool:
func _is_daily_close_boundary(minute: int) -> bool:
return minute >= FIRST_DAILY_CLOSE_MINUTE \
and minute % MINUTES_PER_DAY == MORNING_MINUTE_OF_DAY
var day := minute / MINUTES_PER_DAY
return day > 0 and minute == get_daily_close_minute(day)
func _financial_day_for_boundary(boundary_minute: int) -> int:
return (boundary_minute - MORNING_MINUTE_OF_DAY) / MINUTES_PER_DAY
return boundary_minute / MINUTES_PER_DAY
func _daily_close_minute_for_day(day: int) -> int:
return day * MINUTES_PER_DAY + MORNING_MINUTE_OF_DAY
return get_daily_close_minute(day)
func get_daily_close_minute(day: int) -> int:
return day * MINUTES_PER_DAY + (MORNING_MINUTE_OF_DAY if day <= _legacy_calendar_last_day else 0)
func is_legacy_financial_history(day: int) -> bool:
return day <= _legacy_history_last_day
func get_open_financial_day() -> int:
return _day_summaries.size() + 1
func get_financial_period_start(day: int) -> int:
return get_daily_close_minute(day - 1) if day > 1 else (MORNING_MINUTE_OF_DAY if _legacy_calendar_last_day > 0 else 0)
func _max_carry_for_config(config: Dictionary) -> int:
@@ -2764,67 +2865,169 @@ static func _is_save_safe(value: Variant, depth := 0) -> bool:
static func _variant_tree_report(value: Variant) -> Dictionary:
var budget := {&"nodes": 0, &"string_length": 0}
# Shared per-traversal counters: [visited nodes, total string length].
var budget: Array[int] = [0, 0]
var issue := _inspect_variant_tree(value, budget, 0)
if not issue.is_empty():
return {&"ok": false, &"code": issue}
return {
&"ok": true,
&"code": &"OK",
&"nodes": int(budget[&"nodes"]),
&"string_length": int(budget[&"string_length"]),
&"nodes": budget[0],
&"string_length": budget[1],
}
static func _inspect_variant_tree(
value: Variant,
budget: Dictionary,
budget: Array[int],
depth: int
) -> StringName:
var issues: Array[StringName] = []
_visit_snapshot_tree(value, budget, depth, issues, false)
return issues[0] if not issues.is_empty() else &""
static func _snapshot_tree_report(value: Variant) -> Dictionary:
var budget: Array[int] = [0, 0]
var issues: Array[StringName] = []
var encoded: Variant = _visit_snapshot_tree(value, budget, 0, issues, true)
if not issues.is_empty():
return {&"ok": false, &"code": issues[0]}
return {&"ok": true, &"code": &"OK", &"nodes": budget[0],
&"string_length": budget[1], &"value": encoded}
# Capture validated, canonical copies for unchanged root fields.
# The cache never survives create_snapshot and only root-depth subtrees reuse it.
# Use only for that synchronous internal-to-output conversion: these four fields
# have identical source values and depths in both root dictionaries. No callbacks
# or state mutation may occur between capture and reuse. Aggregate-limit failure
# still uses the original visitor to retain its exact error precedence.
static func _snapshot_root_report(source: Dictionary, cache: Dictionary, capture: bool) -> Dictionary:
var budget: Array[int] = [1, 0]
var issues: Array[StringName] = []
var converted: Dictionary = {}
if source.size() > MAX_SAFE_COLLECTION_SIZE:
return {&"ok": false, &"code": &"COLLECTION_TOO_LARGE"}
if not _canonical_key_collision(source).is_empty():
return {&"ok": false, &"code": &"DUPLICATE_CANONICAL_KEY"}
for key: Variant in source:
if typeof(key) not in [TYPE_STRING, TYPE_STRING_NAME, TYPE_INT]:
return {&"ok": false, &"code": &"INVALID_DICTIONARY_KEY"}
budget[0] += 1
if budget[0] > MAX_VARIANT_NODES:
return {&"ok": false, &"code": &"MAX_VARIANT_NODES"}
var name := str(key)
var length := name.length()
if length > MAX_SINGLE_STRING_LENGTH:
return {&"ok": false, &"code": &"STRING_TOO_LONG"}
budget[1] += length
if budget[1] > MAX_TOTAL_STRING_LENGTH:
return {&"ok": false, &"code": &"TOTAL_STRING_BUDGET"}
var node_start := budget[0]
var string_start := budget[1]
var reusable := name in ["demand_history", "arrival_reports", "alerts", "quarantine_report"]
var value: Variant
var cached: Dictionary = cache.get(name, {}) if not capture else {}
if not cached.is_empty() and budget[0] + cached[&"nodes"] <= MAX_VARIANT_NODES and budget[1] + cached[&"strings"] <= MAX_TOTAL_STRING_LENGTH:
budget[0] += cached[&"nodes"]
budget[1] += cached[&"strings"]
value = cached[&"value"]
else:
# Fall back to the original source-order visitor when an aggregate
# limit can fail, preserving which budget error occurs first.
value = _visit_snapshot_tree(source[key], budget, 1, issues, not capture or reusable)
if not issues.is_empty():
return {&"ok": false, &"code": issues[0]}
if capture and reusable:
cache[name] = {&"nodes": budget[0] - node_start, &"strings": budget[1] - string_start, &"value": value}
elif not capture:
converted[name] = value
converted.sort()
return {&"ok": true, &"code": &"OK", &"nodes": budget[0], &"string_length": budget[1], &"value": converted}
static func _snapshot_tree_issue(issues: Array[StringName], code: StringName) -> Variant:
issues.append(code)
return null
static func _visit_snapshot_tree(
value: Variant,
budget: Array[int],
depth: int,
issues: Array[StringName],
encode: bool
) -> Variant:
# The validator and encoder share one traversal so their depth, key and
# aggregate budgets cannot drift. Validation-only callers allocate no copies.
if depth > MAX_VARIANT_DEPTH:
return &"MAX_VARIANT_DEPTH"
budget[&"nodes"] = int(budget[&"nodes"]) + 1
if int(budget[&"nodes"]) > MAX_VARIANT_NODES:
return &"MAX_VARIANT_NODES"
return _snapshot_tree_issue(issues, &"MAX_VARIANT_DEPTH")
budget[0] += 1
if budget[0] > MAX_VARIANT_NODES:
return _snapshot_tree_issue(issues, &"MAX_VARIANT_NODES")
match typeof(value):
TYPE_NIL, TYPE_BOOL, TYPE_INT:
return &""
return value
TYPE_FLOAT:
return &"" if is_finite(float(value)) else &"NON_FINITE_NUMBER"
return value if is_finite(float(value)) else _snapshot_tree_issue(issues, &"NON_FINITE_NUMBER")
TYPE_STRING, TYPE_STRING_NAME:
var text := String(value)
if text.length() > MAX_SINGLE_STRING_LENGTH:
return &"STRING_TOO_LONG"
budget[&"string_length"] = int(budget[&"string_length"]) + text.length()
return &"" if int(budget[&"string_length"]) <= MAX_TOTAL_STRING_LENGTH \
else &"TOTAL_STRING_BUDGET"
return _snapshot_tree_issue(issues, &"STRING_TOO_LONG")
budget[1] += text.length()
if budget[1] > MAX_TOTAL_STRING_LENGTH:
return _snapshot_tree_issue(issues, &"TOTAL_STRING_BUDGET")
return text
TYPE_ARRAY:
var values: Array = value
if values.size() > MAX_SAFE_COLLECTION_SIZE:
return &"COLLECTION_TOO_LARGE"
return _snapshot_tree_issue(issues, &"COLLECTION_TOO_LARGE")
var converted: Variant = [] if encode else null
for child: Variant in values:
var issue := _inspect_variant_tree(child, budget, depth + 1)
if not issue.is_empty():
return issue
return &""
var encoded: Variant = _visit_snapshot_tree(child, budget, depth + 1, issues, encode)
if not issues.is_empty():
return null
if encode:
converted.append(encoded)
return converted
TYPE_DICTIONARY:
var source: Dictionary = value
if source.size() > MAX_SAFE_COLLECTION_SIZE:
return &"COLLECTION_TOO_LARGE"
return _snapshot_tree_issue(issues, &"COLLECTION_TOO_LARGE")
if not _canonical_key_collision(source).is_empty():
return &"DUPLICATE_CANONICAL_KEY"
return _snapshot_tree_issue(issues, &"DUPLICATE_CANONICAL_KEY")
var converted: Variant = {} if encode else null
# Validate in source order, retaining the historical error precedence.
for key: Variant in source:
if typeof(key) not in [TYPE_STRING, TYPE_STRING_NAME, TYPE_INT]:
return &"INVALID_DICTIONARY_KEY"
var key_issue := _inspect_variant_tree(str(key), budget, depth + 1)
if not key_issue.is_empty():
return key_issue
var value_issue := _inspect_variant_tree(source[key], budget, depth + 1)
if not value_issue.is_empty():
return value_issue
return &""
return _snapshot_tree_issue(issues, &"INVALID_DICTIONARY_KEY")
if depth + 1 > MAX_VARIANT_DEPTH:
return _snapshot_tree_issue(issues, &"MAX_VARIANT_DEPTH")
budget[0] += 1
if budget[0] > MAX_VARIANT_NODES:
return _snapshot_tree_issue(issues, &"MAX_VARIANT_NODES")
var string_key := str(key)
var key_length := string_key.length()
if key_length > MAX_SINGLE_STRING_LENGTH:
return _snapshot_tree_issue(issues, &"STRING_TOO_LONG")
budget[1] += key_length
if budget[1] > MAX_TOTAL_STRING_LENGTH:
return _snapshot_tree_issue(issues, &"TOTAL_STRING_BUDGET")
var encoded: Variant = _visit_snapshot_tree(source[key], budget, depth + 1, issues, encode)
if not issues.is_empty():
return null
if encode:
converted[string_key] = encoded
if not encode:
return null
# Every key is now a unique String. Native string sorting preserves
# canonical byte order without repeated Variant-to-string callbacks.
converted.sort()
return converted
_:
return &"UNSAVEABLE_VARIANT"
return _snapshot_tree_issue(issues, &"UNSAVEABLE_VARIANT")
static func _canonical_key_collision(source: Dictionary) -> Dictionary: