docs: arc closeout (T8) — stage 3 landed, chain advances to 22

- stories 08+11 to done/ with banners (11: fs-park re-scoped out of
  v1, disclosed); guarantee-contract table re-homed in story 08;
  marker doc deleted per convention
- board standup: implemented/findings/learned/unblocked/next/.dev-ref
  for the landing; In-progress = nothing active, next = 22 spec
- arc plan status ARC COMPLETE, T7/T8 boxes checked with deviations;
  graph nodes done; framework ledger rows note arc-unblocked;
  18's pub/sub rejection expired note
- CODE-LOGIC: runtime DB-actor + ring-params section, database slot
  surface; oop-vm/03 contract gains the reply-park protocol
- 22 precursor recorded: remote insert ~8us/op RAM-only
- full battery + db-actor gate green after doc edits; links verified

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
shoney.arickathil 2026-08-21 13:16:25 +02:00
parent 1ed4922fdd
commit 5a9c11bfa8
20 changed files with 535 additions and 131 deletions

1
docs/.obsidian/app.json vendored Normal file
View file

@ -0,0 +1 @@
{}

1
docs/.obsidian/appearance.json vendored Normal file
View file

@ -0,0 +1 @@
{}

3
docs/.obsidian/community-plugins.json vendored Normal file
View file

@ -0,0 +1,3 @@
[
"obsidian-kanban"
]

33
docs/.obsidian/core-plugins.json vendored Normal file
View file

@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": false,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,11 @@
{
"id": "obsidian-kanban",
"name": "Kanban",
"version": "2.0.51",
"minAppVersion": "1.0.0",
"description": "Create markdown-backed Kanban boards in Obsidian.",
"author": "mgmeyers",
"authorUrl": "https://github.com/mgmeyers/obsidian-kanban",
"helpUrl": "https://publish.obsidian.md/kanban/Obsidian+Kanban+Plugin",
"isDesktopOnly": false
}

File diff suppressed because one or more lines are too long

200
docs/.obsidian/workspace.json vendored Normal file
View file

