writeonce/justfile
shoney.arickathil b74e13d21e feat(db): durable:false skips the WAL append and replay
Task 4 of docs/superpowers/plans/2026-08-26-table-residency.md — the first
behavioural change in the iteration.

- db.c: one predicate, `table_is_durable`, gating the three EXISTING mutation
  sites. Kept as a function rather than an inlined condition so
  database/src/CODE-LOGIC.md's "nothing else may mutate storage" claim keeps
  holding — the choke points stayed three
- the ack contract is untouched for durable tables: RAM applied, record
  staged, one commit before the ack, and a failed commit still removes the row
- replay: a log holding records for a class the image now declares volatile is
  a real migration case, not corruption. apply_record returns -2 (distinct
  from -1), wo_wal_replay_ex reports the class id, and main.c names it and
  exits 2. `wo_wal_replay` stays as the NULL wrapper, so all 156 WAL unit
  checks are untouched
- measured, not asserted: 50 inserts wrote 1500 WAL bytes into a durable
  table and ZERO into a volatile one. The file's SIZE proves nothing (it is
  fallocate'd to 1 MiB up front), so the gate measures the non-zero prefix

BUG I INTRODUCED AND CAUGHT: the mismatch message first printed the class name
with %s, but wo_str.data is `char data[]` with NO NUL terminator (obj.h) — a
buffer over-read. Now %.*s with the explicit length, and re-verified under
ASan.

New gate `just residency` (8 checks), because everything above was otherwise
a one-off manual measurement: restart behaviour, the zero-byte write path, the
mismatch refusal (exit 2, names the class, NOT reported as corruption), and
both compile-time refusals. Its own first run failed two checks for a bug in
the script rather than the feature — `woc | grep` under `set -o pipefail`
returns woc's exit 1 even when grep matches, since woc exits 1 whenever it
reports diagnostics. Captures first now, with the reason noted inline.

Also new: corpus run/table-volatile-inprocess pins that a volatile table is a
FULL table in-process — same @unique enforcement, same index probe, same query
surface. Only survival differs, and that is unobservable from inside one
process.

Gates: woc-test 557/0, 18 runtime suites 0 fail, cli_smoke OK, oop-e2e 119/0
(was 118), residency 8/0, employee 8/0, db-actor 8/0, site 21/0, ASan clean on
the new replay path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 08:23:49 +02:00

179 lines
8 KiB
Makefile

