docs: story 33 — single-file store (WO_DATA=<path>.db)
- file path IS the wal; dir form byte-identical; one fork (nonexistent path semantics) leaning recorded; off-chain, driver-only - board + story table rows (held tail seqs bumped) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a8829232dc
commit
b3baf6dd9a
3 changed files with 83 additions and 8 deletions
|
|
@ -242,6 +242,7 @@ that sequences its tasks. Read one, approve, then the next starts.
|
|||
| 24 | [chat: WebSocket workload](language-runtime-database/refine/24-chat-websocket-workload.md) | ⬜ fourth in chain — the arc's acceptance; after 31 |
|
||||
| 23 | [io_uring group-commit](language-runtime-database/refine/23-io-uring-commit.md) | ⬜ fifth in chain, after stage 3 + 22 |
|
||||
| 32 | [WAL checkpoint](language-runtime-database/refine/32-wal-checkpoint.md) | ⬜ last in chain, after 23 — disk reclamation + bounded replay (story written 2026-08-21) |
|
||||
| 33 | [Single-file store](language-runtime-database/refine/33-single-file-db.md) | ⬜ off-chain, small — `WO_DATA=<path>.db` file form; driver-only (story written 2026-08-22) |
|
||||
| 20 | [Cross-program tables](language-runtime-database/hold/20-cross-program-tables.md) | ⏸ hold (2026-08-21); channel done (branch ipc-attach keeps its manifest) |
|
||||
| 21 | [Keypair attach auth](language-runtime-database/hold/21-keypair-attach-auth.md) | ⏸ hold (2026-08-21); crypto+handshake done (branch keypair-auth keeps its manifest) |
|
||||
| 25 | [HTTP service layer](../superpowers/plans/2026-08-01-http-service-layer.md) | ⏸ hold (2026-08-21) — story file removed; the plan doc remains |
|
||||
|
|
|
|||
|
|
@ -107,14 +107,15 @@ still pending IS the runtime-concurrency chain; order:
|
|||
| 18 | 24 | [chat: WebSocket workload](refine/24-chat-websocket-workload.md) | the arc's acceptance: WS upgrade + frames (SHA-1 via crypto fork, Bytes via 19), rooms/broadcast, 1k clients, drain-clean. *(was 19)* |
|
||||
| 19 | 23 | [io_uring group-commit](refine/23-io-uring-commit.md) | WAL WRITE+FSYNC chains on the arc's per-shard rings; fsync fallback kept (after 22 + the arc). *(was 9f)* |
|
||||
| 20 | 32 | [WAL checkpoint](refine/32-wal-checkpoint.md) | **NEW 2026-08-21** (stage-3 guarantee refinement found the hole) — the WAL is append-only forever: snapshot + truncate reclaims disk and bounds replay time; every durability guarantee byte-identical; crash mid-checkpoint recovers from the previous snapshot + full tail. After 23 (composes with group-commit); RAM slot-reuse already contracted in `04-db-binding.md`. |
|
||||
| 21 | 25 | [HTTP service layer](../../superpowers/plans/2026-08-01-http-service-layer.md) | `service` blocks lower onto the framework (after 9b + 20 by their own precedence notes). **HELD 2026-08-21** — story file removed; the plan doc remains. *(was 10)* |
|
||||
| 22 | 18 | [framework v2: memory-rich features](hold/18-memory-db-features.md) | spec+plan approved: TTL cache, @table flags, durable job queue, `transaction { }` over the WAL's staged batch. **Demoted from seq 14**: more surface on a framework with one consumer, and the cache still stores `Text` because there are no generics |
|
||||
| 23 | 27 | [Query grammar corpus](hold/27-query-grammar-corpus.md) | grow the query grammar from real corpora; likely collapses to "confirm `len(query)` + add `exists`"; precedes 28. *(was 9g)* |
|
||||
| 24 | 26 | [Blue-green deploy](hold/26-blue-green-deploy.md) | two VM slots, in-runtime compile, atomic switch, resident rollback (plan authored after 9 + 25). *(was 12)* |
|
||||
| 25 | 20 | [Cross-program tables](hold/20-cross-program-tables.md) | attach to a running program's database over local IPC; owner stays the single writer (channel half-built). **Demoted from seq 16**: new distribution surface while there is no TLS, no crypto, and the multi-shard DB still traps. *(was 9c)* |
|
||||
| 26 | 21 | [Keypair attach auth](hold/21-keypair-attach-auth.md) | program identity is a keypair; mutual challenge–response at attach (crypto half-built; plan folds into 20's). **Demoted with 20** — and it needs crypto primitives that do not exist. *(was 9d)* |
|
||||
| 27 | 28 | [skillhost host workload](hold/28-skillhost-host-workload.md) | host-shaped driving workload naming runtime gaps — demoted with the framework goal. *(was 14)* |
|
||||
| 28 | 29 | [Compile-time metaprogramming](hold/29-compile-time-metaprogramming.md) | `@derive(...)` from class-table metadata; held with the parked drain by the 2026-08-08 scope directive. *(was 13)* |
|
||||
| 21 | 33 | [Single-file store](refine/33-single-file-db.md) | **NEW 2026-08-22** — `WO_DATA=<path>.db`: a file path IS the wal (the store already lives in exactly one file; this makes the surface say so). Driver-only, independent of the chain; composes with 32's rename-swap. |
|
||||
| 22 | 25 | [HTTP service layer](../../superpowers/plans/2026-08-01-http-service-layer.md) | `service` blocks lower onto the framework (after 9b + 20 by their own precedence notes). **HELD 2026-08-21** — story file removed; the plan doc remains. *(was 10)* |
|
||||
| 23 | 18 | [framework v2: memory-rich features](hold/18-memory-db-features.md) | spec+plan approved: TTL cache, @table flags, durable job queue, `transaction { }` over the WAL's staged batch. **Demoted from seq 14**: more surface on a framework with one consumer, and the cache still stores `Text` because there are no generics |
|
||||
| 24 | 27 | [Query grammar corpus](hold/27-query-grammar-corpus.md) | grow the query grammar from real corpora; likely collapses to "confirm `len(query)` + add `exists`"; precedes 28. *(was 9g)* |
|
||||
| 25 | 26 | [Blue-green deploy](hold/26-blue-green-deploy.md) | two VM slots, in-runtime compile, atomic switch, resident rollback (plan authored after 9 + 25). *(was 12)* |
|
||||
| 26 | 20 | [Cross-program tables](hold/20-cross-program-tables.md) | attach to a running program's database over local IPC; owner stays the single writer (channel half-built). **Demoted from seq 16**: new distribution surface while there is no TLS, no crypto, and the multi-shard DB still traps. *(was 9c)* |
|
||||
| 27 | 21 | [Keypair attach auth](hold/21-keypair-attach-auth.md) | program identity is a keypair; mutual challenge–response at attach (crypto half-built; plan folds into 20's). **Demoted with 20** — and it needs crypto primitives that do not exist. *(was 9d)* |
|
||||
| 28 | 28 | [skillhost host workload](hold/28-skillhost-host-workload.md) | host-shaped driving workload naming runtime gaps — demoted with the framework goal. *(was 14)* |
|
||||
| 29 | 29 | [Compile-time metaprogramming](hold/29-compile-time-metaprogramming.md) | `@derive(...)` from class-table metadata; held with the parked drain by the 2026-08-08 scope directive. *(was 13)* |
|
||||
| ✅ | 17 | [library projects + `internal/`](done/17-library-projects-internal.md) | **LANDED 2026-08-20** — `kind = "library"` + entry-less check mode (retires the `--emit` workaround) and Go's `internal/` rule as WO-E108 at the consumer's `use`; driver-only, VM/GC untouched. `just web-app` 26/0 |
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
iteration: "33"
|
||||
status: refine
|
||||
---
|
||||
|
||||
# Iteration 33 — `WO_DATA=<path>.db`: the persistent store as one file
|
||||
|
||||
> Format: `product/story-iteration-template`. Part of
|
||||
> [Story — one language, one runtime, one database, one binary](../00-story.md).
|
||||
>
|
||||
> **Inserted 2026-08-22** (developer ask: "can the persistent db be in
|
||||
> file.db form?"). The truth is already almost there: `WO_DATA=<dir>`
|
||||
> holds exactly ONE file (`shard-0.wal`) — the entire persistent state,
|
||||
> since RAM is authoritative and no data pages exist. This iteration
|
||||
> makes the surface say so: point `WO_DATA` at a file and THAT file is
|
||||
> the store. Small, driver-only, independent of the concurrency chain.
|
||||
|
||||
## Goals
|
||||
|
||||
- **`WO_DATA=<path>` accepts a file path.** A path that is not an
|
||||
existing directory is treated as THE wal file (`app.db`,
|
||||
`store.wo.db` — the name is the operator's). The directory form stays
|
||||
and keeps meaning `<dir>/shard-0.wal` — every existing deployment and
|
||||
gate is byte-identical.
|
||||
- **One file remains the whole truth at any core count** — stage 3 made
|
||||
the WAL owner-shard-only (shard 0 is the sole writer), so nothing
|
||||
multi-shard ever adds a second file.
|
||||
- **The contract says it out loud**: `04-db-binding.md` documents the
|
||||
file form, and documents honestly that the file is an append-only log
|
||||
that grows until iteration 32 lands.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- **Given** `WO_DATA=/tmp/app.db` (no such directory), **when** a
|
||||
program seeds, restarts, and verifies, **then** replay is byte-true
|
||||
and `/tmp/app.db` is the only artifact on disk.
|
||||
- **Given** `WO_DATA=<dir>` (existing directory), **when** the same
|
||||
program runs, **then** behavior is byte-identical to today —
|
||||
`<dir>/shard-0.wal`, every standing gate unchanged.
|
||||
- **Given** the db-bench durability legs pointed at the file form,
|
||||
**when** the restart proof and kill -9 battery run, **then** every
|
||||
guarantee holds identically (the file IS the same WAL, only named by
|
||||
the operator).
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
- A paged database file (SQLite's shape) — RAM is authoritative; the
|
||||
disk story is the WAL, full stop.
|
||||
- Checkpoint/compaction — [iteration 32](32-wal-checkpoint.md)'s; its
|
||||
rename-swap (write snapshot+tail to a NEW file, fsync, `rename()`
|
||||
over the old) is exactly what keeps the single-file promise crash-safe
|
||||
when it lands. 33 before or after 32 works; landing 33 first means
|
||||
32's spec inherits the file form as a stated constraint.
|
||||
- Multiple stores per process, attach-by-file — held iteration 20's
|
||||
territory.
|
||||
|
||||
## Info
|
||||
|
||||
- The whole change is `runtime/src/main.c`'s hardcoded
|
||||
`snprintf("%s/shard-0.wal", dir)` growing a stat-based fork
|
||||
(directory → today's path; otherwise → the path itself), plus a gate
|
||||
check and the binding-doc note. No engine, no WAL format, no
|
||||
compiler.
|
||||
- Fork for the (tiny) spec: what does a NONEXISTENT path mean? Leaning:
|
||||
a path whose parent exists and that does not end in `/` is a file to
|
||||
create; a trailing `/` or existing directory keeps the directory
|
||||
form. Refusing ambiguity loudly (WO exit 2) beats guessing.
|
||||
|
||||
## Proposed Solution
|
||||
|
||||
Small enough for a bounded slice: brainstorm the one fork in chat,
|
||||
implement driver + db-bench file-form leg + docs in one pass, gates
|
||||
green. No plan document needed unless it grows.
|
||||
Loading…
Reference in a new issue