@ -0,0 +1,200 @@
{
"main": {
"id": "37ae5fc60296c375",
"type": "split",
"children": [
{
"id": "7ef3e1b9e1a65a0c",
"type": "tabs",
"children": [
{
"id": "97901a6f2f70cb17",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "stories/00-status.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "00-status"
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "6918ba61f90a8cfd",
"type": "split",
"children": [
{
"id": "fbed015db39ece98",
"type": "tabs",
"children": [
{
"id": "691d5f208a487f9b",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
},
"icon": "lucide-folder-closed",
"title": "Files"
}
},
{
"id": "c33bb438afb8b866",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "Search"
}
},
{
"id": "a998ab8b9bb836be",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {},
"icon": "lucide-bookmark",
"title": "Bookmarks"
}
}
]
}
],
"direction": "horizontal",
"width": 300
},
"right": {
"id": "a01f7bd149bc3ae9",
"type": "split",
"children": [
{
"id": "e374d16e4702303c",
"type": "tabs",
"children": [
{
"id": "6d1b536f9ffba4ae",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"file": "stories/00-status.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "Backlinks for 00-status"
}
},
{
"id": "69948a39e8f1fe33",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"file": "stories/00-status.md",
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "Outgoing links from 00-status"
}
},
{
"id": "7658cb0464d442ae",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "Tags"
}
},
{
"id": "4b4cac875bd137f0",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"file": "stories/00-status.md",
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "Outline of 00-status"
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"left-ribbon": {
"hiddenItems": {
"switcher:Open quick switcher": false,
"graph:Open graph view": false,
"canvas:Create new canvas": false,
"daily-notes:Open today's daily note": false,
"templates:Insert template": false,
"command-palette:Open command palette": false,
"bases:Create new base": false,
"obsidian-kanban:Create new board": false
}
},
"active": "97901a6f2f70cb17",
"lastOpenFiles": [
"stories/board-views.md",
"stories/00-status.md",
"Untitled.base",
"Untitled Kanban 1.md",
"Untitled Kanban.md",
"plan/oop-vm/03-concurrency-coroutines.md",
"examples/db-actor/main.wo.tmp.2343240.b9747a44fe0b",
"examples/db-actor/target/db-actor",
"examples/db-actor/target",
"examples/db-actor/main.wo",
"examples/db-actor/main.wo.tmp.2343240.9b5c59f21269",
"examples/db-actor/wo.toml",
"examples/db-actor/wo.toml.tmp.2343240.4efce1d04b07",
"examples/db-actor",
"plan/compiler/2026-08-01-woc-compiler-front.md",
"plan/compiler/2026-08-14-logwatcher-executable.md",
"plan/compiler/2026-08-15-employee-relations-query.md",
"08-project-structure.md",
"01-problem.md",
"00-principles.md",
"00-link-audit.md",
"00-dependency-graph.md",
"stories/00-status.md.tmp.2343240.053e968b0201",
"in-progress/2026-08-21-arc-stage-3.md"
]
}

View file

@ -33,10 +33,10 @@ flowchart TD
I9c["20 cross-program tables (half-built)"]:::open
I9d["21 keypair attach auth (half-built; crypto+handshake already on its branch)"]:::open
I9e["22 durability + throughput baseline"]:::open
I8["8 shard-actor runtime"]:::open
I8["8 shard-actor runtime ✅ 2026-08-21"]:::done
I9f["23 io_uring group-commit"]:::open
I10["10 HTTP service layer (lowers onto the framework)"]:::open
I11["11 fibers"]:::open
I11["11 fibers ✅ 2026-08-21"]:::done
I12["12 blue-green deploy"]:::open
I13["13 metaprogramming @derive"]:::open
I14["14 skillhost workload (demoted)"]:::open

3
docs/Untitled.base Normal file
View file

@ -0,0 +1,3 @@
views:
- type: table
name: Table

View file

@ -17,7 +17,9 @@ writeonce-framework = { git = "https://github.com/shoneyj/writeonce-framework",
Connection policy: **pipelined requests are served on one connection;
idle connections close after the response** — on a single-threaded server
a parked keep-alive connection would block `accept` and starve every
other client, so closing is the correct shape until shards/fibers (8/11).
other client, so closing is the correct shape until fiber-per-connection
serving lands (the arc — 8/11 — landed 2026-08-21; the serve-loop slice
that consumes it is iteration 24's).
A proxy in front simply reconnects.
- **Router** (`router/`): method + path table with `:param` captures into
`req.params`; first match wins; a known path with the wrong method is
@ -51,7 +53,8 @@ writeonce-framework = { git = "https://github.com/shoneyj/writeonce-framework",
## Honest limits (v1, all deliberate)
- **Single-threaded, blocking** — one request at a time. Concurrency arrives
underneath this same surface with the shard/fiber iterations (8/11).
underneath this same surface now that the arc (8/11) has landed
(2026-08-21); the switch itself rides iteration 24's serving slice.
- **TLS: none, anywhere.** Deploy behind nginx/caddy; the proxy terminates
TLS+ALPN and gives browsers HTTP/2 while this backend speaks HTTP/1.1
keep-alive. See the web-app sample's README for the nginx sketch.
@ -77,7 +80,7 @@ first (pure `.wo` cannot express it yet).
| Item | State |
| --- | --- |
| HTTP/1.1 parsing | 🔶 parses + 400-and-survive; STRICT ambiguity rejection (duplicate/conflicting `Content-Length`, oversize checks beyond BODY_MAX) not audited — hardening slice |
| Keep-alive | ✅ pipelined-serve / close-when-idle (starvation-honest until 8/11) |
| Keep-alive | ✅ pipelined-serve / close-when-idle (arc landed 2026-08-21; retirement of close-when-idle rides iteration 24's fiber-per-connection slice) |
| Read/write/idle timeouts | 🔧 `net` has no timeout surface — runtime seam, then a framework knob |
| Request size limits | ✅ BODY_MAX bounds headers AND body |
| Unix socket binding | 🔧 `net.listen` is TCP-only — runtime seam |
@ -102,7 +105,7 @@ first (pure `.wo` cannot express it yet).
| Content negotiation | 🔶 `media_type(req)` covers the request side; `Accept`-driven response negotiation ⬜ |
| Trusted-proxy client IP | 🔶 `X-Forwarded-For/-Proto` parsing is expressible (candidate slice); VERIFYING the peer is the trusted proxy needs a peer-address runtime seam 🔧 |
| Status/header setting · redirects | ✅ builders + `set_header` |
| Lazy body streaming + backpressure · streaming responses · explicit commit point | ⏸ 8/11 — whole bodies, one write, by design |
| Lazy body streaming + backpressure · streaming responses · explicit commit point | ⏸ UNBLOCKED by the arc (8/11 landed 2026-08-21) — stays parked until its own slice |
| ETag + conditional requests | ⬜ candidate; wants the crypto slice's hashing |
### Context & middleware

View file

@ -1,60 +0,0 @@
# In progress — the 8+11 arc, stage 3: the transparent DB actor
> **Status: 🔄 in progress** (started 2026-08-21) — first slice of the
> concurrency chain **stage 3 → 22 → 31 → 24 → 23 → 32**. Board:
> [../00-status.md](../stories/00-status.md).
>
> This folder holds ONE marker doc: the slice being executed right now,
> so the active work is findable without reading the board. When the
> slice lands, the board's done section takes the record and this file
> is deleted — the plan and stories stay the authority.
## What
Stage 3 (Tasks 7–8) of the plan of record,
[`superpowers/plans/2026-08-20-shard-fiber-arc.md`](../superpowers/plans/2026-08-20-shard-fiber-arc.md):
engine calls off the owner shard become message sends with parked
replies. A correctness fix, not an optimization — `rt.db` is set only on
the primary (`runtime/src/main.c`), worker VMs are zero-initialized, so
any DB statement off the primary traps `WO_T_DB` today.
## Why now
Developer decision 2026-08-21: correctness before measurement. Fixing
the hole first lets iteration 22's single benchmark campaign cover
single- AND multi-shard honestly.
## Stories
- [8 — shard-actor runtime](../stories/language-runtime-database/in-progress/08-shard-actor-runtime.md)
(stage 3 is its remaining scope)
- [11 — fibers](../stories/language-runtime-database/in-progress/11-fibers.md)
(substance landed stages 1+2; closes with this slice — note: `fs`
still blocks instead of parking, land it here or re-scope 11's
criterion explicitly at close)
## Guarantee contract (refined 2026-08-21)
The five store properties, mapped honestly — what this slice owes vs
what is already proven or deferred:
| property | state |
| --- | --- |
| Atomicity | per-statement ✅ (WAL record replays whole-or-not-at-all); multi-statement = `transaction { }`, iteration 18, ⏸ held. **Stage-3 obligation:** a worker write RPC is exactly ONE owner-shard commit — a crash between send and commit leaves no ack and no partial state. |
| Durability | ✅ fsync-per-commit, ack-after-durable. **Stage-3 obligation:** the ack crosses shards only AFTER the owner's fsync completes. Power-loss rides fdatasync semantics; 22's kill battery is the scripted proof. |
| Crash recovery | ✅ boot replay, torn-tail drop, index rebuild; 22 scripts the restart proof. **Stage-3 obligation:** workers never open the WAL or data dir; replay completes on the primary before any worker serves. |
| Concurrency control | **THIS SLICE.** The DB actor serializes every statement; replies are materialized copies — no torn read can exist by construction. Each statement sees the serialized moment its envelope executes; cross-statement snapshots arrive with 18. |
| Space reclamation | RAM ✅ — deleted rows free their slot ([`04-db-binding.md`](../plan/oop-vm/04-db-binding.md): "Ids are never reused; slots are"). Disk ✖ — the WAL grows unbounded, no checkpoint exists → [story 32](../stories/language-runtime-database/refine/32-wal-checkpoint.md), end of chain. |
## Definition of done
- The guarantee obligations above hold: one commit per write RPC with
ack-after-owner-fsync, workers WAL-free with replay-before-serve, and
no torn reads under concurrent multi-shard load.
- Plan Tasks 7–8 checked off; full battery green (`just woc-test`,
`just oop-e2e`, `just deps-accept`, `just web-app`, `just log-watcher`,
`just employee`, `just fibers`) — multi-shard DB answers byte-identical
to single-shard, WAL ack-after-durable unchanged.
- Stories 08 + 11 move to `stories/language-runtime-database/done/`
together; board updated in the same change.
- Next slice: iteration 22 (measurement backbone) replaces this file.

View file

@ -3,8 +3,8 @@
> Exploration/reference note (no status banner by board convention).
> The normative decisions live in the arc spec
> ([`2026-08-20-shard-fiber-arc-design.md`](../../../superpowers/specs/2026-08-20-shard-fiber-arc-design.md))
> and iterations [8](../../../stories/language-runtime-database/in-progress/08-shard-actor-runtime.md) /
> [11](../../../stories/language-runtime-database/in-progress/11-fibers.md); this
> and iterations [8](../../../stories/language-runtime-database/done/08-shard-actor-runtime.md) /
> [11](../../../stories/language-runtime-database/done/11-fibers.md); this
> page explains the WHY at doctrine depth. Written 2026-08-20, when this
> file was also the target of a dangling reference from iteration 11 —
> it exists now.

View file

@ -107,6 +107,13 @@ write, never restarts it.
— resume **continues PAST the builtin**. `park_ts` must outlive the
ring submission (the TIMEOUT op reads it asynchronously).
**Parking on a reply** (stage 3, the DB actor): `park_fd =
WO_PARK_INBOX` (-2) — the fiber joins the parked list with NO plane
wait at all; the wake is `wo_io_unpark` from the shard's envelope
drain when the reply lands. `park_done = 0`: resume re-executes the
builtin, which consumes the answer. Deadline scans key on
`park_fd == -1` EXACTLY — an inbox park must never read as a deadline.
**The I/O plane** (`park.c`): one event loop per shard — parked fibers'
waits and the shard's inbox eventfd on the SAME loop. io_uring FIRST
(raw `io_uring_setup`/`io_uring_enter`, POLL_ADD + TIMEOUT at the Linux
@ -139,7 +146,7 @@ stop is not a trap and cannot be caught.
| --- | --- |
| shards, envelopes, ownership-move sends, WO-E221/E222, placement | [arc spec](../../superpowers/specs/2026-08-20-shard-fiber-arc-design.md) + [arc plan deviations](../../superpowers/plans/2026-08-20-shard-fiber-arc.md) |
| request/response, bounded mailboxes, actor death, timers | [iteration 31](../../stories/language-runtime-database/refine/31-actor-lifecycle.md) — not built yet |
| the DB actor (stage 3) | [in-progress marker](../../in-progress/2026-08-21-arc-stage-3.md) |
| the DB actor (stage 3) | [story 8's guarantee contract](../../stories/language-runtime-database/done/08-shard-actor-runtime.md) — landed 2026-08-21 |
| builtin ids and their park behavior | [`08-builtin-surface.md`](08-builtin-surface.md) |
## 7. Rejected alternatives — settled, argue against the reason

View file

@ -34,49 +34,49 @@ machine-readable truth behind this board; live Obsidian Dataview views:
## ▶ NEXT PLAN
**The concurrency + fiber chain — stage 3 → 22 → 31 → 24 → 23 → 32**
(directive 2026-08-21). Active slice: the 8+11 arc's **stage 3, the
transparent DB actor** — marker doc
[`in-progress/2026-08-21-arc-stage-3.md`](../in-progress/2026-08-21-arc-stage-3.md),
plan of record
[`shard-fiber-arc` Tasks 7–8](../superpowers/plans/2026-08-20-shard-fiber-arc.md),
stories [8](language-runtime-database/in-progress/08-shard-actor-runtime.md) +
[11](language-runtime-database/in-progress/11-fibers.md) in
`stories/language-runtime-database/in-progress/`.
**The concurrency + fiber chain — ✅ stage 3 → 22 → 31 → 24 → 23 → 32**
(directive 2026-08-21). Next slice: **iteration 22, the measurement
backbone** — its spec brainstorm is the next act (four forks recorded in
[the story](language-runtime-database/refine/22-durability-throughput-scale.md));
no marker doc until it starts.
**Implemented last time:** framework v1 complete (polish, auth, form,
multipart — `just web-app` 26/0); the arc's stages 1+2 (reduction-budget
fibers, `spawn`/`send`/`actor M`, pinned shards, envelope sends with
home-routed frees, WO-E222, io_uring-first I/O plane with `just fibers`
8/0); iterations 19 (Float/Bytes, `.wob` v5) and 17 (library kind +
`internal/`).
**Implemented last time (2026-08-21):** the arc's **stage 3 — the
transparent DB actor landed, the arc is COMPLETE** (stories
[8](language-runtime-database/done/08-shard-actor-runtime.md) +
[11](language-runtime-database/done/11-fibers.md) → done/). A worker
shard's DB statement marshals to shard 0 (requester-side slot encode),
executes serialized on the owner, and the fiber resumes with the
materialized reply — `WO_T_DB` off the primary is gone. NEW gate
`just db-actor` 8/0; ASan/TSan clean; WO_DATA pair proves worker writes
are ack-after-durable and replay.
**Key findings:** a multi-shard program touching the database traps
`WO_T_DB` (`rt.db` is set on the primary only) — a correctness hole, so
stage 3 runs BEFORE measurement; the benchmark (22) has never run, so no
performance claim is sourced; `send` is one-way and the mailbox FIFO is
unbounded (iteration 31 born from this); epoll approach discarded —
io_uring is a must (2026-08-01 shard-actor plan ✖).
**Key findings:** a latent stage-1 bug — io_uring ring params were ONE
shared static, rewritten by every shard's lazy init while others read
offsets from it: submits landed at garbage offsets and parked fibers
LOST WAKES (~1/20 hangs at default cores). Per-vm params fixed it; a
short `io_uring_enter` submit is now a loud trap. Also: single-binary
gates embed the runtime — rebuild the SAMPLE, not just wovm, or you
debug a stale binary.
**Learned from the last iteration:** the reduction budget must decrement
at loop back-edges only (budget-1 livelock otherwise); a mutex-guarded
inbox + eventfd suffices until 22 measures the mutex; routed frees
during teardown must be no-ops (arenas die wholesale) — two TSan races
and one SEGV taught it.
**Learned from the last iteration:** the owner thread must never read a
requester's VM heap (concurrent mark-bit writes = TSan race) — marshal
by ENCODING on the requester's thread, execute from slots replay-style;
a plane-less park (`WO_PARK_INBOX`) + envelope wake is all an RPC reply
needs; a busy shard adopting its inbox once per reduction slice bounds
request latency.
**Dependencies unblocked:** 19 unblocks 24's WS frames and the crypto
digests; stages 1+2 unblock stage 3 itself and 23's per-shard ring;
stage 3 unblocks 22's multi-shard campaign.
**Dependencies unblocked:** 22's multi-shard campaign (the store is
correct under shards now); 24's serving model (fiber-per-connection has
a database it can touch from any shard); the framework ledger rows the
arc gates stay ⏸ until their own slices.
**Next steps:** stage 3 → 22 (baselines + mutex-inbox number) → 31
(lifecycle) → 24 (chat, the arc's acceptance) → 23 (io_uring
group-commit) → 32 (WAL checkpoint — disk reclamation, added
2026-08-21 by the stage-3 guarantee refinement). Held tail resumes on
its own precedence notes.
**Next steps:** 22 (baselines single- AND multi-shard + the mutex-inbox
number; precursor recorded in story 8: remote insert ≈8µs/op RAM-only)
→ 31 (lifecycle) → 24 (chat) → 23 (io_uring group-commit) → 32 (WAL
checkpoint). Held tail resumes on its own precedence notes.
**`.dev/reference` used:** `linux` (the "single event loop" card behind
the io_uring-first directive, arc T4). Record the ones each iteration
touches here, per the standup convention.
**`.dev/reference` used:** `linux` (io_uring uapi struct layouts and the
"single event loop" card — both load-bearing in the ring-params fix).
---
@ -225,11 +225,11 @@ that sequences its tasks. Read one, approve, then the next starts.
| 6 | [Program mode + stdlib](language-runtime-database/done/06-program-mode-stdlib.md) | ✅ (the surface log-watcher uses) |
| 7 | [log-watcher proof](language-runtime-database/done/07-logwatcher-proof.md) | ✅ **landed 2026-08-15** — executable, not merely compilable: zero ASan leaks in all three modes, SIGTERM ends parked syscalls, fds flat, `LW_SOAK` gate; `just log-watcher` 7/0 |
| 7b | [Inferred GC + mark-sweep](language-runtime-database/done/07b-inferred-gc-mark-sweep.md) | ✅ **landed 2026-08-18** — `@gc` gone (WO-E104), GC-ness inferred, RC replaced by incremental mark-sweep, `.wob` v4; supersedes iteration 2's RC memory model |
| 8 | [Shard-actor runtime](language-runtime-database/in-progress/08-shard-actor-runtime.md) | 🔄 arc stages 1+2 landed 2026-08-20 (branch concurrency-arc); stage 3 (transparent DB actor) = **first in the concurrency chain** |
| 8 | [Shard-actor runtime](language-runtime-database/done/08-shard-actor-runtime.md) | ✅ **landed 2026-08-21** — the arc complete: stages 1+2 (fibers/budget/actors/io_uring plane, shards, envelopes, WO-E222) + stage 3's transparent DB actor (`just db-actor` 8/0, ASan/TSan clean, WAL replay pair) |
| 9 | [Database engine](language-runtime-database/done/09-database-engine.md) | 🔄 engine complete (storage/WAL/indexes/insert-update-delete); reads land with 9b |
| 9b | [`@table`, relations, query](language-runtime-database/done/09b-table-relations-query.md) | 🔄 query surface + relations + FK done (branch query-surface); group-by parked |
| 19 | [Float + Bytes](language-runtime-database/done/19-missing-scalar-types.md) | ✅ **landed 2026-08-20** — `.wob` v5: Float constant tag, field kinds 6/7, opcodes 34-41 (IEEE-quiet f64), builtins 70-83. Full stack: literals, arithmetic, `@table` column, WAL bit-exact replay, json fractions in / shortest-round-trip out, `?Float` reserved-NaN nil, total-order index (NaN last, `-0.0` == `+0.0`), Bytes + base64. No implicit Int/Float mixing (WO-E201); `float`/`trunc` are the only bridges. Proof: web-app price is a real Float (`{"price":9.99}`), `just web-app` 23/0; corpus 103/0 |
| 11 | [Fibers](language-runtime-database/in-progress/11-fibers.md) | 🔄 stages 1+2 landed 2026-08-20 with 8 (`just fibers` 8/0); closes with the arc's stage 3 |
| 11 | [Fibers](language-runtime-database/done/11-fibers.md) | ✅ **landed 2026-08-21** with the arc (`just fibers` 10/0); fs-park re-scoped out of v1, disclosed in the story |
| 22 | [Durability, throughput, scale](language-runtime-database/refine/22-durability-throughput-scale.md) | ⬜ needs a spec first — second in chain, after arc stage 3 |
| 31 | [Actor lifecycle](language-runtime-database/refine/31-actor-lifecycle.md) | ⬜ needs a spec first — third in chain (story written 2026-08-21) |
| 24 | [chat: WebSocket workload](language-runtime-database/refine/24-chat-websocket-workload.md) | ⬜ fourth in chain — the arc's acceptance; after 31 |
@ -245,7 +245,7 @@ that sequences its tasks. Read one, approve, then the next starts.
| 15 | [deps: `wo.toml [deps]`](language-runtime-database/done/15-deps-package-manager.md) | ✅ **landed 2026-08-18** (branch web-framework): [deps] inline tables, git-binary fetch, wo.lock pinning, offline-when-locked, --update-deps, WO-E106/E107; `just deps-accept` 8/0 |
| 16 | [web framework](language-runtime-database/done/16-web-framework.md) | ✅ **landed 2026-08-19** — writeonce-framework (HTTP/1.1 + router + Handler/Middleware) consumed by web-app through [deps]; h2c parked (§C) behind 8/23/11. **v1 polish landed 2026-08-20** (branch framework-v1): get/post/put/delete_ helpers, 405+Allow, HEAD, Logging middleware, set_header; `just web-app` 16/0; fixed the interp-borrowed-field emitter crash en route. **Auth-in-core landed 2026-08-20**: http/auth.wo (Bearer/Basic, ct_eq, req.principal), web-app dogfoods BearerAuth, gate 17/0 |
| 17 | [library projects + `internal/`](language-runtime-database/done/17-library-projects-internal.md) | ✅ **landed 2026-08-20** — `kind = "library"` in `wo.toml` (default `program`, so every existing manifest is byte-identical; unknown value = WO-E109 exit 2); `woc <dir>` on a library runs the FULL pipeline entry-less and writes nothing, retiring iteration 16's `--emit` workaround; the no-entry build error names the kind; lib+bin dual works. Go's `internal/` rule as **WO-E108** at the consumer's own `use`, dep-boundary-only — the library imports its own interior freely. Framework reorganized: `internal/{parse,serve}.wo` behind the line, `http/form.wo` split out to keep `media_type`/`form_values` public. Driver-only change; VM/`.wob`/GC untouched. `just web-app` **26/0** (3 new checks), every standing gate unchanged |
| 18 | [framework v2: memory-rich features](language-runtime-database/hold/18-memory-db-features.md) | ⏸ hold (2026-08-21); spec approved + plan authored, both held intact ([spec](../superpowers/specs/2026-08-20-memory-db-features-design.md), [plan](../superpowers/plans/2026-08-20-framework-v2-memory-features.md)): TTL cache + @table flags + durable job queue (drain-on-request) + `transaction { }` over the WAL's staged batch; pub/sub REJECTED until 8/11 |
| 18 | [framework v2: memory-rich features](language-runtime-database/hold/18-memory-db-features.md) | ⏸ hold (2026-08-21); spec approved + plan authored, both held intact ([spec](../superpowers/specs/2026-08-20-memory-db-features-design.md), [plan](../superpowers/plans/2026-08-20-framework-v2-memory-features.md)): TTL cache + @table flags + durable job queue (drain-on-request) + `transaction { }` over the WAL's staged batch; pub/sub rejection expired with the arc (8/11 landed 2026-08-21) — revisit on unhold |
---
@ -253,7 +253,7 @@ that sequences its tasks. Read one, approve, then the next starts.
| Track | Item | Where |
| -------- | --------------------------------------------------------------------------- | ---------------------------------------------------------- |
| Runtime | **the 8+11 arc, stage 3: transparent DB actor** — first slice of the concurrency chain (2026-08-21) | [marker doc](../in-progress/2026-08-21-arc-stage-3.md) · [arc plan Tasks 7–8](../superpowers/plans/2026-08-20-shard-fiber-arc.md) |
| Runtime | nothing active — arc stage 3 landed 2026-08-21; next per the chain: iteration 22's spec brainstorm (four forks recorded in its story) | [order](#implementation-order-re-sequenced-2026-08-21--concurrency-chain) |
The active slice's marker doc lives in [`in-progress/`](../in-progress/) —
one file, deleted when the slice lands. Everything else pending is the
@ -434,7 +434,8 @@ the arc's, the baseline is 22's); 24 after 31 (chat is dishonest without
lifecycle); h2c stays parked behind the chain; the held tail keeps its own
precedence notes for resumption.
1. **8+11 stage 3** — transparent DB actor. A correctness fix, not an
1. ✅ **8+11 stage 3** — landed 2026-08-21 (`just db-actor` 8/0; arc
complete, stories in done/). Was: transparent DB actor. A correctness fix, not an
optimization: worker VMs are zero-initialized, so a DB statement off
the primary traps `WO_T_DB` — a multi-shard program touching the
database is broken today. Plan of record:

View file

@ -99,7 +99,7 @@ still pending IS the runtime-concurrency chain; order:
| 10 | 9b | [`@table`, relations, query](done/09b-table-relations-query.md) | `@table` real storage; `ref`/`backlink`/`multi`; compiler-checked queries |
| 11 | 15 | [deps: `wo.toml [deps]`](done/15-deps-package-manager.md) | exact-rev git deps + `wo.lock` + `.wo-deps`; flat-only, offline once locked |
| 12 | 16 | [web framework](done/16-web-framework.md) | the `.wo` framework v1 (router, middleware, auth, all three body hooks) consumed via `[deps]` |
| 13 | 8+11 | [Shard-actor runtime](in-progress/08-shard-actor-runtime.md) · [Fibers](in-progress/11-fibers.md) | THE ARC (stages 1+2 landed 2026-08-20: fibers/budget/actors/io_uring plane; pinned shards, envelope sends, home-routed frees, WO-E222); stage 3 = transparent DB RPC. **Promoted above 22 (2026-08-21): stage 3 is a correctness hole, not an optimization** — worker shards are zero-initialized, so a DB statement off the primary traps `WO_T_DB`. |
| 13 | 8+11 | [Shard-actor runtime](done/08-shard-actor-runtime.md) · [Fibers](done/11-fibers.md) | ✅ **THE ARC LANDED 2026-08-21** — stages 1+2 (fibers/budget/actors/io_uring plane; pinned shards, envelope sends, home-routed frees, WO-E222) + stage 3's transparent DB actor: worker statements marshal to shard 0, ack-after-owner-fsync, materialized replies (`just db-actor` 8/0, ASan/TSan, WAL replay pair). fs-park re-scoped out (disclosed in story 11). |
| 14 | 22 | [Durability, throughput, scale](refine/22-durability-throughput-scale.md) | restart-persistence proof, benchmarks, ~1M rows — the baseline the arc and 23 sign against. It has never run, so every performance claim on this project is currently unsourced; runs after stage 3 so one campaign covers single- and multi-shard, plus the stage-2 mutex-inbox number. *(was 9e)* |
| 15 | 30 | Observability, CI, fuzz *(no story file yet)* | **NEW** — runtime counters + a profiler hook, 22's harness wired to run per change instead of by hand, and a fuzz target on the parser and `.wob` loader. The whole proof-maturity gap had no iteration to point at. |
| 16 | 19 | [Float + Bytes](done/19-missing-scalar-types.md) | **LANDED 2026-08-20** — `.wob` v5; the full stack: IEEE-quiet f64 through literals/VM/@table/WAL/json + Bytes as the binary carrier, no implicit mixing, total-order indexes. Unblocks 24 (WS frames) and the crypto fork (digests). *(was 20)* |

View file

@ -1,6 +1,6 @@
---
iteration: "8"
status: in-progress
status: done
chain: 1
---
@ -9,6 +9,18 @@ chain: 1
> Format: fiberloom `product/story-iteration-template`. Part of
> [Story — one language, one runtime, one database, one binary](../00-story.md).
>
> **✅ LANDED 2026-08-21** — the arc is complete. Stage 3 closed the
> `WO_T_DB` hole: worker-shard DB statements marshal to the owner shard
> (requester-side slot encode, serialized owner execution, materialized
> reply, ack-after-owner-fsync). Proof: `just db-actor` 8/0 (NEW gate,
> `docs/examples/db-actor`), ASan/TSan clean, full battery green, WAL
> replay pair. The three stage-3 criteria below hold; the heavier
> concurrent-load truth is iteration 22's campaign. 22's minimal
> precursor (RAM-only): 500 remote inserts ≈4ms (~8µs/RPC round-trip)
> vs local ≈0ms; 50 remote scans ≈2–4ms. En route, a latent stage-1 bug
> fell: shared io_uring params raced by lazy worker init lost park wakes
> (~1/20 hangs) — params are per-vm now, short submits trap loud.
>
> **REFINED 2026-08-20** (developer decisions, no code): iterations 8 and
> 11 are **one arc** — the scheduler, fibers on it, then serving — because
> the database-ownership decision below makes a fiberless multi-shard
@ -115,8 +127,8 @@ chain: 1
- **when** the deterministic multi-shard corpus runs under TSan,
- **then** no torn read exists — every statement sees the serialized
moment its envelope executes on the owner shard (replies are
materialized copies). Full guarantee map:
[the marker doc](../../../in-progress/2026-08-21-arc-stage-3.md).
materialized copies). Full guarantee map: the contract table in
*Info* below.
## Out Of Scope
@ -129,6 +141,17 @@ chain: 1
## Info
**Guarantee contract** (stage-3 refinement 2026-08-21; moved here from
the slice's marker doc when it landed):
| property | state |
| --- | --- |
| Atomicity | per-statement ✅ (WAL record replays whole-or-not-at-all); multi-statement = `transaction { }`, iteration 18, ⏸ held. Stage 3: a worker write RPC is exactly ONE owner-shard commit — a crash between send and commit leaves no ack and no partial state. |
| Durability | ✅ fsync-per-commit, ack-after-durable; the ack crosses shards only AFTER the owner's fsync (`just db-actor`'s WAL pair). Power-loss rides fdatasync semantics; 22's kill battery is the scripted proof. |
| Crash recovery | ✅ boot replay, torn-tail drop, index rebuild; replay completes on the primary before any worker serves (main.c boots the engine before the shards). 22 scripts the restart proof. |
| Concurrency control | ✅ stage 3 — the DB actor serializes every statement; replies are materialized copies, no torn read by construction. Cross-statement snapshots arrive with 18. |
| Space reclamation | RAM ✅ (deleted rows free their slot — ids never reused, slots are); disk ✖ → [story 32](../refine/32-wal-checkpoint.md), end of chain. |
- The C proving ground (`docs/plan/exploration/c-runtime/`, phases A–F:
epoll loops, eventfd mail) is the substrate this lifts into `wovm`.
(Path restated 2026-08-20; the old `runtime/wo-rt.c` reference was

View file

@ -1,6 +1,6 @@
---
iteration: "11"
status: in-progress
status: done
chain: 1
---
@ -9,6 +9,16 @@ chain: 1
> Format: fiberloom `product/story-iteration-template`. Part of
> [Story — one language, one runtime, one database, one binary](../00-story.md).
>
> **✅ LANDED 2026-08-21** with the arc's stage 3 (fiber substance landed
> stages 1+2; stage 3 added the plane-less reply park `WO_PARK_INBOX` —
> a fiber parked on the DB actor's reply, woken by the envelope drain).
> RE-SCOPED at close, disclosed: the goal's "blocking builtins park"
> covers `net`/`time`; **`fs` still blocks the shard thread** — v1
> semantics, deliberately: program mode is single-fiber by design, and
> no serving workload reads files mid-request yet. fs-park becomes real
> when a workload demands it (candidate rider on 23's ring work). The
> criteria below are met under that re-scope.
>
> **REFINED 2026-08-20** (developer decisions, no code): 8 and 11 ship as
> **one arc** — the DB becomes an actor on an owner shard
> ([iteration 8](08-shard-actor-runtime.md)'s decision), so serving

View file

@ -1,8 +1,18 @@
# The 8+11 concurrency arc — implementation plan (staged)
> **Status: STAGES 1 AND 2 COMPLETE 2026-08-20** (branch `concurrency-arc`,
> T1–T4 landed + the `docs/examples/fibers` demo and its `just fibers`
> gate, 8/0). Stages 2–3 pending. Execution deviations, disclosed:
> **Status: ✅ ARC COMPLETE — STAGE 3 LANDED 2026-08-21** (branch
> `concurrency-arc-stage3`, T7 executed; T8 is this closeout). The
> transparent DB actor is live: a worker shard's DB statement marshals to
> shard 0, parks, resumes with the materialized reply — `WO_T_DB` off the
> primary is gone. Proof: NEW gate `just db-actor` 8/0 (multi-shard ×3 +
> both forced backends + single-shard byte-exact + WO_DATA replay pair),
> ASan/TSan 6/6 on the RPC path, full battery green. Stage-3 deviations
> are disclosed at Task 7; stage 1+2 history below stands. 22's minimal
> precursor recorded in the stories (RAM-only: 500 remote inserts ≈4ms
> vs local ≈0ms — real numbers are 22's).
>
> Stages 1+2 completed 2026-08-20 (branch `concurrency-arc`, T1–T6 + the
> `docs/examples/fibers` demo and its gate). Execution deviations, disclosed:
> (1) the reduction budget decrements at loop BACK-EDGES ONLY, after the
> jump lands — the spec's "same three sites as the GC" wording had a
> livelock at budget 1 (pre-instruction save re-executes the jump into
@ -37,8 +47,8 @@ every standing gate green before the next begins.
**Architecture:** see the spec (normative):
[`../specs/2026-08-20-shard-fiber-arc-design.md`](../specs/2026-08-20-shard-fiber-arc-design.md).
Stories: [8](../../stories/language-runtime-database/in-progress/08-shard-actor-runtime.md) ·
[11](../../stories/language-runtime-database/in-progress/11-fibers.md).
Stories: [8](../../stories/language-runtime-database/done/08-shard-actor-runtime.md) ·
[11](../../stories/language-runtime-database/done/11-fibers.md).
**Tech Stack:** C11 libc-only (`wovm`), OCaml stdlib-only (`woc`), bash
gates; TSan added to the corpus harness at stage 2.
@ -194,7 +204,7 @@ transitively-traced check), corpus + TSan.
> primary before any worker serves; (3) statements are serialized by the
> DB actor — replies are materialized copies, no torn reads under the
> concurrent multi-shard corpus (TSan). The five-property map lives in
> [the marker doc](../../in-progress/2026-08-21-arc-stage-3.md); disk
> [story 8's guarantee contract](../../stories/language-runtime-database/done/08-shard-actor-runtime.md); disk
> space reclamation is story 32, not this stage.
### Task 7 — transparent DB RPC
@ -235,14 +245,18 @@ transitively-traced check), corpus + TSan.
### Task 8 — the arc's closeout
- [ ] 22's benchmark re-run (or its minimal precursor if 22 has not
landed: the employee read/write loop timed) single- vs multi-shard;
numbers recorded in the stories.
- [ ] Stories 8 + 11 landing banners; board rows; graph node classes;
framework README ledger rows that the arc unblocks (streaming etc.
stay ⏸ until their own slices — the arc UNBLOCKS, it does not build
them); CODE-LOGIC files (vm fiber model, shard/mailbox model, DB RPC).
- [ ] Full battery once more after doc edits. Commit.
- [x] 22's minimal precursor (22 has not landed): a timed 500-insert +
50-scan loop, local vs spawned-actor, RAM-only — remote inserts ≈4ms
for 500 (~8µs/RPC round-trip incl. park/resume), local ≈0ms; scans
≈2–4ms per 50. Recorded in story 8's landing banner; honest numbers
with p50/p99 are 22's campaign.
- [x] Stories 8 + 11 landed with banners (11 carries the fs-park
re-scope, disclosed); board standup + rows + pending list flipped;
graph nodes I8/I11 → done; framework README ledger rows note the arc
UNBLOCKED them (streaming/keep-alive retirement ride iteration 24;
rows stay ⏸); CODE-LOGIC: runtime/src gains the DB-actor + ring-params
section, database/src the slot-surface section.
- [x] Full battery once more after doc edits. Commit.
## Success criteria

View file

@ -1,7 +1,7 @@
# The 8+11 concurrency arc — shards, fibers, actors: design
> **Status: spec, awaiting review (2026-08-20).** The arc's decisions were
> settled in [iteration 8](../../stories/language-runtime-database/in-progress/08-shard-actor-runtime.md)
> settled in [iteration 8](../../stories/language-runtime-database/done/08-shard-actor-runtime.md)
> (refined) and the brainstorm of 2026-08-20 (this document's Decisions).
> Covers iterations 8 AND 11 as one arc; iteration 24 (chat) is its
> acceptance workload and gets its own spec after this one. The plan