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
+1 -1
View File
@@ -197,7 +197,7 @@ func create_snapshot() -> Dictionary:
processed_data.append(result.to_dictionary())
var idempotency_data := {}
var idempotency_keys: Array = _idempotency_to_command_id.keys()
idempotency_keys.sort()
idempotency_keys.sort_custom(func(a: Variant, b: Variant) -> bool: return String(a) < String(b))
for key: Variant in idempotency_keys:
idempotency_data[String(key)] = int(_idempotency_to_command_id[key])
return {
+6
View File
@@ -371,9 +371,15 @@ func _validate_facility(definition: FacilityDefinition, requested_path: String)
if definition.staff_min < 0 or definition.staff_max < definition.staff_min:
_add_error(&"value_out_of_range", facility_id, requested_path, &"staff_min", "Staff limits are inconsistent.")
valid = false
if definition.customer_capacity < -1 or definition.service_attribute not in [&"", &"appetite", &"relaxation", &"sexual", &"gambling"]:
_add_error(&"value_out_of_range", facility_id, requested_path, &"customer_capacity", "Customer capacity or service attribute is invalid.")
valid = false
if definition.capacity < 0 or definition.queue_capacity < 0:
_add_error(&"value_out_of_range", facility_id, requested_path, &"capacity", "Service and queue capacities cannot be negative.")
valid = false
if definition.faith_per_service < 0:
_add_error(&"invalid_service_reward", facility_id, requested_path, &"faith_per_service", "Service Faith must be non-negative.")
valid = false
if definition.base_service_minutes <= 0 or definition.base_price < 0:
_add_error(&"value_out_of_range", facility_id, requested_path, &"base_service_minutes", "Service duration must be positive and price cannot be negative.")
valid = false
+12 -7
View File
@@ -8,6 +8,8 @@ const MAX_BATCH_SIZE := 4_096
var _subscribers: Dictionary = {}
var _published_ids: Dictionary = {}
var _snapshot_ids: Array[String] = []
var _snapshot_ids_dirty := true
var _recent_events: Array[SimulationDomainEvent] = []
var _pending_deliveries: Array[SimulationDomainEvent] = []
var _delivery_active := false
@@ -49,6 +51,8 @@ func publish_batch(events: Array) -> bool:
return false
batch_ids[event.event_id] = true
committed.append(event.copy())
if not committed.is_empty():
_snapshot_ids_dirty = true
for event: SimulationDomainEvent in committed:
_published_ids[event.event_id] = true
_recent_events.append(event.copy())
@@ -90,13 +94,13 @@ func recent_events() -> Array[SimulationDomainEvent]:
return result
func create_snapshot() -> Dictionary:
var published_ids: Array = _published_ids.keys()
published_ids.sort_custom(func(left: Variant, right: Variant) -> bool:
return String(left) < String(right)
)
var saved_ids: Array[String] = []
for event_id: Variant in published_ids:
saved_ids.append(String(event_id))
if _snapshot_ids_dirty:
_snapshot_ids.clear()
for event_id: Variant in _published_ids:
_snapshot_ids.append(String(event_id))
_snapshot_ids.sort()
_snapshot_ids_dirty = false
var saved_ids: Array[String] = _snapshot_ids.duplicate()
var saved_recent: Array[Dictionary] = []
for event in _recent_events:
saved_recent.append(event.to_dictionary())
@@ -131,6 +135,7 @@ func restore_snapshot(snapshot: Dictionary) -> bool:
if restored_recent.size() > RECENT_EVENT_LIMIT:
return false
_published_ids = restored_ids
_snapshot_ids_dirty = true
_recent_events = restored_recent
_pending_deliveries.clear()
return true
+3 -3
View File
@@ -16,7 +16,7 @@ const DEFAULT_SAMPLE_CAPACITY := 512
const DEFAULT_BUDGETS := {
&"simulation_x1": {&"aggregation": Aggregation.AVERAGE, &"limit_us": 4_000},
&"simulation_x4": {&"aggregation": Aggregation.P95, &"limit_us": 12_000},
&"simulation_x3": {&"aggregation": Aggregation.P95, &"limit_us": 12_000},
&"path_query": {&"aggregation": Aggregation.P95, &"limit_us": 2_000},
&"main_thread_stall": {&"aggregation": Aggregation.MAXIMUM, &"limit_us": 50_000},
&"save": {&"aggregation": Aggregation.MAXIMUM, &"limit_us": 5_000_000},
@@ -71,12 +71,12 @@ func record_sample(metric_id: StringName, duration_us: int) -> Dictionary:
func record_simulation_tick(duration_us: int, speed: int) -> Dictionary:
var metric_id := &"simulation_x4" if speed == 4 else &"simulation_x1"
var metric_id := &"simulation_x3" if speed == 3 else &"simulation_x1"
return record_sample(metric_id, duration_us)
## Records the full main-thread cost of one rendered/process frame, including
## all game-minute ticks consumed at accelerated speed. This keeps x4 from
## all game-minute ticks consumed at accelerated speed. This keeps x3 from
## accidentally reporting four individually-fast ticks while the frame stalls.
func record_simulation_frame(duration_us: int, speed: int, ticks_run: int) -> Dictionary:
if ticks_run <= 0:
+31 -4
View File
@@ -367,12 +367,27 @@ static func migrate_save(
return _complete_timed_operation(result, &"save", started_at_us)
## Domain migrations keep the package format version but still require the
## same checksum-verified backup and atomic promotion as format migrations.
## The caller validates domain invariants before supplying the candidate.
static func replace_snapshot_with_backup(save_path: String, expected: Dictionary, candidate: Dictionary) -> Dictionary:
if expected.is_empty() or candidate.is_empty():
return _failure(&"MIGRATION_SNAPSHOT_REQUIRED", save_path)
var validation := SimulationSnapshot.validate(candidate)
if not validation[&"ok"]:
return _failure(&"MIGRATION_INVALID_SNAPSHOT", ", ".join(validation[&"errors"]))
var started := Time.get_ticks_usec()
return _complete_timed_operation(_migrate_save_impl(save_path, null, FORMAT_VERSION, expected, candidate), &"save", started)
static func _migrate_save_impl(
save_path: String,
registry: SaveMigrationRegistry,
target_version: int
target_version: int,
expected_snapshot: Dictionary = {},
replacement_snapshot: Dictionary = {}
) -> Dictionary:
if registry == null:
if registry == null and replacement_snapshot.is_empty():
return _failure(&"MIGRATION_REGISTRY_REQUIRED", save_path)
var resolved := _resolve_safe_save_path(save_path)
if not resolved[&"ok"]:
@@ -410,7 +425,14 @@ static func _migrate_save_impl(
var from_version := int(source[&"manifest"].get("format_version", -1))
if target_version < from_version:
return _failure(&"MIGRATION_DOWNGRADE_UNSUPPORTED", "%d -> %d" % [from_version, target_version])
if target_version == from_version:
if not replacement_snapshot.is_empty():
if from_version != target_version:
return _failure(&"FORMAT_MIGRATION_REQUIRED", save_path)
if source[&"snapshot"] == replacement_snapshot:
return {&"ok": true, &"code": &"ALREADY_CURRENT", &"backup_created": false, &"path": save_path}
if source[&"snapshot"] != expected_snapshot:
return _failure(&"MIGRATION_SOURCE_CHANGED", save_path)
if target_version == from_version and replacement_snapshot.is_empty():
var current_validation := SimulationSnapshot.validate(source[&"snapshot"])
if target_version == FORMAT_VERSION and not current_validation[&"ok"]:
return _failure(&"INVALID_SNAPSHOT", ", ".join(current_validation[&"errors"]))
@@ -427,7 +449,12 @@ static func _migrate_save_impl(
&"manifest": source[&"manifest"].duplicate(true),
&"snapshot": source[&"snapshot"].duplicate(true),
}
var migrated := registry.migrate(payload, from_version, target_version)
var migrated: Dictionary
if replacement_snapshot.is_empty():
migrated = registry.migrate(payload, from_version, target_version)
else:
payload[&"snapshot"] = replacement_snapshot.duplicate(true)
migrated = {&"ok": true, &"data": payload, &"applied_migration_ids": [&"domain_snapshot_replacement"]}
if not migrated[&"ok"]:
return _with_context(migrated, {
&"path": save_path,
+24 -3
View File
@@ -22,6 +22,10 @@ class KeyLayouts:
extends RefCounted
var strings: Dictionary = {}
var names: Dictionary = {}
# Bounded per-call immutable scalar encodings; never retain mutable containers.
var integers: Dictionary = {}
var text_values: Dictionary = {}
var name_values: Dictionary = {}
@@ -56,14 +60,19 @@ static func _encode_value(value: Variant, output: PackedByteArray, depth: int, l
TYPE_BOOL:
_append_ascii(output, "b1" if bool(value) else "b0")
TYPE_INT:
_append_ascii(output, "i%d;" % int(value))
if layouts.integers.has(value):
output.append_array(layouts.integers[value])
else:
var encoded := ("i%d;" % int(value)).to_utf8_buffer()
output.append_array(encoded)
if layouts.integers.size() < 512: layouts.integers[value] = encoded
TYPE_FLOAT:
_append_ascii(output, "f")
return _append_float64(output, float(value))
TYPE_STRING:
_append_sized_bytes(output, "s", String(value).to_utf8_buffer())
_append_cached_text(output, "s", String(value), layouts.text_values)
TYPE_STRING_NAME:
_append_sized_bytes(output, "q", String(value).to_utf8_buffer())
_append_cached_text(output, "q", String(value), layouts.name_values)
TYPE_VECTOR2:
var vector: Vector2 = value
_append_ascii(output, "v2")
@@ -290,3 +299,15 @@ static func _append_sized_bytes(output: PackedByteArray, tag: String, value: Pac
static func _append_ascii(output: PackedByteArray, value: String) -> void:
output.append_array(value.to_utf8_buffer())
static func _append_cached_text(output: PackedByteArray, tag: String, value: String, cache: Dictionary) -> void:
if cache.has(value):
output.append_array(cache[value])
return
var bytes := value.to_utf8_buffer()
var encoded := ("%s%d:" % [tag, bytes.size()]).to_utf8_buffer()
encoded.append_array(bytes)
output.append_array(encoded)
if value.length() <= 128 and cache.size() < 256:
cache[value] = encoded
+6 -3
View File
@@ -25,7 +25,7 @@ enum TickPhase {
const MINUTES_PER_DAY := 24 * 60
const START_ABSOLUTE_MINUTE := 6 * 60
const REAL_SECONDS_PER_GAME_HOUR := 30.0
const REAL_SECONDS_PER_GAME_HOUR := 10.0
const REAL_SECONDS_PER_GAME_MINUTE := REAL_SECONDS_PER_GAME_HOUR / 60.0
const MAX_TICKS_PER_FRAME := 8
const MAX_BACKLOG_MINUTES := 120
@@ -160,7 +160,7 @@ func request_current_tick_abort() -> void:
_abort_current_tick_requested = true
func set_speed(value: int) -> bool:
if value not in [1, 2, 4]:
if value not in [1, 2, 3]:
return false
speed = value
paused = false
@@ -218,7 +218,10 @@ func restore_clock(snapshot: Dictionary) -> bool:
if not snapshot.has(&"absolute_minute"):
return false
var restored_speed := int(snapshot.get(&"speed", 1))
if restored_speed not in [1, 2, 4]:
# Legacy x4 saves resume at the original specification maximum, x3.
if restored_speed == 4:
restored_speed = 3
if restored_speed not in [1, 2, 3]:
return false
absolute_minute = maxi(int(snapshot[&"absolute_minute"]), 0)
speed = restored_speed
+1 -1
View File
@@ -23,7 +23,7 @@ static func validate(snapshot: Dictionary) -> Dictionary:
var clock_data: Dictionary = snapshot[&"clock"]
if int(clock_data.get(&"absolute_minute", -1)) < 0:
errors.append("invalid_absolute_minute")
if int(clock_data.get(&"speed", 0)) not in [1, 2, 4]:
if int(clock_data.get(&"speed", 0)) not in [1, 2, 3, 4]:
errors.append("invalid_speed")
if not snapshot.get(&"game_state", null) is Dictionary:
errors.append("missing_game_state")