Skip to content

Batch 45 · R2i production config ownership

2026-10-26, dev-0.9.0-bootloader, starting HEAD e3e17767. Implementation 248f4049 contains nine modified paths and four additions; documentation/evidence follows separately. No push, normal-profile write or player build.

Production boundary

Previously SaveManager saved the entire typed GameConfig through the generic writer, discarding fields that GameConfig does not represent. SaveManager now owns ConfigSettingsOwner/ConfigFileStore at the existing Game.Save.SavePath(CONFIG_FILE), with the pinned action definition referenced by Bootloader. No new identity/environment/path discovery or directory creation is introduced. The path stays pinned for the owner's lifetime. SaveService.WriteNew blocks config and normalized relative/absolute aliases; ordinary other-file writes remain supported. Arbitrary filesystem writers/symlink aliases are outside that guard.

The legacy Config object remains the mutable caller view. An immutable full document retains unknown root/nested/record data, precise untouched values and remaps; a snapshot tracks staged fields. Explicit settings saves patch known fields and validated compatibility choices. Unknown-record edits, list membership/order changes and invalid values reject before publication. The existing public settings controls keep their targets and mappings. GameSettings preset controls now send explicit expected/selected intent through SaveControlPreset, including same-number P1 reselection when the new keyboard preference differs. P2 keyboard stays compatibility data, not a new assignment. No player/input polling, movement or balance change.

Existing/legacy file loads prepare input import in memory without saving. Missing files explicitly initialize/save defaults. Incomplete required graphics/presets, invalid/future data and read failures do not become writable defaults. Startup clears readiness before work, and config failure prevents its ready notification. Player/progression methods and their startup order remain unchanged: player handling still occurs before config loading. Their complete migration/recovery is outside this batch.

Saved/NoChanges complete normally. Failed/Conflict/Indeterminate/NotWritable throw ConfigWriteException carrying the structured outcome and recovery path; SaveManager exposes LastConfigWrite and HasPendingConfigChanges. Staged state survives failure. Advancing the staged snapshot prevents retry replaying a stale preset expectation; later caller-view edits during IO remain pending. There is no rollback of already-applied runtime or typed values and no success notification on failed publication. Owner DiscardAndReload is explicit; no completed SaveManager recovery command/screen exists. Backup retention/stale locks and user feedback remain open; backups currently accumulate. Active production wiring is not a normal-profile or release acceptance claim.

Executed evidence

Required Editor Unity 6000.2.8f1, revision c9992ac36c34; Input System 1.17.0, Both handling. Direct -batchmode -nographics -tinyChaosTrace, explicit project/private-log paths, runner-owned exit and no immediate -quit.

Initial ConfigOwnerChecks run: 9/10, exit1. CO04 expected a generic InvalidOperationException; the implementation correctly returned ConfigWriteException with NotWritable and preserved the file. After correcting that expectation, the next 9/10, exit1 exposed another fixture error: it set an unknown version extension instead of the actual inputSchemaVersion, so the supported file was correctly accepted. The fixture now modifies the actual schema field. These were test expectation/data errors, not reproduced runtime data loss. A legacy-no-wrapper case and exact decimal-retention assertion were also added before final verification.

Final 44 groups pass across five Editor processes, all exit0: ConfigOwnerChecks.RunBatch45 10/10, SettingsCompatibilityChecks.RunBatch43 10/10, LoadedSettingsChecks.RunBatch44 8/8, StabilizationChecks.RunBatch23 7/7, RunBatch24 9/9. Existing fixtures attach the owner to an unused disposable path/in-memory initial view instead of relying on the retired typed config writer. The audio/locale failure fixture now injects a write-lock failure because changing Game.Save no longer retargets an already-owned config path. Assertions were retained, not weakened.

