- 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>
3.4 KiB
db-actor — the database reached from any shard
Status: shipped — arc stage 3's acceptance gate. Run it with
just db-actor. Landed 2026-08-21 with the shard-fiber arc (story 8 · plan).
The database lives on one shard — the owner, shard 0 — because RAM is
authoritative and a single writer is what makes the WAL's ordering meaningful.
That is a problem the moment actors are placed round-robin across cores: a
spawned actor has no say in which shard it lands on, and before stage 3 a
worker-shard insert trapped WO_T_DB with "database engine not initialized".
Stage 3's answer is a transparent DB actor: statements issued off the owner
shard marshal to it, execute there, and materialize their replies back. The
program's source says nothing about any of it — the same insert and the same
from … select work wherever the actor happens to run. This sample exists to
prove exactly that, which is why its acceptance criterion is placement
independence rather than any particular output.
What it does
Note is a @table with a secondary index on tag. Writer is an actor: each
one inserts a row, then scans the whole table and prints the sum it sees. main
spawns two writers, waits, then scans once itself.
With the default shard count, round-robin placement puts at least one writer off the owner shard — so one of those inserts and one of those scans travel the RPC path under test, and the other does not. Both must produce the same shape.
just db-actor # the gate
woc docs/examples/db-actor/ # or build it by hand
WO_SHARDS=1 ./docs/examples/db-actor/target/db-actor # force the local path
What the gate proves
scripts/db-actor-accept.sh, 8 checks:
| Check | Why it is shaped that way |
|---|---|
| multi-shard, three rounds | The writer lines are asserted as a set, not a sequence — scheduling decides their order, and pinning it would be testing the scheduler, not the RPC. The main line is exact. |
both WO_IO backends forced |
The reply park has to be plane-independent: io_uring and epoll must give the same answer, or the parking is leaking into semantics. |
| single shard, byte-exact | The local path is untouched by stage 3. Any drift here means the RPC changed the non-RPC case. |
WO_DATA restart pair |
A worker's insert must commit on the owner's WAL before its ack, so a restart replays it: 2 rows, then 2+2 after a second run. This is the durability claim the RPC could most easily break. |
Run under wovm_asan and wovm_tsan as well — cross-shard message passing is
exactly where a data race would hide, and TSan covering this demo is the one
place it runs.
Read it for
- How little the source knows. Compare
Writer.receivehere against the same statements inemployee: identical. Transparency is the feature. - Why
mainwaits.mainis not an actor and has no mailbox, so it sleeps rather than awaiting — the gap iteration 31'scallcloses for actors and 24's marker tracks.
Reasoning under the engine side: database/src/CODE-LOGIC.md.
Contract: plan/oop-vm/04-db-binding.md.