Commit graph

338 commits

Author SHA1 Message Date
96af299663 docs(db2-14): the shop workload story — what an order-taking web app needs from the store (refine)
- inserted 2026-09-12 from a developer question ("would I build an
  e-commerce site on writeonce?"): the load is a non-question — a hundred
  orders a minute is under two durable writes a second against an engine
  that group-commits thousands; what the developer hits is the SHAPE of the
  query and schema surface, measured against PostgreSQL habits
- goals, each its own future slice: range queries and ordering through an
  ordered index (today's indexes are equality-only hash buckets); `skip`
  beside `take` (specced 2026-08-15, never built); group-by aggregation for
  the reports (parser accepts, types.ml refuses — owner: language track);
  composite unique, check rules, on-delete policy beside FK restrict;
  export/import and a read-only attach (databasev2 9)
- Given/When/Then per page or report of docs/examples/shop; out of scope;
  the forks left open for a brainstorm before any slice starts; progress
  and history empty — `status: pending`, `readiness: refine`

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit f33ae982c954d5478d549a6dc5f15463de43ab1b)
2026-09-15 01:16:24 +02:00
f8b470d7cf docs(db2-5): brainstormed to ready — twelve forks; the resident byte budget arrives as Phase A
- `readiness: ready`, `review_pending` (forks 1–12 settled 2026-09-10 by
  codd-shoney under autonomy; look first at the cuts — fork 4 no
  back-pressure, no cross-table shedding, no warn threshold; fork 2 the
  per-table bound is rows only; forks 3/7 the default budget)
- two independent questions: RAM for all tables is one process budget in
  bytes (`WO_DB_MB`; unset = the default, never "no budget"), breached by
  refusal — the crossing insert traps WO_T_OOM, one stderr line names the
  largest table, the budget and its source; during replay the crossing is
  exit 2. Capacity of one table is `@table(max_rows: N)` with `on_full:
  refuse | drop_oldest`; drop_oldest legal on `durable: false` only,
  oldest = smallest live id; eviction never touches a durable table
- the default is the kernel's limit minus what the process holds at boot:
  cgroup v2 memory.high/max up the ancestry, else MemAvailable, minus VmRSS
  before replay — no fraction, no invented reserve; headroom is MEASURED
  (A4 re-runs iteration 1's 64 MiB swap-off leg, refusal must precede kill)
- estimate = what the engine asked the allocator for, chunk-rounded; keys
  tables count what is resident; observed on the WO_WAL_STATS exit line
- phases A–F, progress A1–A4 / B1–B3 / D1–D2 / F1 / P1 with owners; `.wob`
  v9 carries max_rows + policy; `status: pending`, Phase A startable now

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 579199af01581ebad3d2fa5f7e208745b210e9f9)
2026-09-15 01:16:24 +02:00
15b15dbe1c docs(db2-4b): part B re-brainstormed — the async barrier on the corrected premise, ten forks
- retitled "group commit, and the async barrier"; the 2026-08-15/20/28
  banners compressed into a trail; `readiness: refine`, `review_pending`
  (forks 1–5 and 8–10 decided under autonomy 2026-09-10 by codd-shoney;
  6 and 7 keep readiness at refine)
- what part B is FOR: the read tail on shard 0 while a barrier blocks — and
  only that; mechanism: the drain pwrites as today, then submits ONE bare
  IORING_OP_FSYNC and keeps working; held replies released by the
  completion; the epoll fallback is part A unchanged; ordering with
  compaction and the deferred drops/re-points; the inline durable write on
  shard 0 unified through its own inbox while a barrier is in flight;
  completion delivery on a busy shard 0; shutdown reaps an in-flight
  barrier before wo_wal_close
- fork 6 (kernel floor and raw-syscall shape) goes to lintor; fork 7
  (go/no-go) is settled by one measurement — tmpfs vs ext4 `mixread.p99` —
  then one developer answer; both answers already sit in
  .dev/zack/databasev2-4b.md, the fold into this story is pending
- progress table B1–B9 with sizes and owners (cyril B1/B8, lintor B2, the
  runtime agent B3, codd + pm B9); no new knob, no new dependency

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 7ceb7b8805da41e67661744746bf2d0b7879cc50)
2026-09-15 01:16:24 +02:00
54b160070f docs(db2-keys): databasev2 13 story — fresh-log keys-resident seed SEGV, fixed 6310078 + 1b6750d
- symptom: `seed` of docs/examples/residency on a FRESH log, rc 139, in both
  WO_DATA forms — found smoke-testing databasev2 7, independent of it
- root cause, two defects composing: wo_wal_fold_row_at wrote `*msg`
  unguarded while wo_idx_probe borrows with msg = NULL; and the databasev2 12
  schema head was staged lazily AFTER db.c captured the first keys-resident
  row's offset (`koff`), so that offset pointed at the schema record
- fix (already on dev, prefix db2-keys): wo_wal_next_offset stages the
  pending head before returning an offset; the fold tolerates a NULL msg;
  both failing-first, and a control build with wal.c reverted reproduces
  the trace
- third finding: residency-accept.sh never checked seed's rc, so 20/0 was
  green over a crash — `e274f4a`; the gate is 32/0 since
- `residency.keys.fit` rc 74 confirmed a SEPARATE defect (compaction/replay
  of keys-resident offsets), still open under codd.md "Next bugs"
- `status: done`, `readiness: ready`; counts test_wal 6629 → 6660,
  make -C runtime test 8462/0 at the time of the fix

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit b5b1da795917f0446a1e4a0317d9136c33acb262)
2026-09-15 01:16:24 +02:00
9b5498fafe docs(db2-7): story closeout — acceptance met per task, progress table, WO_DATA is always a path
- frontmatter `status: done`, `readiness: ready`, `review_pending` (the
  nonexistent-path rule settled under autonomy 2026-09-10)
