writeonce/docs/stories/language-runtime-database/33-single-file-db.md
shoney.arickathil c0b0dbb846 docs: audit all markdown against the code, fix findings, flatten status folders
- README: shipped concurrency/HTTP/WebSockets sat in the roadmap as "not yet
  available"; "no package manager" contradicted [deps]; the deps example
  would not have compiled (the key IS the module name)
- runtime/README: leads with wovm, wo-rt.c demoted to a historical section;
  dropped 2 nonexistent recipes, crates/rt, @gc refcounting, 13 suites -> 18
- employee + log-watcher READMEs claimed "does not compile"; both are gates
- error catalog: +10 emitted codes incl WO-E250, the only diagnostic the
  shipped query surface raises; recorded why the sweep rotted
- language-surface: group-by parses, then the typechecker refuses it
- 00-code-review + 00-link-audit re-run; history kept, not rewritten
- 48 dead Rust-era exploration links de-linked rather than re-pointed (their
  prose names the retired plan by number); successor map -> discarded.md
- 08-project-structure: compiler/plan/ never existed; corpus has 9 dirs, 5 empty
- releasing.md: dropped a --draft step the workflow never had
- new docs/00-doc-audit.md: findings + disposition, incl one row where the
  audit was wrong and the doc it accused was right
- status folders removed: 34 stories flat, status only in frontmatter; 252
  links recomputed from resolved paths; board/board-views/structure retaught
- story 24 -> in-progress, since frontmatter is now the only truth
- new iteration 38: fs mutation verbs + net.connect, the two capability
  families no iteration owned
- new iteration 39: gofiber/fiber v3.5.0 parity study. The ledger called
  CSRF/sessions unblocked by iteration 34's HMAC, but the runtime has no
  source of randomness at all
- linkcheck skips .dev/.superpowers: 0 broken paths, 0 bad anchors

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 19:20:22 +02:00

3.2 KiB

iteration status
33 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.

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'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.