Commit graph

57 commits

Author SHA1 Message Date
eacc7fe4f2 docs: oop-vm/03 — stackless coroutine contract (no async)
- normative reference for the concurrency chain: fiber = interpreter
  state, suspension only at VM boundaries, park/resume protocols
  (re-execute vs continue-past, park_wr_at), back-edge budget,
  no-coloring rule, rejected-alternatives table
- README slot 03 repointed (old shard-actor row rode discarded plan 4)
- story 11 links the contract

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 11:07:52 +02:00
a3a642b8bb docs: status board moved to docs/stories/00-status.md
- developer move; all inbound links repointed (root docs, plan/,
  plan/compiler/, exploration, superpowers plans+specs, in-progress
  marker), board's own links re-based one level deeper
- prose mentions inside landed plans left as historical records

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 10:07:20 +02:00
299b448181 docs: active stories 08+11 into stories in-progress/ (slip fix)
- 08 landed in discarded/ by mis-drop, swept into prior commit with
  two dead links; corrected to stories/.../in-progress/ per intent
- 11 joins it (one arc, active slice)
- board doctrine: active stories bucket named; all links re-verified

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 06:21:33 +02:00
d3f77d6850 docs: discard 2026-08-01 shard-actor plan (epoll-based)
- io_uring is a must; epoll approach discarded (developer decision)
- plan superseded by shard-fiber-arc plan of record; banner + row in
  plan/discarded.md; file kept as idea reference
- three live pointers repointed: status language-track row 8,
  principles enforced-by, story 08 note

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 05:59:21 +02:00
1cfcd6292a docs: stories 08+11 promoted to root — ready to implement
- code-verified ready: arc stages 1+2 merged to master; stage 3
  concrete in plan (tasks 7-8); rt.db set on primary only
  (main.c), worker_late_init memsets rt — WO_T_DB hole real
- 22/23/24/31 stay in refine/: open forks, no bench harness,
  no crypto builtins, chain-blocked
- links fixed both directions; board doctrine names hold/ bucket

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 05:10:39 +02:00
d24c705860 feat: iterations 19 + 17 — Float/Bytes scalars (.wob v5), library kind + internal/
- Float full stack: literals (fraction/exponent; `0..10` still a range), f64
  opcodes 34-41, @table column, WAL bit-exact replay, json fractions in and
  shortest-round-trip out. IEEE-quiet — FDIV never traps where DIV does.
- Bytes: a wo_str with its own class id, so alloc/free/copy are shared but no
  Text builtin accepts one; len/at/slice/eq/concat, base64 both ways, json
  boundary as base64; TEXT_COPY preserves the kind.
- No implicit Int/Float mixing (WO-E201 in the typechecker, not the emitter,
  which picks the opcode from one side and would misread the other).
- One IEEE deviation: float_cmp total order (NaN last, -0.0 == +0.0) for
  indexes and order-by, keys canonicalized to match. `?Float` nil is a
  reserved quiet NaN — the zero word is +0.0, WO_NIL_SCALAR's bits are -2.0.
- Renderer prefers fixed over exponential in 1e-6..1e21: pure shortest makes
  a price of 900.0 read `9e+02`. One renderer for interp/json/float_to_text.
- Fixed en route: lexer double-counted the leading digit; is_scalar_shaped
  took Float/Bytes as Int-shaped; Bytes ownership needed a shared heap-scalar
  predicate or temps never dropped; order-by bit-compared negatives backwards.
- Iteration 17: `kind = "library"` (absent = program; bad value = WO-E109),
  entry-less check mode retiring the `--emit` workaround, Go's `internal/` as
  WO-E108 at the consumer's `use`. Driver-only; VM/.wob/GC untouched.
- Framework reorg: internal/{parse,serve}.wo; http/form.wo split out to keep
  media_type/form_values public (parse.wo had grown public surface).
- Docs: link audit (97 -> 88 broken, conflict markers resolved, 2 duplicate
  stories removed), 00-code-review verified 26/27, iterations re-sequenced.
- Also carries the pre-staged pub(read)/using/#if work from the index.
- Gates: corpus 103/0, test_wal 156/0, web-app 26/0, oop-accept ALL MET.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 19:24:15 +02:00
5521d21a84 docs: pending iterations renumbered by dependency + priority
- developer directive: pending iteration IDs now ARE the priority order;
  LANDED iterations keep historical numbers (code comments and commit
  history cite them — records, not a queue); 8/11 (the half-landed
  arc), 17 (parked, artifacts on a branch), 18 (next, artifacts named)
  also frozen
- mapping (recorded in 00-story): 19<-20 Float+Bytes, 20<-9c attach,
  21<-9d keypair, 22<-9e benchmarks, 23<-9f io_uring WAL, 24<-19 chat,
  25<-10 services, 26<-12 blue-green, 27<-9g query corpus,
  28<-14 skillhost, 29<-13 metaprogramming
- 11 story files renamed; every doc reference re-numbered (word-boundary
  sweep for the lettered 9x ids, phrase-level for numeric ones); the
  iterations table rewritten with Seq == priority and "(was N)" notes;
  story-scoped link check: zero broken
- merge-recovery folded in: the partial master merge had dropped the
  chat story, the fibers exploration note, the arc spec+plan, the
  framework-v2 plan, and the iteration-17 spec+plan — all restored from
  their branches and renumbered consistently

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 14:31:09 +02:00
f6b5333d40 docs: iteration 15 closeout (Task 5)
- error catalog: WO-E106 (dependency fetch/shape failures, one code, message
  names dep + step) and WO-E107 (dep/local module-name collision) rows.
- README: a Dependencies subsection under the manifest docs — [deps] syntax,
  .wo-deps/wo.lock behavior, offline-when-locked, --update-deps, flat-only.
- board: iteration 15 row -> landed (deps-accept 8/0), pending row removed;
  story 15 header records the landing; 08-project-structure notes
  .wo-deps (gitignored) + wo.lock (committed); plan checkboxes all ticked.

(One self-inflicted casualty during this task, restored from git before
commit: a buggy doc-edit script truncated 08-project-structure.md; the file
was recovered intact and the intended one-liner applied by hand.)