- every criterion met with its evidence: task 1 smokes A–D (`b31bd40`),
  residency section 8 checks i–vii (`aaea6b2`), db-bench `--wo-data-file`
  181 checks / 5 failures — the same 5 as the directory form
  (`residency.keys.fit` rc 74, databasev2 13's sibling, not this defect),
  temps-beside-the-log test plus its mutation control (`ccee2d0`)
- the fork, settled: existing dir or trailing `/` → <dir>/shard-0.wal,
  byte-identical; otherwise the path IS the log, created behind an existing
  parent; a missing parent or a non-regular non-directory path refuses,
  exit 2, naming path and parent — never a silent mkdir -p
- `WO_DATA` stays a path: ephemerality is WO_EPHEMERAL=1 (databasev2 2 task
  6a), so the file-vs-directory parse carries no `:memory:` sentinel
- progress table with the four hashes; history

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 38f4f1e5832e79b9834a93fd6c3273fefe5eeadc)
2026-09-15 01:16:24 +02:00
79352bd95c docs(agents): the persona roster — codd/fielding/ada families, lintor, README
- database-developer becomes `codd`: scope is the whole embedded DB (engine,
  runtime seams, the compiler's @table/query surface); doctrine rewritten
  from what landed (fatal commit, group commit per drain, checkpoint by
  rename, delta fold, schema head, v8 table bit, no-WO_DATA refusal); file
  map with anchors; state as of 2026-09-11; architect only — no gates, no
  tests, names the checks for cyril and the tasks for zack
- one four-role pattern shared by three tracks: `<architect>` brainstorms
  and owns contracts, `-zack` implements ONE ready iteration with a
  resume-safe ledger under .dev/zack/, `-cyril` owns every test above unit
  level and the gate ladder, `-pm` keeps stories, board and graph truthful
  (`model: sonnet`); families codd (database), fielding (porch), ada (jarvis)
- `codd-shoney` is the developer's proxy: brainstorms `refine` stories to
  `ready`, reviews `review_pending` forks; `lintor` the kernel consultant
  over .dev/reference/linux
- README: roster (reads, gates), the families rule, proposed agents not yet
  written and the order to add them
- docs/guides/codd-subagent.md, 00-doc-audit.md, 08-project-structure.md
  follow the rename

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 830bbb16d5dd990478149678c642857bb65466f4)
2026-09-15 01:16:24 +02:00
7acd085f46 test(db2-chains): the oracle closes databasev2 11's last criterion — keys vs all across 3×K flattenings and a replay
- test_oracle_all_vs_keys_same_update_sequence continues the shared
  sequence 3×WO_DELTA_MAX_HOPS steps, alternating scalar and Text, and
  asserts the `resident: all` and `resident: keys` rows equal after EVERY
  step; the fold's hop count proves the chain terminated at least twice and
  never exceeded K; then the keys log replays into a fresh store and is
  compared against the oracle once more — the criterion as written, which
  the story carried as ⚠ "an expected value, not an oracle table"
- wal.h: wo_wal_append_row_image's comment claimed the flattened image is
  written as WO_WAL_INSERT; it is WO_WAL_UPDATE — an INSERT would replay as
  a duplicate id; compaction alone writes INSERT, into a FRESH log — as 11
  landed it and its story recorded
- story 11: the criterion flips to ✅ naming the test; the sequencing note
  and out-of-scope bullet record task 7's 2026-08-30 measurement (16× vs
  105× collapse under a cap, 1.53× faster than swapping) — the work stands
- test_wal 6295 → 6880 pass, 0 fail; 21 runtime suites 0 fail

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit d841390f3087a0c2542ddf23f25f15037a7d4d71)
2026-09-15 01:16:24 +02:00
296efb52ed docs(db2-ephemeral): databasev2 2 closes — task 6a contract, forks 1–7, the README sweep
- story 02: `status: done`, `review_pending` (forks 1–7 auto-approved for
  autonomy); progress rows 6a ✅, 6b ➡ databasev2 5 Phase A, 7 `a310496`;
  5c/5d rows cite the `dev` hashes (the pre-merge ones were unreachable);
  task 6a's Given/When/Then met; Info records the seven forks (sentinel over
  `:memory:`, its rules, the refusal contract, startup-only, the budget
  leaves for 5, library-owned tables bind consumers, the v8 table bit);
  History keeps the first cut that refused every class-bearing program
- database/src/CODE-LOGIC.md: "Startup refusal + WO_EPHEMERAL" — contract,
  hatch, table bit, measured blast radius, deferred items, proof; the
  dispatcher paragraph no longer says a failed commit un-applies the row
  (fatal since databasev2 4 part A; WO_T_IO unreachable from a write path)
- residency spec + plan: task 6 items annotated with the 2026-09-09
  decisions; the byte budget marked moved to databasev2 5
- README, seven example READMEs and four guides carry the one-line rule
  (durable default refuses without WO_DATA; WO_EPHEMERAL=1; durable:
  false); shop's RAM-only command sets the sentinel

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 2c3531998124042fe736388e8b926abda3841194)
2026-09-15 01:16:24 +02:00
d38b4f864b feat(db2-ephemeral): refuse a durable table without WO_DATA; WO_EPHEMERAL=1 opts out; .wob v8 table bit
- main.c, startup only: WO_DATA unset and a class carrying WO_CLASSF_TABLE
  without WO_CLASSF_VOLATILE (`durable: true`, the default) refuses — exit 2,
  one stderr line naming the class and the three ways forward (WO_DATA=<dir
  or file>, WO_EPHEMERAL=1, @table(durable: false)); before, every write
  was silently dropped at exit — the one outcome `durable: true` forbids
- WO_EPHEMERAL=1 (exact value) is the whole-program escape: one boot notice,
  rc 0, the RAM path byte-for-byte the old one (db.c untouched); any other
  value refuses; set alongside WO_DATA refuses regardless of tables; the
  `resident: keys` loop still wins and is not rescued
- .wob v8: WO_CLASSF_TABLE 0x08 (WO_CLASSF_ALL 0x0f), set from emit.ml's
  cr_is_table — the first cut keyed on !VOLATILE and refused every
  class-bearing program (fibers' Tick, subprocess's ConnMsg), because v7
  spelled `durable: true` as the mere absence of a bit
- loader refuses VOLATILE/RESIDENT_KEYS without the table bit ("storage
  flags on a class that is not a @table"); a v7 image is refused by the
  exact-match version check, as v7 refused v6; disasm prints `table`;
  runner.ml's independent validator carries both rules; obj.h comment
- test_loader: test_storage_flags_need_table (forged flags word: both
  refusals, and the same bits WITH the table bit load); no golden moved
- contract: docs/plan/oop-vm/00-wob-format.md "v8: the table bit"

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 863692a590d426da0047831ae315142ef5b24416)
2026-09-15 01:16:13 +02:00
0435bd96f5 docs(commit-history): claim prefixes db2-ephemeral, db2-4b, db2-5, db2-14, agents, status
- registry rows for the prefixes this landing uses, claimed before their
  first commit as the file requires: `db2-ephemeral` (databasev2 2 task 6a),
  `db2-4b` (part B re-brainstorm), `db2-5` and `db2-14` (story docs),
  `agents` (the persona roster), `status` (cross-track board/graph sweeps)
