Skip to content

Single-writer storage model: durability fixes + topology guidance#83

Merged
cuibonobo merged 1 commit into
mainfrom
claude/issue-45-design-review-1jgkcj
Jul 10, 2026
Merged

Single-writer storage model: durability fixes + topology guidance#83
cuibonobo merged 1 commit into
mainfrom
claude/issue-45-design-review-1jgkcj

Conversation

@cuibonobo

Copy link
Copy Markdown
Member

Summary

Implements the spec/README/durability items from #45 (items 1–4). Item 5 (write-amplification / debounced persist) is intentionally left out — it's explicitly a follow-up in #45, and gets subsumed by #46's native-SQLite adapter work.

  • docs/spec.md: new "Concurrency & storage ownership" section — states the single-writer-per-file rule, why multi-app access must go through a server (permissions/grants/appId attribution only mean anything behind one), and the fail-loudly / atomic-persist guarantees adapters should provide.
  • README.md: replaces the "apps don't know or care where storage lives" framing (which read as an invitation to point multiple apps at one file) with an explicit "How apps share a stack" section, and marks adapter-local as single-app/embedded or server use only in the package tables.
  • record-adapter-sqljs: persist() now writes db.export() to a temp file and rename()s it over the target instead of rewriting in place — rename is atomic on POSIX, so a crash mid-write can no longer leave a torn/unparseable database.
  • record-adapter-sqljs: open()/initialize() acquire a PID-stamped lock file beside the database and reject with a clear error if another live process already holds it; close() releases it. A stale lock (owning process no longer running) is reclaimed automatically via a liveness check; an optional { force: true } covers the PID-reuse edge case. Threaded through adapter-local's initialize()/open() options.

Test plan

  • pnpm typecheck — full monorepo, clean
  • pnpm lint — full monorepo, clean
  • pnpm test — full monorepo, 463 tests passing (no regressions)
  • New tests in record-adapter-sqljs: atomic persist leaves no temp files / db stays valid across multiple persists; lock rejects a live foreign process, reclaims a stale lock, honors force, releases on close(), and allows same-process reopen without force

Refs #45.

https://claude.ai/code/session_01RRLiGUZC344E3pgNEGAe5W


Generated by Claude Code

…ter-local

Addresses #45's spec/README items and the two durability fixes it calls
out as worth doing regardless of the #46 native-adapter follow-up:

- docs/spec.md: new "Concurrency & storage ownership" section stating
  the single-writer rule, why multi-app access must go through a server,
  and the fail-loudly/atomic-persist guarantees adapters should provide.
- README.md: replace the "apps don't know or care where storage lives"
  framing with an explicit "How apps share a stack" section, and mark
  adapter-local as single-app/embedded or server use only.
- record-adapter-sqljs: persist() now writes to a temp file and renames
  it over the target instead of rewriting in place, so a crash mid-write
  can no longer leave a torn database file.
- record-adapter-sqljs: open()/initialize() acquire a PID-stamped lock
  file beside the database and reject with a clear error if another live
  process already holds it; close() releases it. Stale locks (owning
  process no longer running) are reclaimed automatically, and an
  optional { force: true } escapes PID-reuse edge cases. Threaded
  through adapter-local's initialize()/open() options.

Write-amplification reduction (item 5) is left for #46, which replaces
sql.js with a native SQLite adapter and subsumes it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRLiGUZC344E3pgNEGAe5W
@cuibonobo cuibonobo merged commit 41003f4 into main Jul 10, 2026
5 checks passed
@cuibonobo cuibonobo deleted the claude/issue-45-design-review-1jgkcj branch July 10, 2026 17:03
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.

2 participants