Skip to content

Fix: Serialize AppStorage persistence and inject its backend per app#65

Merged
phranck merged 5 commits into
mainfrom
issue/15-appstorage-writer
Jul 22, 2026
Merged

Fix: Serialize AppStorage persistence and inject its backend per app#65
phranck merged 5 commits into
mainfrom
issue/15-appstorage-writer

Conversation

@phranck

@phranck phranck commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Closes #15.

Summary

  • JSONFileStorage captures 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 released
  • synchronize() is now a true barrier that returns only after every previously issued write has completed; the runtime flushes storage this way during cleanup
  • Encode, serialize, and write failures are reported through StoragePersistenceError with sanitized reasons (error domain and code only, never paths or stored content); the default handler logs one line to stderr
  • The deprecated mutable StorageDefaults global is gone: every production runtime owns its own JSONFileStorage, and @AppStorage access outside a runtime falls back to a deliberately volatile process-local backend that never touches the file system
  • API compatibility manifest and review-policy overrides regenerated from fresh Swift 6.0.3 macOS + Linux snapshots
  • State management docs describe the new persistence guarantees

Acceptance criteria from #15

  • No older snapshot can overwrite a newer mutation (ordered writer + snapshot tests)
  • synchronize() is a true barrier for all prior changes (barrier test)
  • Concurrent stress, restart, corruption, and write-failure tests pass on macOS and Linux using only temporary directories
  • Two app runtimes do not share storage backends unless explicitly configured
  • Persistence errors are observable and contain no path/content leakage (leak-assertion tests)
  • Swift 6.0 build, tests, lint, and DocC are warning-free on both platforms (./scripts/test-linux.sh green)

Test plan

  • 1332 tests green on macOS (Swift 6.0.3) and Linux (Docker 6.0.3-noble)
  • New AppStoragePersistenceTests suite: ordering, barrier, restart, corruption, failure reporting, unbound fallback, concurrency stress
  • verify-compatibility-manifest.sh passes against the regenerated manifest

phranck added 5 commits July 22, 2026 10:58
- 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
@phranck
phranck merged commit 0c7dba3 into main Jul 22, 2026
6 checks passed
@phranck
phranck deleted the issue/15-appstorage-writer branch July 22, 2026 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P0-10] Serialize AppStorage persistence and inject its backend per app

1 participant