- `db2-7` and `lang-18` registered after the fact — both already have
  commits on `dev` (`b31bd40`, `6b4b960`) and had no row

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit d0e658f06df8f3390d56841bdb4093cb8d509fb8)
2026-09-15 01:16:13 +02:00
58dcb1f969 test(db2-7): gate leg for WO_DATA=<file> — residency section 8, db-bench --wo-data-file
- residency-accept.sh section 8 (11 checks): file-form seed -> restart prints
  the directory form's line; `find -mindepth 1` shows exactly app.db; missing
  parent exits 2 naming path + parent, no mkdir -p; a fifo exits 2 "neither a
  regular file nor a directory"; `d/` still writes d/shard-0.wal; `nodir/`
  keeps the pre-7 "cannot open .../nodir//shard-0.wal" bytes; WO_EPHEMERAL=1
  with the file exits 2 on the 6a conflict
- kill -9 battery against app.db: stdbuf -oL vehicle, asserts the kill landed
  (rc 137) before verifying every acked row replays; forced compaction
  (WO_CHECKPOINT_BYTES=1, WO_WAL_STATS proves >= 1 ran) leaves app.db the only
  artifact and every row replays
- failing-first on the pre-7 wovm: 9 of 12 new checks red ("cannot open
  .../app.db/shard-0.wal"); the two trailing-slash pins and the 6a conflict
  pass by construction — they pin what must stay byte-identical
- db-bench.py --wo-data-file: restart proof + crash battery against
  <tmp>/app.db, legs tagged .file, file form also asserts app.db is the only
  artifact; no metric, bench/baseline.json untouched; quick run unchanged
  without the flag (181 checks / 5 failures both ways, all five the known
  residency.keys.fit rc 74)
- READMEs: db-bench env-knob row for WO_DATA=<path>.db + the driver flag;
  residency run instructions name the file form
- gates: just residency 32/1 (the seed rc, pre-existing), make -C runtime
  test 21 suites 8452/0, just oop-e2e 129/0

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit aaea6b2c0f818efd0cdf472ccbd9bdd09eac5554)
2026-09-15 01:16:13 +02:00
ea66761c4e docs(db2-7): contract + CODE-LOGIC — the WO_DATA file form
- docs/plan/oop-vm/04-db-binding.md, WAL section, "Where the log lives":
  WO_DATA is always a path; directory form (existing dir or trailing `/`
  → `<dir>/shard-0.wal`, pre-7 bytes incl. the `//`), file form (the path
  IS the log, created only under an existing parent), the two refusal
  lines verbatim, too-long refused not truncated, one file at any core
  count, compaction/migration temps + parent fsync derived from the log
  path never from WO_DATA, the two pinning tests named.
- database/src/CODE-LOGIC.md, `wal.c — durability`: the resolver's three
  codes and main.c's wording, why no mkdir -p, trailing slash on a missing
  dir kept as the pre-7 `cannot open` on purpose, `parent_dir_of` shared
  by the boot check and the post-rename fsync.
- Both paragraphs sit in regions untouched by the uncommitted 6a/12 doc
  work in the same files; no other docs touched (story/board are pm's).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit f1985bae5d110ed773159393bd82c32b73bfb672)
2026-09-15 01:16:13 +02:00
82efb498d4 fix(compiler): lang-41 side defects — ?T-typed nil try, WO-E305 on moves out of a field
- emit.ml: a `try … catch (e) nil` is `?T` (ty_of_expr) and the nil arm takes that destination, so a `?Int` nil is WO_NIL_SCALAR and an Int body's legitimate 0 no longer reads as nil (it used to fall back to the zero word via the body type / enclosing return type)
- owner.ml: `transfer` on a projection (`d.tags`, `x[i]`) of an owned value reports WO-E305 instead of returning false silently — the silent path compiled `Out { tags: d.tags }` to an alias that both records dropped (the "json.decode as T corruption": not json's, a double free language 44's poison now aborts on); heap scalars exempt (store sites copy)
- error catalog: WO-E305 row; owner.ml module doc updated
- corpus: run/try-nil-int-zero, compile-fail/no-partial-move, run/decode-record-crosses-return (Text copied, record moved whole — the archived `.. ""` workaround is unnecessary)
- verified: oop-e2e 126/0, tests/regress/lang-41 compile, --emit sweep over the non-porch examples, web-app gate 56/0 (porch in project mode) — no legitimate program trips WO-E305
- story 41: both side defects marked fixed; board prose updated

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 2d54710e693fafee4b8d6561cc9cba7b95415d89)
2026-09-15 01:16:13 +02:00
dd426d0581 test(tls): rv2 8 phase E — both AEADs cross-checked against openssl over the wire
- tls-server-accept.sh: each probe pins openssl s_client's -ciphersuites — ec/ChaCha20-Poly1305, rsa/AES-128-GCM, plus openssl's default list whose first suite (AES-256-GCM) the server must skip — 5/0
- tls-accept.sh: the Python/OpenSSL stub prints the negotiated suite; the happy-path ok line carries it — 5/0 (ChaCha under the peer's server-preference default)
- rv2 8 story: E landed (real-protocol interop replaces the infeasible `openssl enc` AEAD check); D (encrypted-cookie wrapper) re-homed to porch as the consumer's phase after porch 2 — fork auto-approved, review_pending; status: done
- porch 2: the encrypted-cookie out-of-scope bullet now points at the landed primitives and names the wrapper as its follow-on
- board row rv2 8: in-progress -> done

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit ac3bf74da4f45f624d7d3b440c8bcf17f4aec3a9)
2026-09-15 01:16:13 +02:00
e1b9ada190 docs(rv2-obs): rv2 7 observability brainstormed to ready
- four forks settled with KISS defaults grounded in runtime/src: counters+gauges only (profiling split out), Prometheus text rendered in .wo from a map<Text, Int>, pull via proc.metrics(), stack trace on trap lands first
- phases A (trace on trap at both trap sites) / B (proc.metrics from existing gc/arena/fiber fields) / C (porch mounts /metrics — consumer's phase)
- builtin id to be confirmed against WO_B_MAX at build time (random_bytes claims 119 per porch 2's brief)
- review_pending marker: forks auto-approved 2026-09-09, developer second review before code lands
- board row: refine -> ready

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit feb11c3aad613ed7f41b280b27c1f6c0dda92ec7)
2026-09-15 01:16:13 +02:00
ed45ac7c06 fix(arena): poison-on-free — a freed block can never pass for a live object (language 44)
- wo_arena_free stamps the header: class_id = WO_CLS_FREED (0xFFFFFFFF), shard_id = 0xFFFF, flags/pad = 0
- freelist link moves from offset 0 to offset 8 so the poison survives on the list; wo_arena_alloc pops from offset 8
- wo_drop_obj aborts first on a poisoned header: a double free is a diagnostic, not a catchable state
- WO_CLS_FREED defined in wob.h beside the builtin id space
- test_arena: test_poison_on_free (poison stamped, LIFO chain through the relocated link, class drains to a fresh bump) — 17/0
- full suite SUITE_ALL_ZERO, wovm + wovm_asan rebuilt, just db-actor 10/0 (lang-41 5x marshal gate unchanged)
- story 44 status: done; board row + dependency graph L44 (41 -.follow-up.-> 44)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 78ae3be403ba533db6f0e181bff201717f789a30)
2026-09-15 01:16:13 +02:00
3b1a188d77 fix(crypto): branch-free EC signing ladder via complete addition (rv2 9 follow-up)
- pmul_ct: double-and-add-always over the Renes–Costello–Batina complete
  projective addition formula (Alg. 4, a=-3) — one exception-free formula for
  add and double, identity (0:1:0), so there is NO point-at-infinity branch.
  Closes the documented residual: the Jacobian jadd/jdouble ladder's fp_zero
  checks leaked k's leading-zero count (a bit-length hint) during ECDSA sign