# writeonce — task runner. `just --list` shows all recipes.
# docs gate: every relative markdown link resolves, every #anchor exists.
# Report lands in docs/00-link-audit.md; this recipe is the re-check.
linkcheck:
python3 scripts/linkcheck.py .
# woc compiler front (compiler/): build the executable
woc-build:
dune build --root compiler
# woc gate: unit tests (test_diag) + golden suite (runner, WOC_BLESS=1 to update)
woc-test:
dune runtest --root compiler
# wovm (runtime/): build the plain, optimized binary — the release build,
# no sanitizer (wovm-test is the ASan-clean gate; `make -C runtime wovm-asan`
# builds a separate sanitized binary for the corpus, see oop-accept)
wovm-build:
make -C runtime wovm
# wovm gate: unit suites (both dispatch flavors: computed-goto + ISO switch
# under -DWO_ISO_C, so neither rots) + CLI smoke, all ASan+UBSan
wovm-test:
make -C runtime test
make -C runtime test-iso
bash runtime/test/cli_smoke.sh
# dist: package the toolchain as an installable, Go-style tarball —
# writeonce-<ver>-linux-amd64.tar.gz whose `writeonce/bin/` holds woc + wovm.
# The version is single-sourced from ./VERSION and asserted against both
# binaries (drift guard). See scripts/mkdist.sh.
dist:
./scripts/mkdist.sh
# deps-accept: iteration 15's gate — wo.toml [deps] + git fetch + wo.lock,
# proven against local file:// remotes built at run time (network-free):
# cold fetch, offline rebuild, lock-beats-moved-tag, --update-deps, drift/
# transitive/collision diagnostics, dep-main-never-entry, manifest shape.
deps-accept:
./scripts/deps-accept.sh
# web-app: iteration 16's gate — the whole chain at run time, network-free:
# a temp git remote from docs/examples/porch, file:// URL
# substituted into a temp copy of docs/examples/web-app, then fetch -> lock
# -> build -> serve -> the storefront matrix (auth/CRUD/@unique/FK/404/400/
# pipelining) -> SIGTERM -> WAL restart persistence.
web-app:
./scripts/web-app-accept.sh
# site: the writeonce.de tutorial (docs/examples/site) — TWO deps
# (porch + view), server-rendered pages, page matrix -> 401/edit
# -> SIGTERM -> WAL restart persistence. `just site` runs it.
site:
./scripts/site-accept.sh
# fibers: the hybrid-scheduler demo (docs/examples/fibers) — part 1 byte-
# exact budget interleave, part 2 parked-sleeper-blocks-nobody, on the
# uring AND epoll backends plus an ASan run.
fibers:
./scripts/fibers-accept.sh
# db-actor: arc stage 3's gate (docs/examples/db-actor) — worker-shard
# actors read/write the database through the transparent DB actor; WAL
# replay pair included. `just db-actor` runs it.
db-actor:
./scripts/db-actor-accept.sh
# residency: databasev2 2's gate — per-table storage. The corpus covers the
# in-process half; this covers what one process cannot see: a volatile table
# empty after restart while its durable sibling replays, volatile inserts
# writing ZERO WAL bytes (measured against the fallocate'd file's non-zero
# prefix, since its size proves nothing), the mode-mismatch startup refusal,
# and the two compile-time refusals.
residency:
./scripts/residency-accept.sh
# db-bench: iteration 22's campaign (docs/examples/db-bench) — OFF the
# fast path, minutes long: ram+durable x 1/N shards, durability legs,
# gates vs bench/baseline.json. quick = seconds, floors only.
db-bench:
./scripts/db-bench.py
db-bench-quick:
./scripts/db-bench.py --quick
# install-accept: extract the dist tarball to a temp prefix, PATH it, and prove
# `woc version` + a from-scratch project build+run (self-located wovm) + the
# wo-constraint refusal all work — the "tarball install actually works" gate.
install-accept:
./scripts/install-accept.sh
# the sample workload's own recipes live beside it (build from wo.toml,
# the acceptance test, the soak): `just log-watcher` runs the acceptance,
# `just log-watcher::build` / `::soak 60` the rest — see the module's
# justfile for what each does. This is the test the whole track exists to
# pass; the corpus below gates the individual behaviors underneath it.
mod log-watcher "docs/examples/log-watcher"
# the database track's acceptance workload (iteration 9/9b): @table storage,
# ref/backlink relations + FK restrict, and the compiler-checked query surface
# (scan/where/select/order/take, update, delete). `just employee` runs it.
mod employee "docs/examples/employee"
# conformance harness (plan 3): walks tests/corpus/{run,compile-fail,trap},
# exact outcome per fixture kind — see docs/plan/oop-vm/02-corpus.md.
# Fails loudly (and names the recipe to run) if woc or wovm isn't built.
oop-e2e:
./scripts/oop-e2e.sh
# milestone-1 acceptance gate (docs/superpowers/specs/2026-08-01-oop-compiler-vm-design.md
# "Success criteria"): the five spec criteria plus both unit gates, one
# command, in the spec's order. Fails loudly on the first failing stage,
# names the criterion, exits nonzero — a measurement that only prints is
# not a gate.
oop-accept:
#!/usr/bin/env bash
set -uo pipefail
ROOT="$(pwd)"
fail() { echo "oop-accept: FAILED -- $1" >&2; exit 1; }
WORK="$(mktemp -d "${TMPDIR:-/tmp}/oop-accept.XXXXXX")"
trap 'rm -rf "$WORK"' EXIT
echo "=== criterion 1: woc compile time, pricing subset (budget: under 100ms) ==="
dune build --root compiler || fail "criterion 1: dune build --root compiler"
WOC="$ROOT/compiler/_build/default/bin/woc"
PRICING="tests/corpus/run/pricing-containers/fixture.wo tests/corpus/run/pricing-current-price/fixture.wo tests/corpus/run/pricing-discounted/fixture.wo tests/corpus/run/pricing-text/fixture.wo tests/corpus/run/pricing-set-price-insert/fixture.wo"
N=20
total_ns=0; max_ns=0; min_ns=""
for i in $(seq 1 "$N"); do
start=$(date +%s%N)
for f in $PRICING; do
"$WOC" --emit "$f" -o "$WORK/pricing.wob" || fail "criterion 1: woc --emit $f"
done
end=$(date +%s%N)
elapsed=$((end - start))
total_ns=$((total_ns + elapsed))
[[ -z "$min_ns" || elapsed -lt min_ns ]] && min_ns=$elapsed
[[ elapsed -gt max_ns ]] && max_ns=$elapsed
done
avg_ms=$(awk -v t="$total_ns" -v n="$N" 'BEGIN{printf "%.3f", t/n/1000000}')
min_ms=$(awk -v t="$min_ns" 'BEGIN{printf "%.3f", t/1000000}')
max_ms=$(awk -v t="$max_ns" 'BEGIN{printf "%.3f", t/1000000}')
echo " woc --emit over all 5 pricing-subset fixtures, $N runs: min ${min_ms}ms avg ${avg_ms}ms max ${max_ms}ms"
[[ "$max_ns" -lt 100000000 ]] || fail "criterion 1: worst case ${max_ms}ms meets/exceeds the 100ms budget"
echo " criterion 1: MET"
echo "=== criteria 2-4: full conformance corpus under ASan (runtime/build/wovm_asan) ==="
make -C runtime wovm || fail "criteria 2-4: make -C runtime wovm"
make -C runtime wovm-asan || fail "criteria 2-4: make -C runtime wovm-asan"
cp "$ROOT/runtime/wovm" "$WORK/wovm.release"
restore_wovm() { cp "$WORK/wovm.release" "$ROOT/runtime/wovm"; }
echo " swapping runtime/wovm -> runtime/build/wovm_asan for this stage only (oop-e2e.sh has no --wovm override)"
cp "$ROOT/runtime/build/wovm_asan" "$ROOT/runtime/wovm"
if ./scripts/oop-e2e.sh; then
restore_wovm
else
restore_wovm
fail "criteria 2-4: conformance corpus failed under ASan (see output above)"
fi
echo " runtime/wovm restored to the release binary"
echo " criteria 2-4: MET"
echo "=== criterion 5: single-binary smoke (runtime/wovm, release binary) ==="
./scripts/single-binary-smoke.sh || fail "criterion 5: single-binary smoke"
echo " criterion 5: MET"
echo "=== unit gate: runtime (both dispatch flavors + cli_smoke) ==="
make -C runtime test || fail "runtime unit gate: make -C runtime test"
make -C runtime test-iso || fail "runtime unit gate: make -C runtime test-iso"
bash runtime/test/cli_smoke.sh || fail "runtime unit gate: cli_smoke"
echo " runtime unit gate: MET"
echo "=== unit gate: compiler ==="
dune runtest --root compiler || fail "compiler unit gate: dune runtest --root compiler"
echo " compiler unit gate: MET"
echo
echo "oop-accept: ALL CRITERIA MET"