Fix: Serialize AppStorage persistence and inject its backend per app#65
Merged
Conversation
- Capture an immutable cache snapshot under the lock for every mutation and persist snapshots on one serial writer queue, so an older snapshot can never overwrite a newer mutation - Make synchronize() a true barrier that waits for every previously enqueued write before returning - Keep atomic file replacement and complete pending writes even if the storage instance is released - Add ordering, barrier, restart, corruption, and concurrency stress tests against an injectable persistence step
- Add StoragePersistenceError with sanitized reasons (error domain and code only, never paths or stored content) - Route encode, serialize, and write failures through an injectable handler; the default logs one line to standard error - Cover failing writes, unwritable destinations, and encoding failures with tests asserting the storage path never leaks
- Delete the deprecated mutable StorageDefaults global - Give every production runtime its own JSONFileStorage instance so two runtimes never share a backend unless explicitly injected - Route AppStorage access outside a runtime to a deliberately volatile process-local fallback that never touches the file system
- Drop policy overrides for the removed StorageDefaults global and the replaced JSONFileStorage initializers - Add tuiSpecific overrides for StoragePersistenceError and the new failure-reporting initializers, copied from fresh 6.0.3 snapshots - Regenerate the manifest with TUIkitAPICheck against the assembled macOS and Linux snapshot set
- Document ordered snapshot writes, the synchronize barrier, and sanitized failure reporting in the state management article - Document the volatile fallback for properties accessed outside a runtime
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #15.
Summary
JSONFileStoragecaptures an immutable cache snapshot for every mutation and persists snapshots through one serial writer queue, so an older snapshot can never overwrite a newer mutation; pending writes complete even if the storage instance is releasedsynchronize()is now a true barrier that returns only after every previously issued write has completed; the runtime flushes storage this way during cleanupStoragePersistenceErrorwith sanitized reasons (error domain and code only, never paths or stored content); the default handler logs one line to stderrStorageDefaultsglobal is gone: every production runtime owns its ownJSONFileStorage, and@AppStorageaccess outside a runtime falls back to a deliberately volatile process-local backend that never touches the file systemAcceptance criteria from #15
synchronize()is a true barrier for all prior changes (barrier test)./scripts/test-linux.shgreen)Test plan
AppStoragePersistenceTestssuite: ordering, barrier, restart, corruption, failure reporting, unbound fallback, concurrency stressverify-compatibility-manifest.shpasses against the regenerated manifest