- wo_ecdsa_p256_sha256_sign uses it; affine x = X * Z^-1 (projective), the
  inversion via the constant-time modexp. Dead Jacobian jmul_ct/jpt_cmov removed
- RFC 6979 A.2.5 vectors still byte-exact (test_crypto 130/0); server loopback
  (signs with this ladder) still green (test_tls 123/0); ASan/UBSan clean
- docs: rv2 9 review_pending — close_notify + complete-formula ladder moved
  from deferred to landed; lang-41 decision 4 fixture marked landed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit fba30352b965e0f3b749168421a920a832df541b)
2026-09-15 01:16:13 +02:00
ad1ad8361c docs(audit): fix stale docs against the code (TLS, net.connect, RNG, lang-41); jarvis deps
Code is the source of truth; these claims no longer matched runtime/src:

- "net.connect does not exist" — landed 2026-09-07 (id 110); net.connect_tls /
  read_tls / write_tls (115-117) + net.accept_tls (118), WO_B_MAX 118. Fixed
  in jarvis 00-story (problem statement + architecture + out-of-scope), porch
  00-story (proxy middleware row), rv2 7 (push-collector fork), 00-code-review
- "TLS: none / proxy-mandated forever" — retired by rv2 9 (in-process TLS both
  directions). Fixed in porch + web-app + site example READMEs (proxy is now a
  deployment choice; HSTS row), 00-code-review
- "no RNG anywhere in the runtime" — imprecise: the runtime has a getrandom(2)
  source since rv2 9 (TLS ephemerals), but nothing exposes it to .wo yet.
  Fixed in CODE-LOGIC (digests), lang 34, porch 2, status lang-39 row
- "porch 9 blocked on language 41" — lang 41 fixed 63065ff. Fixed in porch 1,
  jarvis 00-story, status NEXT PLAN, dependency graph (L41 done, P9 ready)
- dependency graph §7 rewritten: the runtime side is done; jarvis 1 waits only
  on porch (developer's porch-first order). Adds jarvis 1's dependency table +
  the build order that satisfies it
- 00-code-review: a dated 2026-09-09 re-verification appended (record kept)
- site README lives in the writeonce-site submodule: committed there, pointer
  bumped here

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit f1049dd9b7c7770da28bcabfc1cb1324621e7ee6)
2026-09-15 01:16:13 +02:00
00214bd68e fix(vm): marshal cross-shard actor messages (language 41) — the double free
Root cause (decision 1): cross-shard send/call/monitor pointer-shared the
message into the receiver's shard (e->payload = msg_val), so a worker read and
eventually dropped an object living in the sender's arena — a double free, then
a class-0 forge, then a modulo self-route livelock, all downstream of that one
broken invariant ("VM heaps are never read cross-shard", which wo_db_rpc keeps).

- actor_marshal: the sender encodes the message into an arena-independent neutral
  form (wo_db_val_encode, the same marshal wo_db_rpc uses) and drops its own
  original — no pointer crosses an arena boundary, so the double-free class is
  gone by construction. actor_unmarshal rebuilds it in the receiver's arena
  (wo_val_decode_vm) and frees the neutral. Applied to the 4 cross-shard
  producers (send x2, call, monitor) + the 3 consumers (kinds 0/5/7). Same-shard
  paths untouched (the WO_SHARDS=1 fast path never failed). Call replies are
  scalars by contract, so kind 6 needs no marshal.
- eng_settle_inboxes: undrained kind-0/5/7 payloads at teardown are the neutral
  form now — free with wo_db_val_free, not wo_drop_obj (caught by ASan mid-fix).
- decision 2: wo_route_free traps a shard_id >= nshards header (a corrupt/freed
  block) instead of self-routing it into the settle livelock.
- proof: tests/regress/lang-41/cross-shard-marshal.wo (a multi<Text> sent +
  called cross-shard, both sides drop) — clean 12x/5x under WO_SHARDS=4 + ASan;
  shard-settle repro still clean 8x; full runtime suite 0 fail (same-shard
  byte-unchanged). `just db-actor` extended with the new fixture.
- unblocks porch 9. Follow-ups: poison-on-free (decision 3), corpus fixture (4).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 63065ff75799f7f43b2bce6de61e77856799566f)
2026-09-15 01:16:13 +02:00
8992dbd589 docs(rv2-tls): rv2 9 COMPLETE (both directions); retire proxy doctrine; jarvis-after-porch
- rv2 9 story -> status: done. §G G3 landed; ladder A–G complete, live-gated
  both directions (just tls 5/0, just tls-server 4/0). review_pending +
  phase rows + G sub-phases updated