Gates at closeout: deps-accept 8/0, woc-test 540/0, oop-e2e 87/0,
log-watcher 7/0, employee 8/0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 19:23:18 +02:00
f282451867 feat(json): Bool encodes true/false; fraction/exponent decode fails honestly
Closes json's two documented fidelity limits (iteration 5 strictness):

- field_class gains WOB_FIELD_BOOL (a plain `Bool` field) and
  WOB_FIELD_NIL_BOOL (a `?Bool`: WO_NIL_SCALAR nil + bool encoding) — the
  kind byte alone cannot tell a Bool slot from an Int slot, so the metadata
  carries it. Emitter writes them (field_class_meta); loader whitelists
  them; json.c encodes `true`/`false` (and `null` for a ?Bool nil), decode's
  null/omitted-key pre-write covers NIL_BOOL.
- A JSON number with a fraction or exponent is MALFORMED for an Int field:
  the checked decode (`json.decode(t) as T`) yields nil for the whole
  document instead of silently truncating 3.7 to 3 — the language has no
  float, and corrupting data quietly was the one thing a "checked decode"
  must never do. Floats stay representable through a raw `json.Value` field.
- corpus: run/json-bool-fidelity pins the round-trip (true/false both ways,
  ?Bool null both ways, fraction AND exponent rejected).
- Board's two known-gap entries struck; format doc's field_class marker list
  extended.

Verified: oop-e2e 87/0; runtime test + test-iso OK; woc-test 540/0;
log-watcher 7/0; employee 8/0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 18:04:15 +02:00
a43232dc72 feat(compiler): doctrine reject rows — WO-E105 (iter 5 strictness)
The verdict table's reject half is enforced: a Haxe habit fails loudly at
its own position with the doctrine reason, instead of a generic syntax
error — or, worst, compiling clean: `return super.f()` used to exit 0 (the
unresolved ident placeholder swallowed it).

- parser.ml: doctrine_reject_reason maps each rejected word to its spec
  reason (inheritance quartet -> principle 4; cast; Dynamic/untyped ->
  principle 13; macro; extern -> principle 10; operator). Fired at three
  chokepoints: `class B extends A` (with skip-to-brace recovery so the body
  still parses), an expression head (`super`, `cast 3`, `untyped x`), and a
  top-level declaration head (`macro fn`, `extern fn`).
- types.ml: `Dynamic`/`untyped` as a TYPE name keep their WO-E225 site but
  carry the doctrine message.