Group Final actual result
CO01 PASS: the one production Bootloader SaveManager resolves the actual pinned imported action asset, GUID and file ID.
CO02 PASS: actual full/legacy config loads and repeated loads do not write; explicit scalar/graphics patches retain remaps, record/root/nested extensions, an exact untouched decimal and byte-exact backup; no-change save creates no extra publication; reload retains edits.
CO03 PASS: actual missing-file load initializes defaults/input section and saves once; later load sees an existing file without recreating it.
CO04 PASS: empty/truncated/future-schema/missing-preset/missing-graphics/read-failed input stays untouched, does not admit ready settings/defaults and cannot save as a supported config.
CO05 PASS: actual preset commands synchronize P1 layout, preserve custom P3 bindings and extensions, keep P2 keyboard out of layout/assignment changes and honor same-number P1 reselection.
CO06 PASS: injected replacement failure preserves original bytes/dirty preset; ordinary retry plus a later scalar edit saves/reloads both without stale-command replay.
CO07 PASS: external changes produce Conflict without overwrite; error after real publication produces Indeterminate with exact recovery original; blind retry conflicts; explicit owner discard/reload reconciles actual disk.
CO08 PASS: invalid numeric/unknown-record edits and dirty reload reject without publication or false acknowledgement.
CO09 PASS: generic config, relative alias and absolute-path writes reject while another temporary JSON file still writes normally.
CO10 PASS: write-time reentrant owner operations reject, a later view edit stays pending, and mutating the injected resolver cannot retarget the pinned owner or create another directory.

Tests invoke actual SaveManager private load/public save/preset methods through inactive preview fixtures, physical temporary Linux IO and injected faults. Production Bootloader is opened as a preview solely to resolve the imported reference; no Awake/startup handoff runs. No normal SaveService constructor, real player data, migration, network submission or complete StartupAsync was invoked. Readiness failure evidence is the config-path exception plus unchanged false fixture state and the startup control flow; a full startup ready-event test is not claimed. Owner reconciliation checks do not exercise a nonexistent recovery screen/SaveManager discard command.

Prior locale fixtures still manually step the iterator with completed SDK initialization and disposable locales; they do not verify packaged readiness, actual coroutine scheduling or localized rendering. Source/listener values do not prove audible playback. Real Linux Editor replacement/backup success and injected failures do not prove Windows replacement, IL2CPP, power-loss durability, stale-lock recovery or bounded retention. Old noncooperating writers/aliases can still race the filesystem. No complete playthrough, physical-device or full startup claim.

Raw logs/exit records stay private under /tmp/tinychaos-batch45-*: initial editor.log, second editor-fixture2.log, final regression-45/43/44/23/24.log. Known generator/legacy-check and TMP fallback-font warning categories are recorded separately from passing assertions. No raw profile/payload/log is committed. The opt-in bounded trace adds sanitized config load/write status events; it does not solve or attribute GAME-01.

Preservation and coverage

Pre-run capture /tmp/tinychaos-batch45-preserve-4d5e882457/ contains 2,883 project files, 8,172 Unity/profile hashes and recoverable preference bytes. Nine intended prior paths change; 2,874 match exactly. Four of the 69 prior unique rebuild paths are intentionally updated; the other 65 match. New coverage gives 78 unique implementation paths. SaveManager's player/progression methods from LoadNewEncryptedSave onward are byte-identical. Bootloader changes exactly one serialized reference; recovery scenes remain historical/unmigrated. Input definition bytes/action IDs and existing metadata are unchanged.

The immutable selected 608-source baseline CSV retains 604 matching pins. Exceptions are the existing package pair/GameSettings plus SettingsFlowChecks' explicit owner fixture setup. SaveManager/SaveService/Bootloader and other affected files outside this selected pin list are covered by the full pre-batch byte capture, not falsely counted as original pins. Existing CRLF/LF patterns and GUIDs are preserved. Two new metadata GUIDs are unique and have no serialized production references; the Bootloader reference points to the existing action definition. Unresolved audio deletions and Addressables Linux metadata remain excluded.