- doctrine retired where the story named it: language 34 ("TLS permanently
  the proxy's job"), language 38 ("proxy-terminated ... no HTTPS clients"),
  porch 00-story ("TLS ... proxy-terminated") — each corrected to point at
  in-process TLS (net.connect_tls / net.accept_tls)
- status board: rv2 9 row DONE + a top summary; NEXT PLAN = porch then
  jarvis (sequencing set: jarvis follows porch)
- jarvis 00-story: sequencing note (no longer runtime-blocked; porch first)
- CODE-LOGIC: the inbound-server section (net.accept_tls, signing, slot
  refactor, RST-drain, gate)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit f3a3c962e5f288c25e505851edef4e0a5df9a85f)
2026-09-15 01:16:13 +02:00
e1d29d63e4 feat(tls): net.accept_tls — inbound TLS 1.3 termination (rv2 9 phase G3)
- net.accept_tls(listener, certfile, keyfile) -> Int (id 118, WO_B_MAX->118):
  accept (parks like net.accept), load+cache the server identity per path in
  the shard, run the blocking deadline-bounded server handshake, return a TLS
  conn fd. Real clients terminate against the runtime — no front proxy
- wo_tls_conn refactored: holds the negotiated application keys (not an
  embedded driver), so read_tls/write_tls serve both client and server
  connections via the record layer; the handshake drivers are transient
  (heap, ~100KB, freed after). net.close drains a TLS conn's inbound before
  close() so it sends FIN not RST (clients send close_notify)
- server handshake loops past the client's change_cipher_spec (TLS 1.3
  middlebox-compat) before its Finished — the openssl-interop fix
- private-key file loading: wo_tls_pem_one (any-label PEM block) +
  wo_pkey_parse; per-shard identity cache (vm->tls_id), freed in reap
- docs/examples/tls-server + `just tls-server`: openssl s_client validates
  our hand-rolled server (EC + RSA certs) and gets the reply — 4/0; the
  outbound `just tls` gate stays 5/0 through the refactor
- wiring: wob.h, loader.c, builtin.c dispatch, types.ml, vm.h

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 2d4c30033c36c88de5b7ab7cc1042c9537238297)
2026-09-15 01:16:13 +02:00
18e0e6992b docs(rv2-tls): phase G2 server FSM landed
§G sub-phase G2: the sans-io server handshake FSM (wo_tls_server) landed,
loopback-KAT'd against the client driver (EC + RSA identities, app
round-trip). Remaining G3: net.accept_tls + private-key parse + live gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 57613bddc621a90970d9443ae5a5deacffe0cfca)
2026-09-15 01:15:52 +02:00
cd779afa7f docs(rv2-tls): phase G1 signing landed (RSA-PSS + ECDSA-P256)
§G sub-phase G1: constant-time RSA-PSS + ECDSA-P256 signing landed and
KAT'd (RSA vs python from-spec; ECDSA vs RFC 6979 A.2.5). Remaining G1c
(private-key PEM/DER parse) folded into G3 (which reads key files); the
server FSM takes raw key material.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit f02518cdabab02043a04c6bdd28a81b86bb9fbd4)
2026-09-15 01:15:52 +02:00
82446652e4 docs(rv2-tls): brainstorm phase G (inbound TLS server) to ready
- §G written to READY (forks auto-approved, review_pending): the inbound
  server rung. Grounds what's reused (record layer, role-symmetric key
  schedule, X.509, slot table + data plane) vs new (server FSM, signing,
  key parsing, accept surface)
- six locked decisions: (1) constant-time private-key ops — the built
  modexp/scalar-mult are verify-only, not constant-time, so G adds a
  constant-time fixed-window modexp + Montgomery-ladder scalar mult;
  (2) both RSA-PSS + ECDSA-P256 server keys; (3) deterministic RFC 6979
  ECDSA nonce; (4) net.accept_tls(listener,cert,key) w/ per-path shard
  identity cache; (5) full 1-RTT server-auth only (no mTLS/resumption/HRR);
  (6) sans-io wo_tls_server FSM
- sub-phases G1 signing+key-parse, G2 server FSM (loopback KAT), G3
  net.accept_tls + live gate (openssl s_client); acceptance + out-of-scope
- ladder G row -> READY; may become its own runtime-v2 iteration

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 9fcb4a96a137a897f0ce2be868c18e63a979c997)
2026-09-15 01:15:52 +02:00
cf31bb4ebd docs(rv2-tls,jarvis,status): outbound TLS client complete — jarvis unblocked
- rv2 9 §F3c-net marked LANDED + live-gated; phase-F row COMPLETE (client);
  frontmatter review_pending updated (client complete, remaining = G server
  + deferred park-handshake/TlsConn/pooling + doctrine-doc corrections)
- jarvis 00-story + 01: the outbound-TLS blocker is cleared
  (net.connect_tls landed) — jarvis 1 (chat loop) is now buildable
- status board: rv2 9 row + NEXT PLAN rewritten to the completed client;
  next step is jarvis 1 or rv2 9 G

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 732c2216b501dd226d306f9abcbd1ddd846809dc)
2026-09-15 01:15:52 +02:00
72ed35773d test(tls): live acceptance gate for net.connect_tls (rv2 9 F3c-net phase 4)
- docs/examples/tls-client/main.wo: an outbound HTTPS client in .wo —
  net.connect_tls, write_tls a request, read_tls to EOF, print; connect
  failure caught with try/catch and reported (never a silent downgrade)
- scripts/tls-accept.sh + `just tls`: dials a local TLS 1.3 stub (python
  ssl, TLS1.3-only) with a generated test CA — proves the hand-rolled
  handshake + chain/host validation + an app round-trip end to end from
  .wo through the compiler, and refuses the untrusted-chain and
  hostname-mismatch negatives. No live network; log /tmp/tls.log
- gate: 5 checks, 0 failures

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 3d8bb140ec478167a4e660adf2caa964ff410ff1)
2026-09-15 01:15:52 +02:00
53485a748c docs(rv2-tls): lock two more F3c-net requirements from the gofiber/Go comparison
Compared §F3c-net's forks against gofiber v3's client (fasthttp + Go
crypto/tls/x509, .dev/reference/fiber). Two gaps my defaults had vs Go,
now locked as decisions 5 and 6:

- (5) bounded handshake deadline: the blocking model would let a stalled
  server hang the shard's one thread indefinitely (the DoS DoTimeout
  closes). connect_tls now bounds connect+handshake via non-blocking
  connect+poll + SO_RCVTIMEO/SNDTIMEO, default WO_TLS_HANDSHAKE_MS
  (10s); expiry traps WO_T_IO. _dl variant + park handshake stay follow-ups
- (6) chain hardening: signatures+validity+SAN alone let a leaf act as a
  CA. Now every non-leaf must assert basicConstraints CA:TRUE (+pathLen)
  and the leaf must carry EKU serverAuth — what Go's crypto/x509 enforces
- acceptance criteria added (stalled-server timeout; leaf-as-CA + no-EKU
  rejected); connect_tls bullet, frontmatter review_pending, status NEXT
  PLAN updated to six locked forks

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 9662cd8b040f417b4886dae9ce97b70083e24e40)
2026-09-15 01:15:31 +02:00
f1e355c4d4 docs(rv2-tls): brainstorm §F3c-net to ready — four integration forks locked
- §F3c-net rewritten to READY (decisions locked 2026-09-09), grounded in
  the runtime not assumed:
  1. blocking connect+handshake then park the data plane (mirrors
     net.connect's own "tolerable while rare" stance); park-based
     handshake a named follow-up
  2. per-shard fd-keyed wo_tls_conn slot table, no locks (the wo_child /
     one-thread-per-shard pattern); slot holds driver state + partial-record
     + leftover-plaintext buffers
  3. failures trap WO_T_IO loudly incl. chain + hostname (no silent nil)
  4. per-shard lazy read-only CA bundle (/etc/ssl/certs, WO_CA_BUNDLE)
- builtin surface: net.connect_tls/read_tls/write_tls (ids 115-117,
  WO_B_MAX->117), acceptance criteria (incl. concurrent-shard TSan),
  out-of-scope (park handshake, TlsConn object, HTTP layer, inbound G)
- frontmatter review_pending + phase-F row + status NEXT PLAN updated:
  F3c-net spec ready, next action is BUILD (live-gated)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 8b6e72171c5db9dfe5b7a5122be123bf7cc3cdd9)
2026-09-15 01:15:31 +02:00
2391553658 docs(rv2-tls,status): F3c-net plan + net.connect_tls object-model default; session NEXT PLAN
- rv2 9 §F3c-net: the remaining live-gated slice with auto-approved
  defaults — getrandom ephemeral, system CA-bundle loader, net.connect_tls
  builtin returning the TCP fd (fd-keyed side table, blocking model like
  net.connect) driving the sans-io driver, then wo_tls_verify_chain; plus
  net.read_tls/write_tls and a live gate
- status board NEXT PLAN: the TLS client security engine landed this
  session (E-F3c minus socket glue), F3c-net is the next rung, then jarvis

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit ad87974fc722268e278f957f1f3d607f5dafa50d)
2026-09-15 01:15:31 +02:00
ad088163cc docs(rv2-tls,jarvis): TLS ladder through F3c-core + SAN landed
- rv2 9 phase-F row + review_pending: F3c-core sans-io driver + SAN/host
  landed (KAT'd vs RFC 8448 record trace); remaining F3c-net = system CA
  trust-anchor walk + net.connect_tls VM plumbing (live-gated), then G
- jarvis 00-story + 01 blocker tables: crypto/handshake engine landed;
  jarvis now waits only on net.connect_tls (the socket glue)
- status board rv2 9 row updated to the full ladder state

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 4fdf07196d01c32d0ab12d32d36fa4285ff34654)
2026-09-15 01:15:31 +02:00
c84d33c9ba docs(rv2-tls): rv2 9 phase F1-F3b landed (record, key schedule, messages, offline verify)
- phase-F row: F1 record layer, F2 key schedule, F3a message layer,
  F3b offline handshake verification all landed + KAT'd (RFC 8448 /
  real certs); F3c socket FSM + net.connect_tls plumbing remaining
- review_pending updated to the current ladder state

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit d49bc3866b6b620d00a8a57137ba211da25cd05b)
2026-09-15 01:15:31 +02:00
bb64278aa9 docs(rv2-tls): rv2 9 phase E (X.509 core) landed
- phase-E ladder row: core landed (DER reader + cert parse + verify_one
  + parse_spki + check_validity), KAT'd on real RSA + EC chains
- review_pending frontmatter: forks auto-approved 2026-09-08, SAN/
  hostname + CA-bundle walk deferred to phase F

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
EOF2
git log --oneline -2

(cherry picked from commit 796ed88d76f1cf25ced1eb5e7bdb4e4ab3cf4e9b)
2026-09-15 01:15:31 +02:00
9d1689be55 docs(jarvis): create iteration stories 1 (ready) + 2/3 (refine)
- jarvis 1 (chat loop) brainstormed to ready with forks AUTO-APPROVED for
  autonomous execution and flagged in `review_pending` frontmatter for the
  developer's second review: Anthropic Messages API backend, env-var API key,
  actor-per-conversation SSE relay, durable @table history, session-gated routes
- jarvis 2 (tool use) + 3 (retrieval/RAG) created at refine with forks named
- 00-story iterations table linked to the new files
- blocked until rv2 9 TLS reaches phase F; pure .wo on porch 2/3/6/7 + the seam

(cherry picked from commit 8e160c3fcf9c50a05af073c036c693b192c9e595)
2026-09-15 01:15:31 +02:00
ca572086ee docs(rv2-tls): rv2 9 phase D complete (RSA + ECDSA-P256 verify)
- ECDSA-P256 verify landed; phase D done (both signature verifiers)
- rv2 9 story, board ladder, jarvis 00-story deps, and dependency-graph §7
  synced: A-D landed, E-F remain

(cherry picked from commit 3eab98cc268e524c7b4e2ab72a4b093692a67d03)
2026-09-15 01:15:31 +02:00
4e70509001 docs(rv2-tls): rv2 9 phase D part 1 (RSA verify) landed
- RSA PKCS#1 v1.5 + PSS verify over SHA-256, bignum Montgomery modexp,
  KAT-gated vs python RSA-2048. ECDSA-P256 (D2) remains. Board synced

(cherry picked from commit ae42943c97949224d883e9ddcf5ae2117fef62b3)
2026-09-15 01:15:31 +02:00
d02befd6bf docs(jarvis): sync jarvis dependencies to landed state + dependency graph
- jarvis 00-story: net.connect marked landed (id 110); outbound-TLS blocker
  now rv2 9 in-progress (A AEAD / B HKDF / C X25519 done; D-G remain);
  architecture + blocker table updated