- corpus: compile-fail/{reject-inheritance,reject-cast,reject-dynamic}.
- catalog WO-E105 row; plan 8 Task 8 reject half ticked (#if still open);
  board updated.

Verified: woc-test 540/0 + test_diag 14/0; oop-e2e 86/0; log-watcher 7/0;
employee 8/0; legit identifiers (`extended`) untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 17:57:36 +02:00
8f6ff1e865 feat(compiler): WO-E205 structural interface satisfaction + call-arg checks
The hybrid-boundary inversion is closed: a statically provable interface
violation now fails at COMPILE time instead of reaching wovm as an ICALL
that traps WO_T_BOUNDS at runtime.

- types.ml class_satisfies: the same rule emit.ml's `satisfies` builds
  vtable rows from (instance method with matching name + parameter count
  for every interface method; `static fn` never satisfies) — one rule, two
  consumers, so the check and the vtable can never disagree.
- check_iface_boundary fires wherever a confidently class-typed value flows
  into an interface-typed slot: call arguments against the callee's declared
  parameters (free fns, methods off confident receivers, interface-method
  sigs, statics — resolved exactly as confident_typ resolves returns),
  annotated `let`s, and `return`s. Silent when underivable.
- The same per-argument pass extends the ?T boundary to CALL ARGUMENTS
  (the previous slice covered stores/returns/operands): nil into a
  non-nullable parameter is WO-E212, an unnarrowed ?T argument is WO-E211.
- tests/corpus/trap/unsatisfied-interface -> compile-fail/ with
  fixture.code WO-E205, per the fixture's own standing instruction; its
  header comment rewritten to the wired reality.
- The new arg checks caught a real mistyped signature in the sample:
  log-watcher's rpc_error/rpc_result/call_tool declared `id: json.Value`
  while every caller legitimately passes nil (JSON-RPC id-absent) — now
  `?json.Value`; dispatch/call_tool/cron-row sites moved to the
  bind-then-narrow idiom (including an `or`-guard narrowing:
  `if spath == nil or spat == nil { return }`).
- Catalog: E205 gains its main-table row; the "owed gap" section is
  rewritten as closed. Board known-gap struck through.

Verified: woc-test 540/0 + test_diag 14/0; oop-e2e 83/0 (fixture now
compile-fail, satisfying-class negative probe compiles clean); oop-accept
ALL MET; log-watcher 7/0; employee 8/0; gc-cycle clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 17:53:40 +02:00
934780c54c feat(compiler): ?T forced handling — WO-E211/E212/E213 + narrowing (iter 5)
The type system now keeps its nullability promise: a `?T` value cannot be
used, stored, or dereferenced as a plain `T` without narrowing. The canonical
evidence probe (return b.v where v: ?Int, fn -> Int) that compiled clean for
months now fails with WO-E211.

- WO-E211 (un-narrowed use): arithmetic and </<=/>/>= operands, and/or
  operands (?Bool), interpolation segments, for-iterables, and returns whose
  declared type is not nullable.
- WO-E212 (boundary): nil or ?T stored into a non-nullable slot — annotated
  let, assignment to a confidently-typed local (cenv, never the placeholder
  env — a placeholder target must stay silent) or a resolvable class field.
- WO-E213 (deref): field/index access through a possibly-nil base.
- Narrowing (locals only — a field place can be re-assigned between check
  and use, so chains bind to a local first): `if x != nil { }` narrows the
  branch; a DIVERGING then-branch (`if x == nil { return }`) narrows after
  the if; `x != nil and x.n > 3` narrows and/or right operands
  (short-circuit); `while x != nil` narrows the body. The narrow is
  un-applied when an else-less then-env leaks out un-diverged (the existing
  env-leak convention must not leak the narrow).
- No false positives by construction: env/cenv types are declared or
  confidently inferred; the placeholder fallbacks are plain scalars, never
  ?T. The whole golden suite passed untouched (540/0).
- Samples updated to the bind-then-narrow idiom (log-watcher config decode +
  supervisor lock/next_fire, gc-cycle ring print) — 22 genuine unnarrowed-nil
  sites; employee needed zero changes. All acceptances green.
- Corpus: compile-fail/{nullable-unnarrowed-use,nullable-nil-into-plain,
  nullable-deref-unchecked} + run/nullable-narrowing (all four forms) — 83/0.
- Catalog: E211/E212/E213 move from "Reserved, not yet emitted" to the main
  table; nullable-types-implementation.md status flipped to ENFORCED
  (historical record kept); plan 8 Task 6 ticked (boxed scalar cells
  superseded by WO_NIL_SCALAR); board updated.

Verified: woc-test 540/0 + test_diag 14/0; oop-e2e 83/0; oop-accept ALL MET;
log-watcher 7/0; employee 8/0; gc-cycle ring prints + reclaims.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 17:47:13 +02:00
28485a271c docs: iteration 7b migration — amend the normative docs (Phase 4)
The spec's §8 migration table, applied:

- 00-principles.md P3: "@gc is a per-class opt-in, reference-counted" ->
  GC-ness is inferred; incremental per-shard mark-sweep in budgeted slices;
  still no global pause by construction.
- OOP spec: decision-table GC row -> inferred (hybrid rule named); §3 rule 5
  -> traced classes alias freely, which classes is inferred; §4 memory model
  -> the RC + Bacon-Rajan paragraph replaced by tracing (snapshot roots,
  Yuasa barrier, born-black, budgeted slices); header rc comment -> union'd
  sweep link; mixing rule restated for tracing.
- 00-wob-format.md: header says version 4; opcodes 27-28 -> reserved (loader
  rejects); the owned-temporary rule's @gc exclusion restated for tracing.
- 08-builtin-surface.md: the push RC_INC special case and the set(m,k,v)
  retention gap DELETED — neither exists without RC; the corpus cycle is
  collected by tracing.
- story 07b: status -> LANDED 2026-08-18 (with the historical note kept);
  board: 7b row ✅ (supersedes iteration 2's RC memory model), pending row
  removed.
- gc-cycle README: Phase 3 flipped to landed (the ring runs, is reclaimed,
  ASan-clean; the ?Node RC_DEC-on-nil trap no longer exists); the barrier
  prose corrected to the as-built design (snapshot-at-beginning + deletion
  barrier + born-black, not per-slice root re-reads).
- plan 2026-08-18: all checkboxes ticked + a completion banner recording the
  four deviations from the plan as written.

(Error catalog was already amended with the keyword-removal commit: WO-E104
added, WO-W201 retired.)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 17:11:35 +02:00
3f842f854b feat(compiler): remove @gc from the language — GC-ness is fully inferred (7b)
`@gc` is no longer part of the language: a developer never writes or mentions
it. GC-ness is decided entirely by inference (structural cycles + demand
promotion), which the earlier 7b commits made complete and precise.

- parser: `@gc` on a class is now WO-E104 ("GC-ness is inferred; run
  `woc --dump-gc`. Remove it."). `is_gc` stays false; the class classifies by
  inference. No `.wo` in the repo carries `@gc` anymore.
- types.ml: retired the WO-W201 machinery (suggest_gc_annotation,
  has_recursive_structure(_type), has_unique_field, gc_suggestion_code) — it
  suggested `@gc`, now obsolete since inference traces exactly those classes.
- runner.ml: deleted the 8 WO-W201 gc-suggestion test blocks; the @gc-exemption
  test's `Cache` is made self-referential so inference classifies it gc without
  an annotation.
- fixtures: dropped `@gc` from rc.wo (Cache demand-promotes via its escape),
  elision.wo (Cache given a self-ref to stay structurally gc for the rc-elision
  dump), pricing-demo.wo (PriceCache doesn't escape -> now owned), and the
  abandoned-cycle/budget-steps corpus (Node is structurally gc). rc.wo keeps a
  placeholder comment line so its line-indexed rc assertions hold. Goldens
  re-blessed.
- docs: error catalog gains WO-E104 and marks WO-W201 retired; gc-cycle README
  records the keyword removal.

Verified: woc-test 553/0 (was 566 minus the 13 retired WO-W201 checks),
test_diag 14/0, oop-e2e 79/0, employee 8/0, log-watcher 7/0. `git grep '@gc'`
finds only comments — success criterion 1 met.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 19:19:09 +02:00
1a3df8cfac update docs 2026-08-18 02:04:58 +02:00
41422d316b chore: remove the old Rust runtime track from master
Master now reflects only the current woc/wovm project. The Rust `wo` runtime
was the prior, abandoned architecture; it is fully independent of the woc/wovm
stack (dune + make, no Cargo dependency), so it lifts out cleanly. Recoverable
via git history.

Removed:
- crates/ (29 files) + Cargo.toml + Cargo.lock — the Rust runtime workspace
- prototypes/ — wo-rt-c (a stale duplicate of runtime/) + wo-db C++ ref
- justfile: the rt-c-demo / rt-c-bench recipes (drove prototypes/wo-rt-c)
- docs/plan/05..16 (11 Rust engineering plans) + docs/plan/done/ (4 Rust
  Stage-2 done plans)
- docs/runtime/ (11): the old runtime overview + 7-phase DB design series +
  async/fibers/gc/surreal concept essays
- docs/cm.md — legacy scratch note

Kept: compiler/, runtime/ (C VM), database/, the current-track docs
(stories, superpowers, plan/{oop-vm,compiler,exploration}, examples), the
discarded/learnings registers, and the syscall/postgres/assembly/c-runtime
studies. Follow-up commits fix the status board, project-structure doc, and
any dangling links to the removed docs.

Verified: woc + wovm still build; woc/wovm --version green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 01:50:20 +02:00
531b0283c6 docs: remove stale old-runtime docs; abandon the ##ui frontend track
Analyzed the full 131-file docs tree (4 parallel classifiers) against the
shipped woc/wovm toolchain. Removed 21 stale docs, kept all intentional
history (Rust-track plans/done, the runtime/database design series cited by
current specs, syscall/postgres/assembly/c-runtime studies, discarded/
learnings). Deleted:

- old-runtime "front door": writeonce-pl.md, runtime/wo-language.md
  (pitched the Rust wo runtime -- REST/LiveView/SQL+Cypher -- as the current
  language; contradicted the new README)
- v1 design set: 02-recovery, 03-data, 04-ui, 05-datalayer,
  06-markdown-render, 07-ssl; runtime/database/05-go-sdk
- future-scope/ai-agents-content-management (unfinished old-runtime CMS)
- the ##ui/.htmlx LiveView frontend track (product decision to abandon):
  9 plan/exploration/ui/*, plan/14-mvc-ui-implementation,
  superpowers/plans/2026-08-01-ui-htmlx-live; 13d pricing-UI board row

Tree left link-clean: 46 dead links to the removed docs neutralized to plain
text or deleted as pure see-also bullets across 20 kept docs; whole-tree
link-resolving scan reports zero links to any deleted file. Removal recorded
in discarded.md; board Frontend section + project-structure tree updated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 20:06:36 +02:00
30ef8d8533 feat: insert executes (iteration 9, Task 3) -- DB_STUB retires for insert
- 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>
2026-08-15 11:15:06 +02:00
c3741262cb feat(database): typed WAL + boot replay (iteration 9, Task 2)
- 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>
2026-08-15 11:01:41 +02:00
936bd14bff feat(database): class-shaped row storage (iteration 9, Task 1)
- 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>
2026-08-15 10:54:24 +02:00
1749440351 docs: borrow/GC analysis for the database engine, into the iterations
- 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>
2026-08-15 09:57:53 +02:00
ebcbf460df docs: employee sample (target workload) + engine moves to database/
- 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>
2026-08-15 09:49:54 +02:00
5943bf6890 docs: iteration 9b spec + plan — @table, relations, query (employee)
- spec settles 9b's three forks: SQL/Cypher layer superseded as the
  program surface (design history + wo-db engine-semantics reference);
  comprehension syntax desugared at compile time (no function values);
  System.Linq = operator vocabulary + edge cases, PostgreSQL = execution
  + integrity vocabulary (both references surveyed 2026-08-15)
- aggregate semantics normative: count/sum total 0 on empty, avg/min/max
  are ?T with nil (empty is data, not a fault); nil skipped; sum wraps
  like language arithmetic; GroupBy lowers as group-and-reduce
  (AggregateBy shape), transition/finalize ABI from nodeAgg
- relations: ref = FK with direct-index-probe check (nil passes,
  unchanged-key skips), backlink = secondary-index scan, delete is
  restrict-only; nil never joins, nil is a legal group key
- lowering: the compiler is the planner — queries become bytecode loops
  over cursor/group builtins, longest-prefix index selection, no plan
  tree, no SQL text in the image (disassembly-provable)
- plan: 6 tasks gated by a new docs/examples/employee sample
  (Department/Employee, @unique, composite index, ref/backlink,
  GroupBy report mode) with its own acceptance script + crash step;
  blocked on iteration 9's engine plan
- story 09b + status board updated; 02-wo-language.md carries the
  supersession note

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 09:10:08 +02:00
3c53d27347 fix: close per request, soak the daemon, kill five soak-found leaks (Tasks 5+6)
- Task 5: net.close on every path out of a serve iteration (400
  included) and the listener on stop; measured 4 -> 54 fds over 50
  requests before, 4 -> 4 over 200 after. The loop's comment claimed
  the iteration-end drop IS the close -- wrong twice (net.Conn is a
  scalar, and a drop would not close an fd); it now says what is true
- Task 6: LW_SOAK=<seconds> in the acceptance script -- each mode under
  load, resident+descriptor deltas against a WARMED baseline (warm-up
  includes load: cold-to-high-water is not growth), 256 KiB / zero
  tolerance; LW_ACCEPT_WOVM soaks another build
- the soak caught ~1.6 MiB/min of in-arena leaks ASan cannot see (the
  arena is one allocation to LeakSanitizer); an arena size-class
  census + pointer trace attributed five bugs:
  - jparse_string sized every decoded string at "rest of the input"
    and relabeled len after -- blocks filed on free lists their next
    allocation never reads (fs.read_all's mis-size, again); copy out
    exact, free at the taken size
  - `!=` never dropped fresh operands (headers["authorization"] !=
    "Bearer ${key}" leaked both sides per request); Ne now reaps as Eq
  - an Int interpolation segment is a fresh int_to_text, not a borrow;
    is_borrowed_value_t asks the segment's type
  - json.encode(Ctor{...}) had no owner -- record + both field copies
    leaked per tool call; its bespoke lowering now drops the argument
  - a discarded expression statement owns its result: `pop(lines);`
    leaked the popped element; reader builtins excluded
- after: arena live bytes flat per request on every handler; release
  soak 30 s per mode watch 0 / run 0 / mcp +20 KiB, descriptors flat;
  ASan build flat at 14600 KiB across 601686 requests in 90 s past its
  ~1200-request quarantine warm-up
- gates: oop-accept ALL CRITERIA MET, oop-e2e 71/0, woc-test 565/0,
  wovm-test green, log-watcher 7/0 (soak opt-in, fast path <1 min)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 00:32:49 +02:00
22910e3974 fix: a stopping program stops (executable plan, Task 4)
- blocking stdlib calls that PARK (net.accept, socket read/write,
  time.sleep, a child wait) no longer restart the syscall when the
  stop flag is set on an interruption: a server sitting in accept
  ignored SIGTERM and only `kill -9` ended it
- a stop is NOT a trap -- builtin.h's WO_SYS_STOPPED carries no error
  record and no catch handler sees it (`try` must not swallow
  SIGTERM); the VM unwinds the whole stack through the same drop
  machinery an uncaught trap uses, so nothing leaks on the way out
- wo_vm_call gained a third outcome (1 = stopped); the CLI maps it to
  the status the program's own `return 0` would have given, and a
  regular-file read keeps its plain EINTR retry -- it does not park
- an ASSIGNMENT was not an ownership boundary: `api_key =
  j.mcp.apiKey` moved the field pointer into the local, so the local
  aliased the record and the first unwind freed the same string twice
  (SIGSEGV in class_free). `let` copied a Text place, assignment now
  does too -- the same double free was latent on the normal exit path,
  hidden by the order the compiler happens to emit drops in
- log-watcher-accept is 7 checks: the seventh is the stop itself, with
  the hard kill demoted to a fallback whose use is the failure
- measured under ASan: mcp parked, mcp after traffic, watch and run
  all exit rc 0 with zero leaks; SIGINT behaves as SIGTERM
- gates: oop-accept ALL CRITERIA MET, oop-e2e 71/0, woc-test 565/0,
  wovm-test green, log-watcher 7/0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 23:58:21 +02:00
4a2fc2041e fix: release the argv container (executable plan, Task 3)
- program mode built the entry's `multi Text` of arguments and never
  freed it: the entry only BORROWS a parameter (never a `take`, and
  the drop tables never drop one), so the runtime that built the
  container owns it
- dropped after the entry returns and after a trap alike -- the
  container outlives the unwind; `multi_free` recurses, so the
  argument strings go with it
- one site covers both invocation shapes: `self_rc` picks the argv
  offset, it does not build a second container
- measured: watch, run and the full MCP mix now report ZERO leaks
  under ASan -- the clean baseline the soak (Task 6) reads against
- gates: oop-accept ALL CRITERIA MET, oop-e2e 71/0, wovm-test green,
  log-watcher 6/0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 23:41:13 +02:00
ef74d157b6 fix: drop the values nobody names (executable plan, Task 2)
- the drop tables track bindings only, so six shapes had no owner: a
  comparison operand (`if parse_expr(s) == nil` abandoned a schedule
  record and its five containers per cron line), a borrowed call
  argument (a 1 KB string per MCP request), a container read's copy,
  a loop's iterable, a projected record, and any of those escaped by
  a `return` from inside the statement that built them
- `c[i]` is the one place expression whose register holds a COPY:
  no second copy at a boundary (`let u = tokens[0]` copied twice and
  abandoned the first), and a drop where every other place is left be
- never drop an argument register after a CALL — the callee's frame
  overlaps it; the reap moved into call_window's pre-call stash
- a statement-owned temporary is parked in a LOCAL slot: a loop
  reclaims every temp for its body, and the end-of-statement DROP was
  releasing the loop counter instead of the record
- reader builtins (get/latest/key_at/val_at) keep arg0 alive — their
  result points into it — but their key argument is ordinary
- measured: run 2 112 B -> 64 B, flat 8 s to 20 s; MCP mix 21 312 B /
  63 -> 64 B / 1; every handler flat from 2 to 6 requests; the 64 B
  left is Task 3's argv container
- gates: oop-e2e 71/0, woc-test 565/0, wovm-test green, log-watcher 6/0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 23:23:21 +02:00
eb0095428d fix: Text is an owned value copied at every boundary (executable plan, Task 1)
Measured on the workload's supervisor mode, eight seconds, clean SIGTERM exit:
run 1 051 040 B in 24 allocations -> 2 112 B in 19; watch 128 B in 2 -> 64 B in
1. corpus 71/0, woc runtest 565/0, wovm unit gates green, just log-watcher 6/0.

- owner.ml: `oclass_of` called `Text` a builtin scalar, so it was Copy and NO
  Text local was ever dropped — that, not the missing stdlib table, was the
  leak. Text is now Owned, which forces an answer for what it does at an
  ownership boundary, and the answer is uniform: it is COPIED. Into a
  container (push/set/`m[i] = v`, already true), into a field (SETF), out of a
  function (return), into a binding (`let s = other`), and into a loop cursor.
  The source keeps its value; a freshly built Text stays the caller's and is
  dropped at the site
- owner.ml: resolve_callee answers for three shapes it never knew — reserved
  stdlib members, builtins, and a class's `static` members — so their results
  get a type, an owner and a drop
- vm/builtin: WO_B_TEXT_COPY, the one new builtin the rule needs; SETF copies a
  TEXT field in; emit copies a Text read out of a container, bound from a
  place, returned from a place, or loaded into a cursor, and drops a freshly
  built one after a copying store
- sysio.c: fs.read_all/net.read allocated their cap then relabelled the buffer
  with the short length — but wo_str_free sizes a block by its len (no size
  headers, obj.h), so a 1 MiB buffer wearing a 30-byte length went onto a
  32-byte free list and never came back. They copy out at the true size now
- two regressions the corpus caught, fixed in the same pass: a @gc value read
  out of a container is a plain borrow, not an rc-counted alias; and push's @gc
  escape is keyed on "push is not a user-declared fn" rather than "the callee
  did not resolve", which stopped being true once builtins resolved
- docs: Task 1 closed in the executable plan with its before/after numbers, and
  the status board's item 1 records the deeper root cause

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 22:45:03 +02:00
7c10df67a3 docs: reprioritise to log-watcher-executable only; update stories and plans
Every remaining item is now traced to a measurement on the sample; anything the
sample does not exercise is deferred by name with the measurement that says so.

- new plan docs/plan/compiler/2026-08-14-logwatcher-executable.md — six tasks
  between "it runs" and "you can leave it running": the ownership pass learning
  stdlib return types (>1 MB leaked in 8s of `run` mode, one fs.read_all
  result), dropping a projected temporary (`for e in parse_dir(d).entries`
  leaks the shell per rescan), the runtime's own argv container (128 B every
  run), honouring the stop signal in blocking calls (a server in accept ignores
  SIGTERM), closing accepted connections (net.close exists, unused), and a soak
  that would have caught all of it. Opens with the measured starting point and
  closes with an explicit out-of-scope list
- story 7 (log-watcher proof): status banner separating the met compile-and-run
  half from the executable half, plus a new Given/When/Then — clean SIGTERM
  exit, zero leaks, flat RSS and descriptors across a soak
- story 5: grammar half landed, strictness half deliberately deferred
- story 6: landed for the surface the workload uses, with the two lifetime
  defects it exposed pointed at the new plan
- story 7b: recorded as off this workload's path, measured — the sample has no
  @gc class, 0 RC_INC/RC_DEC against 78 DROPs
- 00-status.md: NEXT PLAN is the executable list; story table and in-progress
  row point at the new plan; deferrals carry their evidence
- plan 8 (haxe-parity): banner now says on hold behind the executable plan, and
  its task states are corrected — Task 5 shipped, Tasks 6 and 7 are half done

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 22:16:14 +02:00
4dbbc48772 docs: record copy-on-push (gap closed) and the SIGTERM-in-accept gap
- 08-builtin-surface.md: containers copy a TEXT element/key/value; a freshly
  built Text is the caller's to drop, a value read out of a place keeps its
  owner; OWNED/GCREF still move and set's @gc retention gap stays open
- 00-status.md: the borrowed-Text double free is struck through as closed by
  copy-on-push, with the concrete failure it fixed; new gap recorded — a
  blocking accept/read swallows SIGTERM, which belongs to iteration 8's event
  loop rather than a patch to the blocking calls

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 18:50:54 +02:00
0acb6be559 fix: net.Conn is a scalar, \r escape, map[k] is optional, interp node ids
Found by driving the compiled log-watcher's third path — the MCP server. It now
answers real JSON-RPC over HTTP: initialize returns protocolVersion/serverInfo,
tools/list returns the full tool list (1049 bytes of generated JSON), and an
unauthorized request gets 401 {"error":"unauthorized"}. corpus 71/0, woc 565/0,
wovm gates green.

- lexer: `\r` and `\0` escapes. Without `\r` a program cannot write CRLF at
  all — the server's `index_of(buf, "\r\n\r\n")` was searching for a literal
  backslash-r, so it never found a header terminator and hung on every request
- parser: an interpolated sub-expression now mints node ids from the OUTER id
  space. A fresh sub-parser started at 1, so `${...}` nodes collided with the
  file's own nodes — and every side table (drops, moves, rc, masks, f_decl) is
  keyed by node id. Surfaced as WO-E404 "ownership table names `headers`,
  which has no register"; silent misattribution otherwise
- types.ml: `net.Conn` is a reserved SCALAR type (a file descriptor). It was
  falling through as "some user class", i.e. WO_K_OWNED, so the frame would
  DROP an integer at scope end
- types.ml: confident_typ knows `..` yields Text. Interpolation desugars to a
  Concat chain, so without it every interpolated value looked underivable —
  which is why the `+`-on-Text check missed two live sites in the workload
- `m[k]` on a map is now the OPTIONAL read (nil for a missing key), while
  `get(m, k)` stays the asserting one that traps KEY. That is what makes
  `let v = m[k]; if v != nil` — the workload's header lookup — work.
  trap/missing-map-key now pins `get(...)`, and the surface doc records the
  split
- json.encode of a `json.Value` emits it verbatim (kind 255): an echoed id was
  coming back as "1" instead of 1
- disasm: TRY/ENDTRY render instead of ?OP32/?OP33
- status board: the push-of-a-borrowed-Text gap is now recorded with the
  concrete failure it produces (tools/call tail_log), plus the leaked
  temporary-record shell found in the same disassembly

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 17:47:45 +02:00
993a540d7a fix: nullable scalars need their own nil word; EQS accepts nil
Found by running the compiled log-watcher, not by reading code: the supervisor
rejected every cron line ("malformed schedule: * * * * *") because a `*` field
expands to 0 and `?Int`'s nil was also 0, so `a == nil` was true for a real
value. Both log-watcher subcommands now behave: `watch` alerts on a live file,
`run` reports SCHEDULE /var/log/backup.log: * * * * *. corpus 71/0, woc 565/0,
wovm gates green.

- a nullable SCALAR (?Int/?Bool/?Timestamp/?Id) spells nil as WO_NIL_SCALAR
  (-2^62), not the zero word. Heap-shaped optionals keep 0 — a null pointer is
  unambiguous. The value is -2^62 and NOT INT64_MIN on purpose: the compiler's
  integers are OCaml's 63-bit natives, so INT64_MIN is not expressible there
  (and `min_int * 2` silently wraps to 0 — the first attempt did exactly that)
- the class table marks such fields (WOB_FIELD_NIL_SCALAR in field_class), so
  the runtime writes the right absence where it produces absence itself:
  json.decode leaving a key absent or seeing `null`, and parse_int on
  unparseable input (so parse_int("0") is now distinguishable from a failure).
  json.encode renders a nil scalar as JSON null
- emit.ml: `nil` takes its word from its destination (annotation, field,
  return type); a comparison against `nil` emits the literal with the other
  operand's type, so ?scalar compares against the sentinel and ?heap against 0
- vm.c: EQS accepts a nil operand — two `?Text` values compare with it, and the
  answer is "both absent is equal, one absent is not". Trapping there made
  `a != b` on optionals unusable (it was trapping BOUNDS "null text" in the
  supervisor's rescan). A non-nil operand must still be a real Text
- docs: both normative docs now state the heap-vs-scalar nil split and the EQS
  rule; the stale duplicate vm_unwind comment is gone

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 17:28:50 +02:00
065ac99224 feat: json encode/decode + as, .wob v2 class metadata — log-watcher compiles
docs/examples/log-watcher (1285 lines, 7 files) now compiles clean: 0
diagnostics, a 35KB .wob written. corpus 71/0, woc runtest 565/0, every wovm
unit gate green (both dispatch flavors).

- .wob v2: each class row gains three u32 per-field arrays — the field's NAME
  constant, the CLASS it refers to (or the json-raw marker), and a container
  field's ELEMENT kinds. json is then a runtime service driven by metadata
  instead of per-type generated code. loader/emitter/disassembler/test
  assembler all read and write v2; field-name constants are interned with the
  rest of the pool (interning during serialization silently loses them)
- runtime/src/json.c (new): encode by static kind + object headers + class
  table (nested records need no static knowledge); decode parses and BINDS
  straight into the target class — keys matched to field names, nested objects
  built as the field's class, arrays as a multi of the field's element kind,
  unknown keys skipped, absent keys nil. Malformed input is nil, never a trap
- `as`: `json.decode(text) as T` is the one cast this language has (WO-E403
  for any other `as`, and for a bare json.decode with no target type). Its
  result is `?T`, which is why the decode and the target are one instruction
- json.Value: a reserved type name for a value the source does not inspect —
  the raw JSON slice, kind TEXT, re-emitted verbatim by encode
- docs: 00-wob-format.md is now the v2 reference (class metadata, TRY/ENDTRY,
  the whole builtin surface, WO_T_IO); 08-builtin-surface.md documents the
  text/container builtins, the OS modules with their predeclared records, and
  json's two documented limits (Bool encodes 0/1, floats truncate)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 17:08:46 +02:00
2a98186259 feat(compiler): let-type annotations, container literals, statics, pub(read)
Driving goal: compile docs/examples/log-watcher (1285 lines of .wo).
Diagnostics on that program: 481 -> 379; parse errors 85 -> 18.
tests/corpus via scripts/oop-e2e.sh stays 71 checks / 0 failures.

- ast.ml: `Let.ty` is a full `field_ty` (was a bare name), so `multi Text`,
  `map<K, V>` and `?T` annotate a local; new `ListLit`/`MapLit` expressions;
  `method_decl.is_static`; `field.pub_read`
- parser.ml: let annotations go through parse_field_ty; `[]`/`[a, b]` and
  `{}` literals in expression position; `static const`/`static fn` in class
  bodies (one token of lookahead — `static` stays an identifier);
  `pub(read) field: T`; a `;` ends a statement on its own, so one-line
  guard bodies (`{ skip(...); return; }`) parse
- emit.ml: list/map literals lower to multi_new/map_new + one multi_push per
  element, element kinds from the destination's declared type (WO-E403 with
  no typed destination, same rule multi_new already had); `static fn` gets a
  receiverless method record (arg_cnt = params) and lowers `Cls.fn(args)`
  through emit_direct with no `self`; a static can satisfy no interface
- types.ml: a written `let` annotation is now the authority for the binding's
  type (the only thing that types `[]`/`{}`/`nil`); `static_method_of` +
  static-call return types; method_info.is_static is wired from the AST
- owner.ml: container literals are fresh owned values, elements read in place
  (inherits push()'s open borrowed-element gap, noted in the code)
- plan doc: `Spec:` header line so planboard's lint accepts the plan

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 16:22:47 +02:00
e966f54ecf update msg 2026-08-12 15:16:29 +02:00
1ba035397d feat(compiler): iteration 5 Tasks 1-4 — modules, language surface, switch, typedef records + enum variants
- Modules: `use`/`pub`, directory-as-module, per-module symbol resolution (a
  flat first-wins merge silently ran the wrong `pub fn` body), six reserved
  stdlib namespaces typed UNKNOWN-BUT-RESERVED.
- Surface: `and`/`or` (own precedence tier, short-circuit, Bool-only), `${}`
  interpolation desugared at parse time, `const`, break/continue with
  drop-correct exits, do-while, inline-fn rejection.
- switch expr/stmt: required `default` over scalars/Text, arm unification,
  EQ/EQS+JZ lowering, per-arm drop scopes with N-way JOIN-DROP; `default`
  sorted last by a shared lowering order (textual order made arms dead).
- typedef records: structural, same shape = one class entry; `?name: T`
  nullable-by-shape; emit_ctor fills omitted defaults; `type` as field name.
- Enum variants: all-bare unions = int ordinals; any-payload = one class
  entry per variant, tag IS the header class_id (no header field, no format
  bump); exhaustive switch without `default`; arity checked both directions.
- Payload escape modeled as move-out (pointer-kind fields only — a scalar
  escape is a copy); caller reaps owned heap temps passed by borrow: two
  unbounded LSan-blind leaks, 10.5 MB -> 1.5 MB flat over 300k iterations.
- Fixed en route, each with a RED repro: dead E209 builtin-arg check and
  `int_to_text` missing from both types.ml builtin tables (both segfaulted
  wovm), multi-file phantom double-report, emit_ctor's field temp clobbering
  dst in tail position (pre-existing), warnings swallowed without an error.
- Two fenced VM builtins: `int_to_text` (13), `variant_tag` (14).
- 14+565 unit (was 14+401), corpus 71 (was 32) plain and under wovm_asan,
  wovm-test + cli_smoke green. Log-watcher 307 -> 93 diagnostics (85 E101 /
  4 E207 / 1 E208 / 3 W202); the 5 non-E101 residuals await Task 7 grammar.
2026-08-12 14:40:07 +02:00
79605cbb4f feat: milestone 1 complete — .wob emitter, conformance corpus, single binary; GC redesign specced
- `woc` now emits `.wob` that `wovm` runs: emit.ml lowers the typed,
  owner-annotated AST (scope-stack registers with a >64 WO-E401 diagnostic,
  Lua-style call windows, ICALL by slot, dedup const pool, drop maps, line
  tables, implicit terminators); disasm.ml backs `--dump-bc` goldens.
- Ownership lowering consumes the four owner tables verbatim; RESIDUAL is the
  only source of borrow ops, coalesced per operand. Review caught the emitter
  consuming only 2 of owner.ml's 4 residual producers — an assignment-anchored
  aliasing violation ran to exit 0 instead of trapping; fixed, plus a backstop
  raising WO-E404 for any residual region left unconsumed.
- Conformance harness `scripts/oop-e2e.sh` (`just oop-e2e`): four fixture
  kinds with exact outcomes — byte-exact stdout, one WO-E### anchored on
  `error CODE:`, numeric trap code, gc trace. 25 fixtures incl. pricing-demo
  logic, the ownership suite, and DB_STUB's parse-but-trap. `tests/` un-ignored
  so the corpus is actually tracked.
- `woc build` produces a self-contained binary: wovm copy + appended image +
  20-byte trailer, self-exec via /proc/self/exe. Verified relocated outside
  the repo, argless, and against adversarial trailer corruption.
- Milestone 1's five spec criteria all MET (`just oop-accept`). Criterion 3
  closed by WO-E405 — the entry must return `Int`, since program mode already
  says its return value is the exit code — which deletes the leak class
  without adding return-type metadata to the format. `gc/held-cycle` retired:
  an externally-held cycle is not expressible in a post-exit pump.
- New spec: inferred GC + incremental per-shard tri-color mark-sweep, retiring
  `@gc` and reference counting. Story gains iterations 7b (that work) and 9b
  (`@table`, relations, compiler-checked query); `.dev/reference` gains a
  sparse System.Linq checkout. Priority: 5→6→7 (log-watcher) then 7b, 8, 9, 9b.
2026-08-11 19:31:26 +02:00
a55971d857 docs: status board at docs/00-status.md; gap-closure spec applied; recover lost doc
- 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.
2026-08-10 23:42:26 +02:00
49872a4b11 docs: six-bucket status board; recover lost vision doc; stop ignoring docs/
- 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.
2026-08-10 21:52:59 +02:00
2de724df11 feat(compiler): MVS ownership pass + woc driver; drop Money/SKU/Float, reject abstract
Completes plan 2 Tasks 7-8. owner.ml: mutable-value-semantics flow analysis
producing the four plan-3 emitter tables (moves, drops incl. LIVE-MASK for trap
unwinding, rc with elision, residual borrow sites) plus WO-E301-304 two-site
diagnostics. Alias questions run over canonicalized places, so a double-mut
reached through let-bound aliases lands in the residual table like the direct
form; dump.ml's contract notes the emitter must coalesce guards per operand.
main.ml: directory discovery, cross-file programs (symbols merge before bodies
check), diagnostics ordered by (file,line,col), new WO-E214 for a name declared
in two files. New docs/plan/oop-vm/01-error-catalog.md (14 emitted + 10 reserved
codes), un-ignored so both plan tracks can cite it; justfile regains woc-*.

builtin_scalars is now the five that work: Int, Bool, Text, Timestamp, Id.
Money/SKU/Float and the abstract_types allowlist are gone — `abstract` never
lexed, and Float had no literal syntax and no wob kind, so no value could exist.
Fixtures and samples retype Money->Int, SKU->Text. The abstract newtype feature
is rejected outright (verdict row adopt->reject); haxe-parity Task 7 keeps `is`.

nullable-types-implementation.md corrected: ?T is plumbed but UNENFORCED
(E211-213 declared, never emitted; probe exits 0), handed to haxe-parity Task 6
as next work item. Records all 10 dead codes incl. E205 — interface satisfaction
is unchecked. crates/rt keeps its Money/SKU fixtures (opaque strings, Stage 2).

Gate: build warning-clean, 14 + 264 checks 0 failures, pricing golden exit 0,
docs/examples histograms unchanged (13/70, zero WO-E225).
2026-08-10 21:24:50 +02:00
5a43210448 docs: compiler front-end specifications and plans (Tasks 2-6)
- Plan docs: architecture, woc front (Tasks 2-7), emit+e2e (Plan 3), Haxe parity (Plan 8)
- nullable-types implementation plan
- Iteration 3: compiler front story
- Specs: systems track, blue-green VM, log-watcher sample, OOP compiler/VM
- Principles + project structure
- Kanban updated with compiler front-end progress
2026-08-10 09:11:04 +02:00
76f72e85c4 feat(compiler): nullable types (?T) support
- ast.ml: Added Nullable variant to field_ty; param.ty/method_sig.ret/method_decl.ret now use field_ty
- parser.ml: Parse ? prefix for field types, return types, parameters
- dump.ml: Render ?T in --dump-ast output
- types.ml: New typechecker (Task 6) with nullable field-kind derivation (WO_K_NULLABLE=6)
- dune: Added types module
- Added golden test fixtures for nullable types and statement/expression parser
- Added implementation plan doc
2026-08-10 08:39:29 +02:00
10cf6e4737 postgress as mirror database 2026-07-15 01:27:55 +02:00
7ae3a20af1 every class with @table anotation is queriable table 2026-07-15 00:44:09 +02:00
45b96f0466 # writeonce - method execution
POST /api/products/1/set_price -d '{"amount": 4999}'
2026-07-12 05:43:49 +02:00
e5203b289d more on mcp streamable http 2026-07-12 05:10:22 +02:00
7a2e09cd19 Update plan with kanban 2026-07-12 04:25:49 +02:00
619aa74933 laanguage prototype 2026-07-12 03:40:30 +02:00
929b2802c4 add wo-rt-c: C runtime prototype, phases A-F shipped
prototypes/wo-rt-c — single-file C reference of the writeonce runtime
layer, zero deps beyond libc + kernel uapi: thread-per-core io_uring
event loops (raw syscalls, no liburing), SO_REUSEPORT listeners, one
mlock'd mmap arena sharded by address, WAL dual-write with group commit
(HTTP ack only after the fsync CQE), boot-time snapshot + WAL replay
recovery, and a bench harness with a Go net/http comparison server.

Measured on 20 cores: 908k reads/s p99 154us and 643k fsync-acked
commits/s p99 177us on 8 shards, vs Go net/http 495k/355k (no
durability) on 20 cores. Crash-under-load testing found and fixed an
ack-before-fsync race and an fd-reuse ABA hazard in commit-ack parking.

docs/plan/exploration/c-runtime — the phased plan (00, exit evidence
per phase), the one-address architecture trace (01), and the
single-binary end-goal contract (02). justfile carries the demo and
bench recipes; .gitignore covers binaries and data dirs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 23:05:13 +02:00
c8f76484f4 explore postgres code base 2026-05-05 00:26:49 +02:00