Unity added only the native Linux toolchain node in manifest/lock; generated copies were archived and captured bytes restored, keeping SDK 1.17.0. Regression checks regenerated TimeManager's fixed-step serialization/line endings; reviewed generated bytes were archived and the captured file restored. Shared preferences differ only in automatic Editor session count/ID keys after locale fixtures restored their key; captured bytes were restored after key-level review. The normal game's one prefs file remains byte-unchanged, with no new normal profile/save/config files. Five external licensing/package/metrics bookkeeping files changed and remain; the whole Unity profile tree is not claimed unchanged.

Inventory covers 258 scripts: eight focused rows amended, 248 earlier rows preserved and two scripts appended. Ten CO gates append to 123 earlier rows (133 total), keeping all 27 workstream follow-ups open. Input consumer membership remains 23 with one migration-note update and 22 unchanged rows; source baseline stays byte-unchanged. All 53 findings still route once and 844 local documentation links resolve. Source paths match tested hashes; whitespace checks pass. ARCH-01/SAVE-05 remain open pending their wider acceptance.

Exact implementation manifest

Path Kind SHA-256
Assets/Script/App/Core/SaveManager.cs production config ownership f14ed81999e6e29f4e51405ab2869000766680ee0ec4f7cd3fe6a1f097e29cde
Assets/Script/TinyChaos/Services/Save/SaveService.cs production config ownership 8d4d96807c242562a22574f2a78810041b21ca93b7521ccaeb159e1d839dba38
Assets/Scenes/Bootloader.unity production composition binding 53ebbdc3ea47c78375576f1705f13562070168d93c08d748c253109f83c1f79f
Assets/Script/External/Editor/SettingsFlowChecks.cs Editor integration/regression fixture 6063ff99a092685c5d93125e37cf72b8ac3085751a0613e57a43e33ce1945237
Assets/Script/External/Editor/SettingsCompatibilityChecks.cs Editor integration/regression fixture 7837ebba280be4ed70db34cc26d55532fb1eafd350ac1b47214dfa623c508991
Assets/Script/External/Editor/LoadedSettingsChecks.cs Editor integration/regression fixture a7c50bf583481b5be489fedd0b5217468d07602777734ac70b95c50bef331d9c
Assets/Script/External/Editor/GraphicsStartupChecks.cs Editor integration/regression fixture aba550cc4361e6f770ad3bc8753b279712c016dc3f29cc1f1609b390b101cc02
Assets/Script/TinyChaos/Services/Save/ConfigFileStore.cs production config ownership 97ebb7961711008344fe394083431cd2772baea044189b633789cc1ac3ffb8e7
Assets/Script/App/Core/GameSettings.cs production config ownership 30eea1d664a1b466e6d42411e7e8e8520fe26499f56e6b5477d058fb33b9a7db
Assets/Script/TinyChaos/Services/Save/ConfigSettingsOwner.cs production config ownership b9039232fdd394406e831f6d6c1c0f1fc5a29e86d8e343e69ad2a2b832c921fb
Assets/Script/External/Editor/ConfigOwnerChecks.cs Editor integration/regression fixture fca09551cf6cdee991e2360a7ff2c3414cfa0575cca2190351f26e37da52ffb9
Assets/Script/TinyChaos/Services/Save/ConfigSettingsOwner.cs.meta metadata 7176f58ded15324afe9a3422eea6a1e9d259a490b70f7f8c986e7dab6ca0bd8d
Assets/Script/External/Editor/ConfigOwnerChecks.cs.meta metadata 5dbb60d5bae14128ae1a4cf3764b2fbabcc9c84bcff624b1b79177c6355be217

Next and commit boundary

Next build and probe a Linux player using explicitly isolated fresh/current/legacy profile paths, real startup and a deliberate setting edit/restart/reload. Confirm build dependencies and locale/audio handoff before setup/remap UI. Record incidental startup stalls without resuming the dedicated GAME-01 investigation. Recovery feedback, stale-lock/backup-retention policy, Windows and normal-profile acceptance remain open. No new unrelated feature, Tutorial completion, player/AbilityHolder migration or released-stage loading is included here.

Implementation 248f4049 precedes separate documentation/evidence. No push. This is one completed wiring batch; R2/F1 and gameplay rebuild completion remain unfinished.