- dependency-graph: new §7 jarvis dependency graph (phase-level TLS ladder +
  porch framework path); §5a net.connect node marked landed

(cherry picked from commit a615ee80238fb384c0b33fc2b54bcd6bd4078078)
2026-09-15 01:15:31 +02:00
8e652800fe docs(rv2-tls): rv2 9 phase C (X25519) landed
- constant-time X25519 (RFC 7748), curve25519-donna radix-2^51; KAT-gated incl.
  the 1000-iteration vector. Ladder A+B+C done; next D. Board synced

(cherry picked from commit b929a20b7482d7137a45b77a2179fe7ef03c52b6)
2026-09-15 01:15:31 +02:00
aff8ffdf14 docs(rv2-tls): rv2 9 phase B (HKDF key schedule) landed
- HKDF-Extract/Expand + Expand-Label over hmac_sha256, KAT-gated (RFC 5869 +
  8446); status -> in-progress; ladder A+B done. Board synced

(cherry picked from commit e24b8ec6d838fc66848864c2a0974205aaa9b4be)
2026-09-15 01:15:31 +02:00
2db3766b66 docs(rv2-aead): rv2 8 phase C (software AES-GCM fallback) landed
- portable constant-time AES-GCM software path; AES-GCM now on any CPU
  (hw-or-sw dispatch), NIST-KAT-gated both paths (48/0). Remaining D/E;
  ARMv8 hw path deferred. Board synced

(cherry picked from commit 138de17988e6bd274abe5e1e2d444ff2689747cd)
2026-09-15 01:15:31 +02:00
6a38ad7cb0 docs(rv2-aead): rv2 8 phase B (AES-GCM) landed
- phases A + B done; B = AES-128/256-GCM via AES-NI/PCLMULQDQ, NIST-KAT-gated,
  ASan clean, portable binary (CPUID-gated). Phase C now owns the software
  fallback AND the ARMv8 hardware path (deferred, untestable on x86-64 host)

(cherry picked from commit 249b1dbd72122ed6c05f4f0aadb7e1a5e87f844c)
2026-09-15 01:15:31 +02:00
da840a5be6 docs(rv2-aead): rv2 8 phase A (ChaCha20-Poly1305) landed
- status -> in-progress; phase A marked landed (matches RFC 8439 §2.8.2,
  KAT-gated in test_crypto, ASan clean). Remaining B/C/D/E. Board synced

(cherry picked from commit db5bdf3c3cac31c0d2be60027e0e2bf9fe8309c1)
2026-09-15 01:15:31 +02:00
7f7a601e2f docs(rv2-aead): brainstorm runtime-v2 8 (AEAD ciphers) to ready
- a second consumer (rv2 9 TLS phase A) reshaped the forks since the draft
- locked: BOTH AES-GCM (128/256, TLS-mandatory per RFC 8446) AND
  ChaCha20-Poly1305 (RFC 8439, easy constant-time, cookie default)
- AES constant-time via AES-NI/ARMv8 hardware + bitsliced software fallback
  (compiler intrinsics, zero external dep)
- caller-supplied nonce (TLS builds its own per-record nonce); random-nonce
  is a cookie WRAPPER (phase D) not the primitive. shape:
  seal(key,nonce,aad,pt)->Bytes / open->?Bytes; AES variant by key length
- raw key + length check; hand-rolled (matches rv2 9); ids from 111
- phases A ChaCha -> B hardware AES-GCM -> C software AES -> D cookie wrapper
  -> E gate (RFC 8439 + NIST GCM vectors, ASan, reference cross-check)
- risk/test: constant-time mandatory, KAT-gated, reused-nonce documented
- retires the stale "TLS proxy-terminated" OOS line (rv2 9 overturned it)

(cherry picked from commit c8a5a31c39a5d14952056cd0af1b8c1e42d4ed2d)
2026-09-15 01:15:31 +02:00
51addb504c docs(rv2-tls): brainstorm runtime-v2 9 (in-process TLS) to ready — hand-rolled
- decision: HAND-ROLL TLS 1.3 (no vendored lib) per developer call; keeps the
  zero-external-dep single binary, and raises risk rather than lowering it —
  recorded, owned, with mandatory mitigations
- 1.3-only; RSA-PSS/PKCS1 + ECDSA-P256 + full ASN.1/X.509 chain validation +
  trust store + hostname (the scope needed to reach real LLM APIs)
- decomposed into a bottom-up phase ladder: A AEAD (=rv2 8, forces AES-GCM
  there) -> B HKDF -> C X25519 -> D signatures/RSA -> E X.509 -> F record+FSM
  client -> G inbound server; C/D/E may each split into own iterations
- risk + test strategy section: constant-time, reference-tested (openssl +
  RFC 8448 vectors), negative tests first-class, no partial-trust states
- deps: rv2 8 (AEAD), lang 34 (SHA/HMAC), net.connect (110, landed). Board synced

(cherry picked from commit f1881cca8cd0cdd58b1ac844e3e3ea9c234bb99c)
2026-09-15 01:15:31 +02:00
cc1c82b2ef docs: jarvis track, runtime-v2 7/8/9, lang-41 fix design, fiber scope-gap
- jarvis (00-story): 6th track, 2nd software built with writeonce — an AI
  assistant; direct-HTTPS design; blockers named (net.connect + TLS)
- runtime-v2 7 observability + 8 symmetric cipher: moved from the language
  track (were 30/43); 9 in-process TLS: created from the gap jarvis surfaces,
  RETIRES the "TLS is the proxy's job" doctrine (both directions)
- language 41 (arena hang): fix design to ready — marshal cross-shard
  messages (root), align the shard_id % nshards route/compare + assert bound;
  poison-on-free + minimal fixture as follow-ups
- fiber scope-gap analysis (plan/exploration/fiber/01): porch vs fiber, what
  porch lacks, would developers prefer porch
- board + dependency-graph synced (porch 2-8 ready; rv2 table; §5/§5a graphs)

(cherry picked from commit 203470ceb2a151fe3584931cd4237af3f96a9f29)
2026-09-15 01:15:31 +02:00
b932e0cb87 docs(porch-static): brainstorm story 8 (static + lifecycle) to ready
- whole porch track (2-8) now brainstormed and locked (all ready)
- four decisions: three hooks (on-listen/on-shutdown/on-route-registered);
  healthcheck ships BOTH /livez + /readyz; directory listing off-by-default,
  documented; Last-Modified via a new small time.utc(ms)->TimeParts builtin
