diff --git a/docs/stories/00-status.md b/docs/stories/00-status.md index 3458bfe..4e7e192 100644 --- a/docs/stories/00-status.md +++ b/docs/stories/00-status.md @@ -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=.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 | diff --git a/docs/stories/language-runtime-database/00-story.md b/docs/stories/language-runtime-database/00-story.md index f7814c6..594fdaa 100644 --- a/docs/stories/language-runtime-database/00-story.md +++ b/docs/stories/language-runtime-database/00-story.md @@ -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=.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 | diff --git a/docs/stories/language-runtime-database/refine/33-single-file-db.md b/docs/stories/language-runtime-database/refine/33-single-file-db.md new file mode 100644 index 0000000..1996435 --- /dev/null +++ b/docs/stories/language-runtime-database/refine/33-single-file-db.md @@ -0,0 +1,73 @@ +--- +iteration: "33" +status: refine +--- + +# Iteration 33 — `WO_DATA=.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=` +> 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=` 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 `/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=` (existing directory), **when** the same + program runs, **then** behavior is byte-identical to today — + `/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.