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
+208
View File
@@ -0,0 +1,208 @@
class_name FacilityUpkeepAccrual
extends RefCounted
## Exact upkeep accumulation in gold-minute units. The caller supplies the
## applicable daily rates for [current_minute, target_minute); this component
## deliberately does not decide whether closed/suspended rooms are billable.
## No money is rounded, debited, or forgiven here. Settlement owns those rules.
const SNAPSHOT_VERSION := 1
const MINUTES_PER_DAY := 1440
const MAX_DAILY_RATE := 1000000000
const MAX_FACILITIES := 20000
const MAX_PERIODS := 10000
const MAX_MINUTE := 1000000000
var _started_at := -1
var _current_minute := -1
var _period_start := -1
var _pending_units: Dictionary = {}
var _closed_periods: Array[Dictionary] = []
func start_at(minute: int) -> Dictionary:
if _started_at >= 0:
return _failure(&"ALREADY_STARTED")
if minute < 0 or minute > MAX_MINUTE:
return _failure(&"INVALID_MINUTE")
_started_at = minute
_current_minute = minute
_period_start = minute
return {&"ok": true}
func get_current_minute() -> int:
return _current_minute
func advance_to(minute: int, daily_rates: Dictionary) -> Dictionary:
if _started_at < 0:
return _failure(&"NOT_STARTED")
if minute < _current_minute or minute > MAX_MINUTE:
return _failure(&"INVALID_MINUTE")
# A bounded batch also supports migration/testing without an unbounded loop.
if minute - _current_minute > MINUTES_PER_DAY:
return _failure(&"INTERVAL_TOO_LARGE")
var parsed := _parse_units(daily_rates, MAX_DAILY_RATE)
if not parsed[&"ok"]:
return _failure(&"INVALID_RATES")
var rates: Dictionary = parsed[&"value"]
var touched := _pending_units.duplicate()
for id: String in rates:
if int(rates[id]) > 0:
touched[id] = 0
if touched.size() > MAX_FACILITIES:
return _failure(&"TOO_MANY_FACILITIES")
var closures := minute / MINUTES_PER_DAY - _current_minute / MINUTES_PER_DAY
if _closed_periods.size() + closures > MAX_PERIODS:
return _failure(&"TOO_MANY_PERIODS")
if minute == _current_minute:
return {&"ok": true, &"advanced_minutes": 0, &"closed_periods": []}
var before := _current_minute
var newly_closed: Array[Dictionary] = []
while _current_minute < minute:
var midnight := (_current_minute / MINUTES_PER_DAY + 1) * MINUTES_PER_DAY
var until := mini(midnight, minute)
var elapsed := until - _current_minute
for id: String in rates:
var rate := int(rates[id])
if rate > 0:
_pending_units[id] = int(_pending_units.get(id, 0)) + rate * elapsed
_current_minute = until
if until == midnight:
var closed := {
&"period_start": _period_start,
&"period_end": until,
&"facility_units": _canonical_units(_pending_units),
}
_closed_periods.append(closed)
newly_closed.append(closed.duplicate(true))
_pending_units = {}
_period_start = until
return {&"ok": true, &"advanced_minutes": minute - before, &"closed_periods": newly_closed}
func get_unsettled_units(facility_id: StringName, settled_periods: int) -> int:
var id := String(facility_id)
var units := int(_pending_units.get(id, 0))
for index in range(clampi(settled_periods, 0, _closed_periods.size()), _closed_periods.size()):
units += int(_closed_periods[index][&"facility_units"].get(id, 0))
return units
func get_closed_periods_from(index: int) -> Array:
return _closed_periods.slice(clampi(index, 0, _closed_periods.size())).duplicate(true)
func get_report() -> Dictionary:
return {
&"current_minute": _current_minute,
&"period_start": _period_start,
&"gold_denominator": MINUTES_PER_DAY,
&"pending_facility_units": _canonical_units(_pending_units),
&"closed_periods": _closed_periods.duplicate(true),
}
func create_snapshot() -> Dictionary:
return {
&"version": SNAPSHOT_VERSION,
&"started_at": _started_at,
&"current_minute": _current_minute,
&"period_start": _period_start,
&"pending_units": _canonical_units(_pending_units),
&"closed_periods": _closed_periods.duplicate(true),
}
func restore_snapshot(source: Dictionary) -> bool:
# Parse and cross-check the complete candidate before mutating live state.
if not _exact_keys(source, ["version", "started_at", "current_minute", "period_start", "pending_units", "closed_periods"]):
return false
for key: String in ["version", "started_at", "current_minute", "period_start"]:
if typeof(source[key]) != TYPE_INT:
return false
if source["version"] != SNAPSHOT_VERSION or not source["closed_periods"] is Array:
return false
var started := int(source["started_at"])
var current := int(source["current_minute"])
var period_start := int(source["period_start"])
var raw_periods: Array = source["closed_periods"]
if raw_periods.size() > MAX_PERIODS:
return false
if started == -1:
if current != -1 or period_start != -1 or not raw_periods.is_empty() \
or not source["pending_units"] is Dictionary or not source["pending_units"].is_empty():
return false
elif started < 0 or current < started or current > MAX_MINUTE \
or period_start < started or period_start > current \
or period_start / MINUTES_PER_DAY != current / MINUTES_PER_DAY:
return false
var periods: Array[Dictionary] = []
var expected_start := started
for raw: Variant in raw_periods:
if not raw is Dictionary or not _exact_keys(raw, ["period_start", "period_end", "facility_units"]):
return false
if typeof(raw["period_start"]) != TYPE_INT or typeof(raw["period_end"]) != TYPE_INT:
return false
var end := int(raw["period_end"])
if raw["period_start"] != expected_start or end > current \
or end != (expected_start / MINUTES_PER_DAY + 1) * MINUTES_PER_DAY:
return false
var units := _parse_units(raw["facility_units"], MAX_DAILY_RATE * (end - expected_start), false)
if not units[&"ok"]:
return false
periods.append({&"period_start": expected_start, &"period_end": end, &"facility_units": units[&"value"]})
expected_start = end
if expected_start != period_start:
return false
var pending := _parse_units(source["pending_units"], MAX_DAILY_RATE * maxi(current - period_start, 0), false)
if not pending[&"ok"]:
return false
_started_at = started
_current_minute = current
_period_start = period_start
_pending_units = pending[&"value"]
_closed_periods = periods
return true
static func _parse_units(value: Variant, maximum: int, allow_zero := true) -> Dictionary:
if not value is Dictionary or value.size() > MAX_FACILITIES:
return {&"ok": false}
var result: Dictionary = {}
for raw_id: Variant in value:
if typeof(raw_id) not in [TYPE_STRING, TYPE_STRING_NAME]:
return {&"ok": false}
var id := String(raw_id)
if id.is_empty() or id.length() > 128 or result.has(id):
return {&"ok": false}
var amount: Variant = value[raw_id]
if typeof(amount) != TYPE_INT or amount < (0 if allow_zero else 1) or amount > maximum:
return {&"ok": false}
result[id] = amount
return {&"ok": true, &"value": _canonical_units(result)}
static func _canonical_units(source: Dictionary) -> Dictionary:
var keys := source.keys()
keys.sort()
var result: Dictionary = {}
for key: Variant in keys:
result[String(key)] = source[key]
return result
static func _exact_keys(value: Dictionary, expected: Array) -> bool:
if value.size() != expected.size():
return false
for key: Variant in value:
if typeof(key) not in [TYPE_STRING, TYPE_STRING_NAME] or String(key) not in expected:
return false
for key: String in expected:
if not value.has(key):
return false
return true
static func _failure(reason: StringName) -> Dictionary:
return {&"ok": false, &"reason": reason}
@@ -0,0 +1 @@
uid://df3eypvgf3f2v
@@ -0,0 +1,252 @@
class_name FacilityUpkeepSettlement
extends RefCounted
## Settles exact accrued upkeep against the existing balanced ledger.
## Whole gold is recognized as expense even when cash is insufficient. Sub-gold
## fractions carry forward; arrears survive the removal of the owning facility.
## The caller publishes the returned transaction notification after committing
## its wider Runtime transaction (as with payroll).
const Accrual = preload("res://scripts/economy/facility_upkeep_accrual.gd")
const VERSION := 1
const CASH: StringName = &"PLAYER_CASH"
const EXPENSE: StringName = &"MAINTENANCE_EXPENSE"
const PAYABLE: StringName = &"MAINTENANCE_PAYABLE"
var _receipts: Array[Dictionary] = []
var _arrears: Dictionary = {}
var _fractions: Dictionary = {}
static func prepare_accounts(economy: EconomyService) -> bool:
if economy == null or not economy.has_account(CASH):
return false
# Reject incompatible accounts before registering anything.
if economy.has_account(EXPENSE) and economy.account_allows_negative(EXPENSE):
return false
if economy.has_account(PAYABLE) and not economy.account_allows_negative(PAYABLE):
return false
if not economy.has_account(EXPENSE):
economy.register_account(EXPENSE)
if not economy.has_account(PAYABLE):
economy.register_account(PAYABLE, true)
return true
func settle(period: Dictionary, economy: EconomyService) -> Dictionary:
var canonical := _parse_period(period)
if canonical.is_empty():
return _failure(&"INVALID_PERIOD")
for saved: Dictionary in _receipts:
if saved.period.period_end == canonical.period_end:
if saved.period != canonical or not validate_ledger(economy):
return _failure(&"REPLAY_MISMATCH")
return {&"ok": true, &"replayed": true, &"receipt": saved.duplicate(true), &"transaction_id": &""}
if not _receipts.is_empty() and canonical.period_start != _receipts[-1].period.period_end:
return _failure(&"PERIOD_GAP_OR_REWIND")
if _receipts.size() >= Accrual.MAX_PERIODS:
return _failure(&"TOO_MANY_PERIODS")
if not validate_ledger(economy):
return _failure(&"LEDGER_MISMATCH")
var plan := _plan(canonical, economy.get_balance(CASH))
if not plan[&"ok"]:
return plan
var entries: Array = _entries(canonical, plan.rows)
var transaction_id: StringName = &""
if not entries.is_empty():
var result := economy.post(entries, StringName("upkeep.period.%d" % int(canonical.period_end)), &"", false)
if not result.is_success():
return _failure(&"LEDGER_POST_FAILED")
transaction_id = StringName(result.details[&"transaction_id"])
# No fallible mutation follows the single, atomic ledger post.
_arrears = plan.arrears
_fractions = plan.fractions
var receipt := {&"period": canonical, &"rows": plan.rows, &"transaction_id": String(transaction_id)}
_receipts.append(receipt)
return {&"ok": true, &"replayed": false, &"receipt": receipt.duplicate(true), &"transaction_id": transaction_id}
func get_arrears_through(minute: int) -> int:
var low := 0
var high := _receipts.size()
while low < high:
var middle := (low + high) / 2
if int(_receipts[middle][&"period"][&"period_end"]) <= minute:
low = middle + 1
else:
high = middle
if low == 0:
return 0
var amount := 0
for row: Dictionary in _receipts[low - 1][&"rows"]:
amount += int(row[&"arrears"])
return amount
func get_facility_balance(facility_id: StringName) -> Dictionary:
var id := String(facility_id)
return {&"arrears": int(_arrears.get(id, 0)), &"fraction_units": int(_fractions.get(id, 0))}
func get_settled_period_count() -> int:
return _receipts.size()
func get_arrears_total() -> int:
var debt := 0
for amount: int in _arrears.values():
debt += amount
return debt
func get_report() -> Dictionary:
return {&"arrears_total": get_arrears_total(), &"arrears_by_facility": _arrears.duplicate(),
&"fraction_units": _fractions.duplicate(), &"gold_denominator": Accrual.MINUTES_PER_DAY,
&"receipts": _receipts.duplicate(true)}
func create_snapshot() -> Dictionary:
# Derived balances are reconstructed, not trusted from the save file.
return {&"version": VERSION, &"receipts": _receipts.duplicate(true)}
func restore_snapshot(source: Dictionary, economy: EconomyService) -> bool:
if not Accrual._exact_keys(source, ["version", "receipts"]) \
or typeof(source["version"]) != TYPE_INT or source["version"] != VERSION \
or not source["receipts"] is Array or source["receipts"].size() > Accrual.MAX_PERIODS:
return false
var candidate := FacilityUpkeepSettlement.new()
for raw: Variant in source["receipts"]:
if not raw is Dictionary or not Accrual._exact_keys(raw, ["period", "rows", "transaction_id"]) \
or not raw["period"] is Dictionary or not raw["rows"] is Array \
or typeof(raw["transaction_id"]) not in [TYPE_STRING, TYPE_STRING_NAME]:
return false
var period := _parse_period(raw["period"])
if period.is_empty() or (not candidate._receipts.is_empty() \
and period.period_start != candidate._receipts[-1].period.period_end):
return false
var budget := 0
for row: Variant in raw["rows"]:
if not row is Dictionary or not Accrual._exact_keys(row, ["facility_id", "new_expense", "paid", "arrears", "fraction_units"]) \
or typeof(row["facility_id"]) not in [TYPE_STRING, TYPE_STRING_NAME]:
return false
for field: String in ["new_expense", "paid", "arrears", "fraction_units"]:
if typeof(row[field]) != TYPE_INT or row[field] < 0 or row[field] > 9000000000000000:
return false
if budget > 9000000000000000 - int(row["paid"]):
return false
budget += int(row["paid"])
var plan := candidate._plan(period, budget)
if not plan[&"ok"] or plan.rows != raw["rows"]:
return false
candidate._arrears = plan.arrears
candidate._fractions = plan.fractions
candidate._receipts.append({&"period": period, &"rows": plan.rows, &"transaction_id": String(raw["transaction_id"])})
if not candidate.validate_ledger(economy):
return false
_receipts = candidate._receipts
_arrears = candidate._arrears
_fractions = candidate._fractions
return true
func validate_ledger(economy: EconomyService) -> bool:
if economy == null or not economy.has_account(CASH) or not economy.has_account(EXPENSE) \
or not economy.has_account(PAYABLE) or economy.account_allows_negative(EXPENSE) \
or not economy.account_allows_negative(PAYABLE):
return false
var expected_expense := 0
var expected_debt := 0
var owned_transactions: Dictionary = {}
for receipt: Dictionary in _receipts:
var expected: Array = _entries(receipt.period, receipt.rows)
var transaction := StringName(receipt.transaction_id)
if economy.get_transaction_id_for_idempotency_key(StringName("upkeep.period.%d" % int(receipt.period.period_end))) != transaction:
return false
if expected.is_empty():
if not transaction.is_empty():
return false
continue
if transaction.is_empty() or owned_transactions.has(transaction):
return false
owned_transactions[transaction] = true
var actual := economy.get_transaction_entries(transaction)
if actual.size() != expected.size():
return false
for i in range(expected.size()):
var a: LedgerEntry = actual[i]
var e: LedgerEntry = expected[i]
if a.amount != e.amount or a.absolute_minute != e.absolute_minute or a.category != e.category \
or a.debit_account != e.debit_account or a.credit_account != e.credit_account \
or a.source_entity_id != e.source_entity_id or a.memo_key != e.memo_key \
or not a.related_transaction_id.is_empty():
return false
for row: Dictionary in receipt.rows:
expected_expense += int(row.new_expense)
for value: int in _arrears.values():
expected_debt += value
for entry: LedgerEntry in economy.get_entries():
if entry.debit_account in [EXPENSE, PAYABLE] or entry.credit_account in [EXPENSE, PAYABLE]:
if not owned_transactions.has(entry.transaction_id):
return false
return economy.get_balance(EXPENSE) == expected_expense and economy.get_balance(PAYABLE) == -expected_debt
func _plan(period: Dictionary, cash: int) -> Dictionary:
if cash < 0:
return _failure(&"INVALID_CASH")
var ids: Dictionary = {}
for source: Dictionary in [_arrears, _fractions, period.facility_units]:
for id: String in source:
ids[id] = true
if ids.size() > Accrual.MAX_FACILITIES:
return _failure(&"TOO_MANY_FACILITIES")
var ordered := ids.keys()
ordered.sort()
var rows: Array[Dictionary] = []
var arrears: Dictionary = {}
var fractions: Dictionary = {}
for id: String in ordered:
var units := int(period.facility_units.get(id, 0)) + int(_fractions.get(id, 0))
var expense := units / Accrual.MINUTES_PER_DAY
var fraction := units % Accrual.MINUTES_PER_DAY
var debt := int(_arrears.get(id, 0)) + expense
var paid := mini(debt, cash)
cash -= paid
if debt > paid:
arrears[id] = debt - paid
if fraction > 0:
fractions[id] = fraction
rows.append({&"facility_id": id, &"new_expense": expense, &"paid": paid,
&"arrears": debt - paid, &"fraction_units": fraction})
return {&"ok": true, &"rows": rows, &"arrears": arrears, &"fractions": fractions}
static func _parse_period(source: Dictionary) -> Dictionary:
if not Accrual._exact_keys(source, ["period_start", "period_end", "facility_units"]) \
or typeof(source["period_start"]) != TYPE_INT or typeof(source["period_end"]) != TYPE_INT:
return {}
var start := int(source["period_start"])
var end := int(source["period_end"])
if start < 0 or end > Accrual.MAX_MINUTE or end != (start / 1440 + 1) * 1440:
return {}
var units := Accrual._parse_units(source["facility_units"], Accrual.MAX_DAILY_RATE * (end - start), false)
if not units[&"ok"]:
return {}
return {&"period_start": start, &"period_end": end, &"facility_units": units[&"value"]}
static func _entries(period: Dictionary, rows: Array) -> Array:
var entries: Array = []
for row: Dictionary in rows:
var id := StringName(row.facility_id)
if int(row.new_expense) > 0:
entries.append(LedgerEntry.new().configure(&"", int(period.period_end) - 1,
EXPENSE, PAYABLE, int(row.new_expense), &"MAINTENANCE_ACCRUAL", id, &"", &"facility.upkeep.accrued"))
if int(row.paid) > 0:
entries.append(LedgerEntry.new().configure(&"", int(period.period_end),
PAYABLE, CASH, int(row.paid), &"MAINTENANCE_PAYMENT", id, &"", &"facility.upkeep.paid"))
return entries
static func _failure(reason: StringName) -> Dictionary:
return {&"ok": false, &"reason": reason}
@@ -0,0 +1 @@
uid://b3e5slv6c8nb4