- language enhancement: YES, one small builtin -- time.utc, a gmtime sibling
  of time.local (time.local is local-tz, time.iso is UTC-but-ISO); IMS by
  string-equality, no date parser. The track's third + smallest language touch
- byte ranges/large files via fs.read_at + iteration 6 writer; not lang-41-exposed
- track language bill now explicit: random_bytes (2), deflate+crc32 (7),
  time.utc (8) -- each a builtin with a named consumer, none decoration
- validated against .dev/reference/fiber. Board: whole track marked ready

(cherry picked from commit 9801fceade799e25718606177f09e4306a579e98)
2026-09-15 01:15:31 +02:00
4d3e4261e1 docs(porch-sse): brainstorm story 7 (SSE + compression) to ready
- five decisions: refuse incoherent heartbeat/idle_ms pair at construction;
  codec = two C builtins deflate+crc32 (perf over pure-.wo; hand-rolled, no
  zlib dep; gzip framing in .wo); ETag over uncompressed bytes + Vary;
  Last-Event-ID explicitly unsupported (not silently ignored); Vary via
  comma-join
- language enhancement: YES, two builtins -- the track's SECOND language
  dependency after iteration 2's random_bytes. CRC32 finally gets its
  consumer; inflate deliberately not built (request-body decompression OOS)
- corrected stale dependency: Vary uses iteration 5's comma-join, so story 7
  depends on 6 + 5, NOT 2; codec is pure compute, not lang-41-exposed
- confirmed CRC32 absent + iteration 36 bit operators landed (pure-.wo was
  viable, traded for hot-path speed)
- validated against .dev/reference/fiber. Board synced

(cherry picked from commit 07f53574dd90f502235b79d4920eab3d684c8b77)
2026-09-15 01:15:31 +02:00
641703903c docs(porch-streaming): brainstorm story 6 (streaming core) to ready
- re-scoped to OUTBOUND streaming only
- three decisions: separate StreamHandler/BodyProducer parallel path (Resp
  path untouched -> existing responses byte-identical); streaming routes opt
  out of the after-chain, framework refuses at registration to combine with
  header-mutating middleware (loud, never silent), security_headers() helper
  lets handlers stamp them; chunked REQUEST bodies split into their own future
  iteration (parse.wo refusal stays, smuggling cases enumerated for later)
- no language enhancement (net.write framing, fs.read_at/actor source,
  interfaces for producer); rides the fiber loop not the actor pool, so not
  lang-41-exposed
- fixed title inconsistency: "three iterations wait on" -> "two" (7 and 8)
- validated against .dev/reference/fiber + the app.wo/serve.wo pipeline. Board synced

(cherry picked from commit 15205408e03c3c02a38e00e5d2017a8a11f62f28)
2026-09-15 01:15:31 +02:00
6b820fdd5f docs(porch-routing): brainstorm story 5 (routing + response ergonomics) to ready
- five decisions: head auto-registers with opt-out (+ patch/options/all);
  request ids mirror limiter trust model with a NON-crypto source; per-route
  body_limit is a SECOND check after routing (global BODY_MAX stays the
  pre-routing ceiling, over-limit = 413); Route fields are corpus-free;
  Vary accumulates by comma-join
- key finding: story 5 has NO upstream dependency, not even iteration 2 --
  request ids are not secrets, so a non-crypto source (time.ticks+counter)
  keeps it startable today; the one porch slice buildable right now
- three story assumptions corrected: per-route limit cannot replace the
  global (body read before routing); the container-owned-move corpus fixture
  has its OWN Route (adding fields is free); Vary needs no iteration 2
- validated against .dev/reference/fiber; zero language enhancement. Board synced

(cherry picked from commit 0589a13db1f3b7c220d9d9fdc76142af6a63c390)
2026-09-15 01:15:31 +02:00
274f7c5361 docs(porch-csrf): brainstorm stories 3 (sessions) + 4 (CSRF) to ready
sessions (3):
- six decisions: pure-auth-primitive row (no payload bag); wall-clock
  time.now not monotonic time.ticks (restart durability); login always
  mints a fresh id (fixation, no anon-session model); throttled last_seen
  touch at idle/20 (not a WAL write per request); Session writes
  req.principal; config refuses absolute < idle
- finding: no per-key actor pool, so NOT blocked on lang-41 (plain @table
  CRUD, same path storefront uses); the no-bag rule closes the one place
  fiber's Set(key,any)+msgp+RegisterType would have hit principle 13

csrf (4):
- five decisions: fiber's hybrid transport (session-stored CsrfToken
  @table + double-submit cookie, both must pass; no CSRF for sessionless
  apps); opt-in single-use (checkout example); double-click -> distinct
  SPENT refusal, NOT coupled to lang-41-blocked idempotency; trusted
  origin/referer/Sec-Fetch-Site second layer; refusal classes distinct in
  logs, opaque in body
- no actor pool, not blocked on lang-41

both validated against .dev/reference/fiber (v3, 3ca9a9d); exactly ZERO
language enhancement needed beyond iteration 2's random_bytes. Board synced.

(cherry picked from commit 3a4fb4215b23d2516362e2dd0acc5bec6c9aebc0)
2026-09-15 01:15:31 +02:00
6a67db252b docs(porch-cookies): brainstorm story 2 (randomness+cookies) to ready
- five forks locked: cookies: multi SetCookie beside unchanged headers
  map; bare-name random_bytes(n)->Bytes; structural-400 in parse_request
  + on-demand cookie() helper; base64(value).base64(mac) signing;
  app-supplied key, no middleware (that is iteration 3)
- validated against .dev/reference/fiber (v3, 3ca9a9d): exactly ONE
  language enhancement needed (the CSPRNG); repeated Set-Cookie, cookie
  attributes, parsing and signing all map to existing primitives
- corrects phase A registry: random_bytes joins the crypto-family
  bare-name table (emit.ml b_* + types.ml), NOT wob.h's module enum;
  next free id 84/90, not 110
- board: story 2 marked ready, porch-2 row rewritten off the stale
  wob.h/110 claim

(cherry picked from commit 4d31d5359436496aed40cb25611abc7ccd4d7875)
2026-09-15 01:15:30 +02:00