- wo_row_update_field: encode new value, unique re-check against a
shadow BEFORE any mutation (violating update leaves the row
untouched, DB_ERR_UNIQUE), index entries moved old-hash -> new-hash,
old engine value freed; proven by test_table (unique refusal keeps
the row, released key becomes insertable)
- WAL UPDATE record: full-row re-log, replay = replace (remove +
re-create same id); prefix/suffix delta recorded as later
optimization; test_wal replays insert+update to the updated state
- builtins 62 DB_UPDATE_FIELD (cid,id,field,value) and 63 DB_DELETE
(cid,id), commit-before-ack like insert, WO_T_UNIQUE/WO_T_DB/WO_T_IO
mapping; dispatch range 61..63; loader arities; runner mirror
- plan Task 5 marked superseded-in-part with the recorded deviation:
the language surface (reads, queries, row views, delete statement)
is 9b's, where the comprehension design put it -- no interim brace-
select grammar to retire later
- gates: test_table 839/0, test_wal 102/0, 15 suites, oop-e2e 73/0
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- compiler: `insert Class { ... }` is a typed Ast.Insert in statement
AND expression position, sharing the ctor literal's field grammar;
typechecked with the ctor's omittable rule; result = the row id (Int)
- owner pass: the engine copies at the row API, so an insert BORROWS
its field values -- no transfer, no E304; node is trap-capable and
carries a live-mask drop entry like DbStub did
- emit: builtin 61 window = class-id const + one slot per DECLARED
field in declaration order; omitted defaults emitted, omitted ?scalar
gets WO_NIL_SCALAR, other omitted optionals the zero word; fresh
argument values reaped after (the push/set copy semantics)
- runtime: database/src/db.c executes via the choke-point row API;
rt.db/rt.wal opaque handles on wo_rt; WO_DATA=<dir> = replay
<dir>/shard-0.wal at boot + commit-before-ack per statement (the
builtin's return IS the ack until iteration 8 ticks); failed commit
un-applies the row and traps WO_T_IO; loader validates the class-id
slot (variable window documented in wob.h + format doc)
- the promised diff: trap/pricing-set-price-db-stub is now
run/pricing-set-price-insert printing engine-allocated ids;
durability smoke prints 1,2 then 3,4 across two WO_DATA runs
- old "bare insert is an Ident" unit test rewritten to the new
contract; runner's loader mirror accepts id 61; goldens re-blessed
- gates: oop-accept ALL CRITERIA MET, oop-e2e 71/0, woc-test 566/0,
wovm-test green, log-watcher 7/0
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- database/src/wal.{c,h}: framed records len|crc32|payload|mark
("WOL1" written last -- no mark, no record), typed-row payloads
walking the class-table kinds (nested records, containers, nil
encodings), little-endian like the loader
- commit order verbatim from the shipped phase-D pattern: RAM apply,
stage, ONE pwrite + ONE fdatasync for the batch, ack after -- group
commit is everything staged riding one sync
- replay decodes straight into engine-owned values (no VM at boot)
and re-enters rows through the choke-point row API, so Task 4's
indexes will rebuild for free; next_id advances past replayed ids
this shard owns (wo_row_create_raw)
- torn tail = short/CRC-fail/no-mark/zero-len: intact prefix applies,
tear dropped whole, wo_wal_open positions AT the tear so the next
commit overwrites it; CRC-valid-but-undecodable = corruption, loud
- wo_wal_check: offline oracle, no engine needed -- the crash
battery's verifier
- test_wal 90/0 ASan+UBSan incl. five crash-battery rounds (fork,
insert/commit/ack-over-pipe, SIGKILL mid-stream: zero acked-but-
missing, zero acked-but-wrong); all runtime suites green, oop-e2e
71/0; binding doc WAL section + CODE-LOGIC + plan Task 2 checked
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- database/src/table.{c,h}: per-shard per-class slabs (256 rows,
malloc'd, never moved -- row addresses stable for 9b's row views),
occupancy bitmap, LIFO slot reuse, open-addressing id hash with
tombstones (ids never 0, never reused)
- field encoding walks the same .wob class-table kinds the VM walks:
scalars raw (WO_NIL_SCALAR passes through), Texts copied to db_text,
owned objects flattened recursively to db_rec, containers
element-wise; GCREF refused at encode (the GC bulkhead, defensively)
- two one-way copy gates: insert copies VM values in, read allocates
fresh VM values out -- no VM pointer in a slab, no slab pointer in
the VM, proven by mutating originals after insert
- id discipline: per table per shard, S+1 step N; owner = (id-1) % N;
N-parametric, runs at N=1 until iteration 8, tested at N=3
- choke points: wo_row_insert/wo_row_remove carry the INDEX HOOK
sites Task 4 attaches to; nothing else mutates storage
- runtime/Makefile links database/src into every wovm + test binary
- test_table 827/0 ASan+UBSan; oop-e2e 71/0; log-watcher 7/0;
binding doc docs/plan/oop-vm/04-db-binding.md; CODE-LOGIC.md beside
the code; plan Task 1 checked off
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 9b spec gains section 6 "Ownership, borrows, and GC across the
engine boundary": two one-way copy gates (no VM pointer enters a
row, everything a select returns is copied out), so the collector
never traces engine memory and the engine never touches refcounts
- row views are borrows WITHOUT a runtime net: rows share the VM's
field encoding but not its header, so no borrow word backs them --
the compile-time escape rule is load-bearing alone
- cursor stability settled: scans materialize their id list before
the body, row updates through the view stay legal (raise mode
updates an indexed column mid-scan and is the proving fixture),
insert/delete on a table with an open cursor is a new WO-E5xx
- GC-pause interaction recorded: collector runs between statements,
a long scan delays slices -- accepted, documented
- iteration-7b ordering constraint: GC inference must classify before
table-field validation, diagnostic names the inference reason --
noted in 7b story, iteration-9 plan constraints, 9b plan tasks
- stories 09/09b Info sections point at the analysis; 9b plan Tasks
3/5 carry the enforceable checkboxes (ASan boundary assertion)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- docs/examples/employee: Department/Employee @table classes with
@unique, [dept] and [dept, salary] indexes, ref/backlink pair;
modes seed/report/staff/raise/drop per the 9b spec section 6 —
written AHEAD of the features (sample-first, like log-watcher);
README states it does not compile on today's toolchain and links
the plans that compile toward it
- report mode is the GroupBy showcase: group-and-reduce projection
{headcount, avg, min, max} ordered by avg desc, whole-query sum
for payroll; staff proves both navigation directions + index probe;
drop proves delete restrict (trap asserted)
- engine directory decision (user, 2026-08-15): database/ is its own
top-level dir, statically linked into wovm — file structures updated
in the iteration-9 plan and the 9b plan
- gap found by writing the sample: iteration 9's subset lacks a
`delete` statement and restrict needs one — added to 9b plan Task 3
- 9b plan Task 6 notes the sample is pre-authored and authoritative
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Board renamed docs/plan/00-kanban.md -> docs/00-status.md and rebuilt: ▶ NEXT
PLAN pointer (iteration 4 — emitter, corpus, `woc build`) then six buckets —
stories, in progress, done, pending, discarded, learnings. It covered only the
Rust runtime before, so the whole OOP track was invisible. All 16 inbound refs
repointed; `Kanban:` banners renamed to `Status:`.
- New discarded.md (settled rejections with reasons: inheritance, `abstract`,
Money/SKU/Float, Dynamic/cast/macro/extern, AOT-to-C, Menhir, shared engine
state) and learnings.md (plumbed≠enforced, vacuous goldens, exit-0-wrong-
output, malloc-path ASan trick, deferred checks that never reach the VM).
- RECOVERED docs/plan/exploration/blue-green-vm/00-vision.md — gone from disk,
never committed (gitignored path), cited by five docs incl. principle 12.
Root cause was broader: all seven forward-roadmap plans in
docs/superpowers/plans/ were untracked and ignored, on one disk only. Dropped
the docs ignore rules with a do-not-re-add note; added __pycache__/*.pyc.
- Repaired broken links across docs/, 270 -> 36: fixes a regression from the
earlier reference/ -> .dev/reference/ move (relative paths at ../../ and
deeper were skipped), plus depth and reorg drift. The 36 residual point at
content that does not exist and need decisions, not paths.
- New spec docs/superpowers/specs/2026-08-10-logwatcher-gap-closure-design.md,
applied: `and`/`or` verdict row; Part 3 gains `env` (six modules), swaps
time.mono for iso/local, adds 22 bare core builtins; throw/time.mono/is cut
(0 uses in the sample). Plan 8: Task 2 gains and/or, Task 5 drops throw,
abstract+`is` task deleted, 8/9 renumber to 7/8. Plan 9 gains core builtins.
Plan 10 gains the 307 -> 0 diagnostic gate. WO-E205 re-filed unreachable-by-
design. types.ml header drops its false satisfaction-set claim. 00-code-
review.md reduced to a stub — its rival Phase 1-4 roadmap retired.
- 00-kanban.md rebuilt: ▶ NEXT PLAN pointer (iteration 4 — emitter, corpus,
`woc build`) then six buckets — stories, in progress, done, pending,
discarded, learnings. It tracked only the Rust runtime before, so the whole
OOP track (wovm shipped, woc Tasks 1-8 shipped) was invisible.
- Board now records iteration 3's known gaps instead of silently owing them:
`?T` plumbed but unenforced; E205/E201/E203/E204 dead, so structural
interface satisfaction is unchecked.
- New discarded.md — settled rejections with reasons so they are not
re-proposed: inheritance, `abstract` newtypes, Money/SKU/Float, Dynamic/cast/
macro/extern, AOT-to-C, Menhir, shared engine state, external deployer.
- RECOVERED docs/plan/exploration/blue-green-vm/00-vision.md — gone from disk,
never committed (gitignored path), cited by five docs incl. principle 12.
- Root cause was broader: all seven forward-roadmap plans in
docs/superpowers/plans/ were untracked and ignored, on one disk only. Rules
were half-fiction — 33 of 34 exploration files were already tracked, so they
swallowed only *new* files.
- Dropped the docs ignore rules (exploration, oop-vm, superpowers/plans,
examples/agent-loop, examples/mcp-think) with a do-not-re-add comment; added
__pycache__/*.pyc. `tests/` stays ignored but warns that the next plan lands
the corpus there.