aboutsummaryrefslogtreecommitdiff
path: root/TODO.md
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 10:20:10 +0000
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 10:20:10 +0000
commiteee97c808f749eae49ec750b71ea9397cdf16f9c (patch)
tree972a07fa33edfb188c922af24869f758f7f747e7 /TODO.md
parenttodo: zc0 structs before the records refactor (diff)
todo: handoff section with state, conventions, in-flight work and architecture notes
Diffstat (limited to 'TODO.md')
-rw-r--r--TODO.md131
1 files changed, 96 insertions, 35 deletions
diff --git a/TODO.md b/TODO.md
index e31d682..d093cab 100644
--- a/TODO.md
+++ b/TODO.md
@@ -141,46 +141,107 @@
- [x] bring documentation, examples, learn entries, history notes and test fixtures in line with the include and namespace format and the other language changes made alongside it: qualify runtime built-ins as `rt.put_s`, `rt.put_n`, `rt.put_c`, `rt.eof` and `rt.get_c`, require the explicit `include` each module needs, and remove the remaining bare builtin names so every shipped sample, every documented snippet and every expected-output fixture compiles and runs against the current compiler. the learn guide and `README.md` snippets are checked by the suite, so they are the gate, but the prose and the non-exercised samples are not.
- [x] add accept, reject and regression coverage for the actor and icon libraries once each is finished: for actors, syntax activation through the include-time extension, spawn/recv/send across input and output types, multiple instances of one actor, parallel execution, implicit `this`, and confirmation that no actor code is reachable from the compiler or anything it reads by default; for icon, find/replace over real syntax, undeclaring names, changing types, adding and rewriting blocks, evaluating parts of an expression, and stepping execution while reading locals and globals, including the failure cases for each.
+## handoff: where things stand
+
+this section is written so work can resume from the repository alone. the
+branch is `ccr-0054c02e-dfdvnd`; everything listed as done below is committed
+and pushed there.
+
+### how the work is organized
+- start with `ONBOARD.md` (reading order and exact commands), then
+ `docs/SPEC.md` (the language reference), then this file.
+- the compiler is twelve files listed in order in `src/compiler/parts`; their
+ concatenation is the old `compiler.zc`. the genome sources (runtime, core,
+ compiler parts, language server) must stay inside zc0's subset: zc0 has no
+ structs, enums or `?:` yet (in progress, see below); `u`, `m`, `d` are
+ ordinary names; parenthesize mixed `&&`/`||`; global arrays as `word[64] x;`.
+- focused checks, never the whole suite until the last item:
+ `make` (ends with `fixpoint: N words`), `bash tests/runerr.sh build/bin/zy
+ tests/errors` (and `typeerrors`, `langerrors`), `python3
+ tests/drivers/learn.py build/bin/zy`, `python3 tests/drivers/icon_test.py
+ build/bin/zy`, `python3 tests/drivers/actor_test.py build/bin/zy`,
+ `ZC_TEST_TIMEOUT_SCALE=4 node tests/drivers/lsp_test.js build/bin/zclsp`,
+ `ZC_TEST_TIMEOUT_SCALE=4 node tests/drivers/hint_fixes_test.js
+ build/bin/zclsp`, `make parity` (zc0 against the self-hosted compiler; by
+ design differences live in `tests/parity.known`). on x86 the language server
+ is interpreted and slow; `ZC_TEST_TIMEOUT_SCALE` stretches the deadlines.
+- work was done by delegating each item to a separate agent in its own git
+ worktree (outside the repo, under `/workspace/tinyvm-wt/`) and merging its branch.
+ every brief started with "read ONBOARD.md first" plus the sections relevant
+ to the job, stated the invariants (fixpoint, byte-identical images where a
+ change should not alter output, zc0 subset), the focused checks, and asked
+ for a report of files changed, tests run and open questions.
+- prose everywhere is lowercase with plain punctuation; `//` line comments,
+ `/* */` only between code; a comment above a declaration is its hover text.
+
+### done in this session (all merged)
+- build from source with c23 `#embed`, everything generated under `build/`,
+ `ONBOARD.md`, the embed declaration (`embed "f" as [type] name;`).
+- language: untyped `const` (local, top level, inside structs), c precedence
+ for `&&`/`||` (the self-hosted compiler had them swapped), `typedef` and the
+ built-in `string` alias, struct constants (`std.Text.MAX`).
+- editor: quick fixes for hints (rename to `_`, make const, `<<`, stack
+ buffer), missing-import fixes for every module (rt, core, run, loaded files,
+ and std, icon and libraries listed in `src/lib/modules.txt`, scanned from
+ source, including static groups like `std.Text.itoa`), typo fixes for
+ functions, module exports, fields and static members.
+- zc0: packed byte strings, `u`/`m`/`d` as names, local `embed`, and the asm
+ enhancement bug parity found.
+- tooling: `make parity` (`src/tools/parity.sh`), the compiler split into
+ phase files, `docs/SPEC.md`, standard-library api docs and
+ `examples/std_tour.zc`, temporary notes removed, `PROPOSALS.md`.
+
+### in flight when this was written (not on the branch; re-brief if missing)
+these were running as agents in worktrees. if their branches were not merged
+before the session ended, the work is lost and each item below must be started
+again from its description in the open list.
+- spec verification (`tests/conformance/`), see "verify both compilers".
+- x86-64 jit phase 1, see "a hand-written x86-64 jit".
+- zc0 structs, enums and `?:`, see "zc0 structs".
+- runtime line tables and backtraces, see "runtime source positions".
+- bounds checking with `unbounded`, see "bounds checking".
+
## open, easiest first
-every item still to do, including the ones added after the list above. sorted
-by how hard each is to implement, so the large language features come last.
-the final full suite stays at the very end whatever its size.
+sorted by how hard each is to implement; the final full suite stays last.
+items with an architecture note carry the design worked out so far, enough to
+brief someone without re-reading the code.
-- [x] remove temporary markdown files: decide on `TASKLIST.md` (a record of an earlier session's requests), `docs/BOOTSTRAP-OWNERSHIP.md` (its problem is resolved) and `docs/design/handoff.md`, keeping anything still referenced from `README.md` or `ONBOARD.md`.
-- [x] verify every command in `ONBOARD.md` from a clean checkout and fix the ones that drifted. (`make check` is left to the final suite run below.)
-- [x] add `string` as a built-in alias of `char*`, in types, hovers and completions.
-- [x] untyped constants inside structs: `struct Text { const MAX = 24; }`, reached as `std.Text.MAX`, with the same rules as a local or top-level `const k = 5;`.
-- [ ] typo suggestions for field and method names: `p.lenght` and `std.Text.itao` suggest the closest member, with the language server's change-to quick fix.
- [ ] hover on standard-library members (`std.Text.itoa`, `std.array_contains`, a group name) returns nothing in the language server, though completion shows the same documentation; a struct static function in the document itself does show its hover. find where `do_hover` resolves qualified library members and fix it, with a hover check.
- [ ] `std.capture.end` writes its terminator at `rt.outbuf[rt.outn]`; when more than 256 characters were captured, `outn` equals the capacity and the 0 lands one word past the buffer. check and fix, with a regression program.
-- [ ] a bare call to a sibling static function inside a struct's method (`lim()` for a static `lim`) reports `lim is used but never defined`; resolve it like the bare struct constants now are.
-- [x] packed byte strings and `u`/`m`/`d` in zc0: match the self-hosted compiler's `bstr` support, and treat `u`, `m`, `d` as ordinary names (a recast is the letter directly followed by `*`; tags are accepted and ignored), keeping zc0's genome image byte-identical.
-- [x] write `docs/SPEC.md`, the language specification, from the self-hosted compiler as the reference, with the zc0 subset marked and every disagreement between prose and code listed.
-- [ ] verify both compilers against `docs/SPEC.md` with a fresh agent: one test program per rule, run on both, every deviation reported and triaged.
-- [x] a `make parity` runner that compiles the zc0-compatible programs (and the genome sources) with zc0 and with the self-hosted compiler, runs both images and compares output, so the two front ends can't disagree silently again (the `&&`/`||` precedence bug). (`src/tools/parity.sh`, `make parity`; by-design differences in `tests/parity.known`.)
-- [x] c typedefs: `typedef T name;` declares a type alias, including pointer, array and function types, usable everywhere a type is, shown in hovers.
-- [x] split `src/compiler/compiler.zc` into files by phase, listed in order in `src/compiler/parts`; the concatenation reproduces the old file exactly so every image stayed byte-identical. the makefile, tool scripts, `genmap` (which still writes one `compiler.zc` into a map directory), the language server (it embeds each part and serves them as the one document `tinyvm:/compiler.zc`), tests and docs read the list. the comments in `src/runtime/rt.zc` that say "compiler.zc" were left alone (rt.zc is part of the genome, and this change touched no genome source).
-- [ ] a cross-reference report: for every global of the compiler, the functions that write it and the ones that only read it, built from the language server's references so scoping is exact, runnable as a script and in ci so a new writer of core state shows up in review.
-- [ ] zc0 structs (word-sized fields, pointers, values, arrays of structs, field access), plain enums and `?:`, so the compiler's own sources can use records. this blocks the records refactor below.
-- [ ] (needs zc0 structs) group the compiler's parallel per-local arrays (`lname`, `ltype`, `lstate`, `lhome`, `lown`, ...) into one record per local with accessor functions, so a branch snapshot is one block copy and each field's invariant is written once next to the record. then do the same for symbols and types. the genome must keep reaching its fixpoint, and the analyzer's behavior must not change (all rejection suites and the program checks identical).
-- [ ] zc0 has no `?:`; add it so parity covers conditional expressions, and grow zc0's subset where it is cheap (structs and enums are the largest group of programs parity skips today).
-- [ ] remaining zc0 gaps: string literals over 4095 bytes, `embed` of an array type inside a function, `x as T` with more than a single name (`x as int*`), and zc0 silently accepting `.u` on a parameter where the self-hosted compiler rejects it; also `docs/history/43-stdlib/notes.md` still says zc0 reserves u/m/d (a history note: add a pointer forward rather than rewriting it).
+- [ ] a bare call to a sibling static function inside a struct's method (`lim()` for a static `lim`) reports `lim is used but never defined`; resolve it like the bare struct constants now are (`mstruct` in the declarations part).
- [ ] a run-only image accepts `void main()` from zc0 but the self-hosted compiler rejects it against `run.zc`'s `int main();` prototype; make the two agree.
-- [ ] fix the implementation bugs listed in `docs/SPEC.md` appendix b (after the verifier confirms them): `memdebug scrub;` rejected; enum members can't reference earlier members; a plain function redefinition silently shadows the first; a prototype after the definition hides it; `?:` with one int and one float branch gives garbage; `bool` not normalised; float global initializers rejected; a global initializer naming another global uses its address; `include std;` inside a function body; syntax-error recovery hiding later errors; unterminated `/*` and string literals; `x as int * y`; prototypes needing parameter names; `len(char*)` with typecheck off; duplicate `case` labels; local `const` in constant expressions; constant expressions without precedence (`1+2*3` is 9). also make zc0's integer literals match (`010`, overflow) and fix the prose items the appendix lists.
-- [ ] continue removing `unchecked` from the remaining runtime boundaries by teaching the analyzer the missing ownership and drop contracts; document any irreducible low-level escapes. the compiler, standard library and lsp no longer disable checking for their functions. status, from a trial that was reverted: with `unchecked` removed, `copy_w` and `fill_w` pass the analyzer once their gate stores go through `syscall(SYS_COPY, ...)`, `dgrow` once `w[-2] = it` becomes `own(w, it)`, `dpush` once `own(x, h[2])` comes before the store, and `dnew` as is. but the checked versions changed run-time behavior: 7 of the 87 program checks in `tests/test.sh` failed (closure cells, the proved-loop bounds check) and `tests/programs/share.zc` hung with a checked `cons`. so checked code in these functions inserts cleanup the runtime can't afford, and each one needs its contract taught to the analyzer, not just a rewrite that compiles. `free`, `recycle`, `recycle_leaf` and `gc` are the allocator and collector that the analyzer's own cleanup calls, so they stay unchecked and need to be documented as the irreducible escapes. `src/lib/actor.zc` has about 20 more.
-- [ ] document the public standard-library apis with concise descriptions of behavior, parameters, ownership and return values where applicable; update reference and learning entries, add executable examples and record implemented changes in history; keep prose lowercase and verify docs appear in hovers.
-- [ ] revise diagnostics, comments and learning/reference prose using professional compiler documentation guidance, preserving lowercase and adding message regressions.
-- [ ] `defer` statement: `defer expr;` or `defer { ... }` runs when the enclosing block ends, on every exit path (fall-through, `return`, `break`, `continue`), in reverse order of declaration, with the values its expressions name at the time the block ends. follows the c defer proposal (n3199 style) with ownership awareness: a deferred call that consumes an owner counts as its transfer, so the analyzer neither frees it twice nor reports it leaked.
-- [ ] test blocks: `test "name" { ... }` with `expect(cond)`, compiled only by `zy --test file.zc`, which runs each block and prints one line per test with the position of the first failed `expect`; skipped at parse time otherwise. built as a library through `run.syntax` and `run.statement_hook`, like actors.
-- [ ] bounds checking on by default for indexing heap pointers (checked against the block header's payload size) and typed arrays (`T[n]`, `T[?]`), stopping with the index, the length and the source line. a keyword `unbounded`, used like `unchecked` (function, block, or top-level for the rest of the unit), turns it off. `o3` implies `unbounded`, so o3 code never pays for bounds checks. constant indexes into fixed arrays are checked at compile time and emit nothing.
-- [ ] after the compiler namespace and fuzzing work, add more general functionality to the standard library.
-- [ ] a hand-written x86-64 jit, ported from the arm64 one: phase 1 translates ordinary blocks (shared translation table, coverage and invalidation; x86 emitter and instruction selection), validated program by program against the interpreter, and becomes the default x86-64 linux core when it matches everywhere. phase 2 compiles o3 regions and inlines enhancements like the arm64 backend does.
-- [ ] struct destructors: a struct may declare `fn drop()`, which the compiler calls wherever it frees an owned value of that type (scope end, reassignment, `rt.free`), before the memory is released. use it for file descriptors in `std.Host` and processes in `actor.zc`. decide and document what happens when an owner with a `drop` passes into unchecked code.
-- [ ] runtime source positions: a line table per function (code offset to source position) stored in the image, behind a `lines on;` switch like `docs on;`. faults, failed bounds checks and a new `rt.trace()` print `file:line in function` for every frame on the interpreter, microcore and javascript vm; the jit and llvm backends map native addresses back to vm code.
-- [ ] borrow returns tied to an argument, with syntax that stays out of the way: a function can return a pointer into one of its parameters (`find`, `skip_space`, `first`), the caller's analyzer treats the result as a borrow of whatever was passed, and freeing or moving that argument while the result is live is an error. the callee is checked to return only borrows of that parameter. prefer inference from the body over annotation; when a spelling is needed, keep it to the parameter's name.
-- [ ] variadic arguments and `std.print`. variadics know their count, keep each argument's type, allow several packs per function when their element types differ (`void test(...int a, ...char b)`), and allow a mixed pack of any types (`...any args`). `...*any args` makes the call comma-free: `std.print("x = " name ", and they are " age " years old.\n");`. `std.print` is a global, javascript-like print that takes any number of arguments and formats each by its type (numbers, floats, strings, byte strings, pointers).
-- [ ] continue fuzzing the compiler, analyzer, runtime, standard library, lsp, build tools and generated artifacts, including analyzer properties, memory-limit edges, compiler image mutation and long-running lsp memory use; fix discovered bugs and performance regressions. current coverage includes malformed parser inputs, source immutability across runtime compilation, allocation/gc leak deltas, configured-memory growth, and available native, microcore, javascript and webassembly execution hosts.
+- [ ] remaining zc0 gaps: string literals over 4095 bytes, `embed` of an array type inside a function, `x as T` with more than a single name (`x as int*`), zc0 silently accepting `.u` on a parameter, and integer literals (`010` is 8 in zc0, 10 in the compiler; zc0 saturates on overflow). `docs/history/43-stdlib/notes.md` still says zc0 reserves u/m/d: add a pointer forward rather than rewriting history.
+- [ ] (in flight) verify both compilers against `docs/SPEC.md` with a fresh agent that did not write it: expectations derived from the spec text before running anything, one program per rule under `tests/conformance/<section>/`, a runner `tests/conformance/run.sh`, each failure classified as self-hosted bug, zc0 bug, or spec error, and appendix b confirmed item by item. then add the runner to `tests/test.sh`.
+- [ ] fix the implementation bugs listed in `docs/SPEC.md` appendix b, once confirmed: `memdebug scrub;` rejected; enum members can't reference earlier members; a plain function redefinition silently shadows the first; a prototype after the definition hides it; `?:` with one int and one float branch gives garbage; `bool` not normalised; float global initializers rejected; a global initializer naming another global uses its address; `include std;` inside a function body; syntax-error recovery hiding later errors; unterminated `/*` and string literals; `x as int * y`; prototypes needing parameter names; `len(char*)` with typecheck off; duplicate `case` labels; local `const` in constant expressions; constant expressions without precedence (`1+2*3` is 9). fix the prose items the appendix lists too.
+- [ ] a cross-reference report: for every global of the compiler, the functions that write it and the ones that only read it. build it from the language server's references (`textDocument/references` on `build/bin/zclsp`, so scoping is exact) and classify each reference as a write when an assignment operator, `++` or `--` follows it. output under `build/xref/`; a committed baseline and a `--check` mode that fails when a new writer of a global appears, so it can run in ci. do it after the records refactor, which reshapes the globals.
+- [ ] (in flight) zc0 structs (word-sized fields only, matching the self-hosted layout of one word per field in order; reject packed small fields, nested structs by value, array fields, methods, constants and generics with clear messages), struct values, arrays of structs, `p.f`/`p->f`/`xs[i].f`, `rt.new(T)`, `sizeof`; plain enums (`name.B` access, the name as an int type); `c ? a : b` with c precedence and right associativity. zc0 needs just enough type tracking to know a name's struct. its output for the genome sources must stay byte-identical. tests `tests/programs/zc0struct.zc`, `zc0enum.zc`, `zc0cond.zc`; `make parity` should compare many more programs afterwards. this blocks the records refactor.
+- [ ] (needs zc0 structs) group the compiler's parallel per-local arrays (`lname`, `ltype`, `lstate`, `lhome`, `lown`, `lslot`, `ltag`, `lpos`, `lnsz`, `lleaf`, ...; many are declared as `word[NL] x_initial; word x = x_initial;` and grow) into one record per local with accessor functions, so a branch snapshot is one block copy and each field's invariant is written once next to the record. then symbols, then types. the genome must keep reaching its fixpoint and the analyzer's behavior must not change (rejection suites and program checks identical).
+- [ ] continue removing `unchecked` from the runtime. a reverted trial showed: `copy_w`/`fill_w` pass the analyzer when their gate stores go through `syscall(SYS_COPY, ...)`, `dgrow` with `own(w, it)` instead of `w[-2] = it`, `dpush` with `own` before the store, `dnew` as is; but the checked versions changed behavior (7 program checks failed, `tests/programs/share.zc` hung with a checked `cons`), so checked code inserts cleanup these functions can't afford. each needs its contract taught to the analyzer. `free`, `recycle`, `recycle_leaf`, `gc` are the allocator and collector the analyzer's own cleanup calls: document them as the irreducible escapes. `src/lib/actor.zc` has about 20 more.
+- [ ] revise diagnostics, comments and learning/reference prose using professional compiler documentation guidance, preserving lowercase and adding message regressions. touches messages everywhere, so do it when few other compiler changes are in flight.
+- [ ] `defer` statement: `defer expr;` or `defer { ... }` runs when the enclosing block ends, on every exit path, in reverse order, evaluating its expressions when it runs (like the c defer proposal), with ownership awareness: a deferred call that consumes an owner is that owner's transfer. architecture: grab the deferred statement's tokens at the `defer` (like `grab()` in the statements part) and keep a stack of [block depth, token list]. replay a list with `src_push(1, q, 0, 0); next(); stmt(); src_pop();`. block ends go through `block_close` (call it there before `exit_vars`, for entries at the current depth, newest first); `kw_return` evaluates its value first, then must replay every entry of the function (depth >= 1) before `exit_vars(1, 0)`; `kw_break` and `kw_continue` replay entries deeper than the loop's depth (`f[2] + 1`) before their `exit_vars`. after an early exit `live = 0`, so the analyzer state changed by the replay is discarded. closures keep their own base index. reject `return`, `break`, `continue` inside a deferred statement. defer must also work in unchecked code (`exit_vars` returns early there, so replay independently of `fchk`).
+- [ ] test blocks: `test "name" { ... }` with `expect(cond)`, compiled only by `zy --test file.zc`, which runs each block and prints one line per test with the position of the first failed `expect`; skipped at parse time otherwise. build it as a library through `run.syntax` and `run.statement_hook`, like `src/lib/actor.zc`.
+- [ ] (in flight) bounds checking on by default, `unbounded` to turn it off (function prefix, block, top-level `unbounded;`, mirroring `unchecked`), implied by `o3`. architecture: indexing is compiled in the postfix `[` handling of the expressions part; growable arrays already check (`dat`, `range_jz`, the `outside` enhancement, `proven()` removing checks a loop test already did). fixed arrays `T[n]` with a variable index get the same inline check against the constant `n`. pointers get a runtime call (for example `rt.bchk(p, i)`) that checks only when `p` is the start of a live heap block (header check word `p ^ MAGIC`, `paylen`), skipping constant index 0 and sizes the analyzer knows (`lnsz`). reports go through `oob`. the runtime, core, compiler parts, server, `run.zc` and `build.zc` start with `unbounded;`, which zc0 accepts and ignores (genome bytes unchanged). keep std, icon and actor checked unless a function touches raw memory on purpose. measure interpreter time before and after.
+- [ ] after the fuzzing work, add more general functionality to the standard library.
+- [ ] (in flight) a hand-written x86-64 jit, ported from the arm64 one in `src/core/core.c` (the `#ifdef ZYJIT` section; `ZYJIT` is only defined for `__aarch64__`). phase 1: a separate macro (for example `ZYJIT_X64`), shared architecture-neutral parts (translation table `tab`, coverage `cov`, invalidation `be_drop`, block boundaries, dispatcher) and an x86 emitter. registers: r12 memory base, r13 data stack, r14 return stack, r15 translation table, rbx state block (the arm64 x19..x23); system v calls to c helpers. semantics identical to the interpreter (wrapping, 0/1 comparisons, literal encoding, stack and `MW` checks, retranslation after stores into code). o3 regions take the portable path in phase 1. validate every `tests/programs`, `examples` and `examples/learn` program on interpreter and jit with identical output (a driver under `tests/drivers/`), the rejection suites, icon and actor fixtures; report timings for a compute example and for compiling the compiler. make it the default x86-64 linux core only when everything matches; `-DZYINTERP` still forces the interpreter. phase 2: o3 regions and inlined enhancements. note the llvm backend (`-DZYLLVM`) is the other native path; the default build could also enable it whenever `llvm-config` is found.
+- [ ] struct destructors: a struct may declare `fn drop()`, called wherever the compiler frees an owned value of that type, before the memory is released. architecture: the compiler frees owned locals in `freevar` (analyzer part), called from `exit_vars`, reassignment and explicit `rt.free`/`rt.recycle` calls (`s_free`, `s_recycle` handling in the call code); when the local's static type is a pointer to a struct with a `Name.drop` method, emit a call to it first. objects freed by the collector or inside unchecked code do not run `drop`: document that. first users: file descriptors in `std.Host`, processes in `actor.zc`.
+- [ ] (in flight) runtime source positions. architecture: at each statement start (`stmt()`) record (code address `here`, line); per function a permanent data block [entry, end, name, file, count, pairs...] linked into a runtime list (`rt.line_blocks`), or appended to run-only images by `build_image` like the symbol blob. `lines on;`/`lines off;` like `docs on;`; on for user programs, off for the genome unless the growth is small. a new syscall op returns the return-stack pointer (the return stack is in vm memory, 0x1A4100..0x1B40FF, growing up); implement it in `src/core/core.c`, `src/micro/micro.c`, `src/js/tinyvm.ts` and the wasm port. `rt.trace()` walks the return stack, printing ` at file:line in function` for words inside a known function range. the runtime's fatal reports (`oob`, bad heap pointer, double free, out of memory, frame overflow) print the trace after their unchanged first line. check mode skips all of it.
+- [ ] borrow returns tied to an argument. inference already works for a callee defined before the call: `char* skip(char* s) { ...; return s + i; }` makes `let r = skip(t); rt.free(t); r[0]` an error. the gap: when the call comes before the callee's definition, nothing is reported and the program reads freed memory. extend the deferred effect requirements (`effect_require`, `effect_finish` at unit end) so a forward-called function whose return turns out to alias a parameter produces the same error. for bodyless declarations, externs and function types, add an unobtrusive spelling, for example a `borrows s` clause after the parameter list (`char* skip(char* s) borrows s;`), checked against the body when one exists.
+- [ ] variadic arguments and `std.print`. design: a pack is passed as one hidden argument, a caller-built read-only growable-array handle (`fixed T[?]` view: [len, cap, items, element size] in the caller's frame, so `len(a)` and `a[i]` work unchanged and nothing is allocated). `...int a` is a typed pack; several packs per function when their element types differ (`void f(...int a, ...char b)`): each extra argument goes to the pack whose element type matches its static type, an ambiguous match is an error, packs come after the fixed parameters. `...any args` packs each value with a kind code (int, float, char, string, bstr, pointer, ...) and its type record: `any` is a small built-in record { kind, value, type }. `...*any args` makes the call comma-free: after the fixed arguments, the parser reads unary expressions until `)`, commas optional, so `std.print("x = " name ", age " age "\n");` works and binary expressions must be parenthesized. `std.print(...*any args)` prints each argument by its kind (`put_n`, the float printer, `put_s`, `put_bs`, a character for `char`, hex for pointers).
+- [ ] continue fuzzing the compiler, analyzer, runtime, standard library, lsp, build tools and generated artifacts, including analyzer properties, memory-limit edges, compiler image mutation and long-running lsp memory use; feed generated programs to `make parity` for differential fuzzing between zc0 and the self-hosted compiler; fix discovered bugs.
- [ ] keep improving the borrow checker: fewer annotations in ordinary code, clearer messages naming both the owner and the conflicting use, and new fixtures for each rule that changes.
-- [ ] run the full suite once everything above is done, fix what it finds, and only then tick this item.
+- [ ] run the full suite once everything above is done (`make test JOBS=4`; `make check` is the quick one), fix what it finds, and only then tick this item.
+
+## done in the sorted list
+- [x] remove temporary markdown files (`TASKLIST.md`, `docs/design/handoff.md` deleted; `BOOTSTRAP-OWNERSHIP.md` moved to `docs/history/`).
+- [x] verify every command in `ONBOARD.md` from a clean checkout and fix the ones that drifted.
+- [x] add `string` as a built-in alias of `char*`.
+- [x] untyped constants inside structs, reached as `Text.MAX` and `std.Text.MAX`.
+- [x] typo suggestions for field and member names, with the change-to quick fix.
+- [x] packed byte strings and `u`/`m`/`d` in zc0, byte-identical genome.
+- [x] `docs/SPEC.md`, with the zc0 subset (appendix a) and disagreements and bugs (appendix b).
+- [x] `make parity`: zc0 against the self-hosted compiler on every program zc0 accepts.
+- [x] c typedefs.
+- [x] the compiler split into phase files listed in `src/compiler/parts`.
+- [x] standard-library api documentation, `examples/std_tour.zc`.