- 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>
12 KiB
log-watcher gap closure — spec amendments + plan reconciliation
Date: 2026-08-10
Status: approved design, pre-implementation
Scope: amending the systems-track spec with four surface gaps the log-watcher
sample revealed, recording three scope cuts, correcting two false status claims,
and retiring a parallel roadmap
Amends: 2026-08-01-systems-track-design.md
(Part 1 verdict table, Part 3 stdlib table)
Supersedes: docs/00-code-review.md (extracted, then reduced to a stub)
Companion specs: 2026-08-01-oop-compiler-vm-design.md
Affected plans: plan 8,
plan 9,
plan 10
Motivation
docs/00-code-review.md was written as a gap analysis: what must exist before
the log-watcher sample compiles. Verified against the code, most of its
"missing" rows are correct — the front end genuinely cannot lex or parse roughly
200 constructs the sample uses. But it also carried three false claims, omitted
the single largest piece of work, and proposed a Phase 1–4 roadmap that competes
with the approved story iterations.
Its real contribution is four surface gaps that no approved spec ever named. Those are the substance of this amendment. The competing roadmap is retired; the false claims are corrected at their sources.
Measured baseline, woc docs/examples/log-watcher over 7 files:
307 diagnostics — 167 WO-E101 (parse) + 140 WO-E207 (unknown type).
Iteration 7 closes when that number is zero.
Decisions locked during brainstorming
| Question | Decision |
|---|---|
Status of docs/00-code-review.md |
Scratch input. Findings extracted here; the file becomes a stub pointing at docs/00-status.md. Its Phase 1–4 roadmap is retired — story iterations 4→5→6→7 remain the only sequence. |
| Shape of the text/collection builtins | Bare globals, no import. len, push, split_ws … are always in scope, like the existing print/now/count/latest. Capability modules (fs, proc, net, time, json, env) stay use-imported and qualified. |
throw |
Cut from the critical path — 0 uses in the sample. |
time.mono |
Cut — 0 uses. |
is |
Cut — 0 uses. Empties plan 8 Task 7, whose abstract half was rejected 2026-08-10, so the task is deleted rather than deferred. |
#if build flags |
Kept in plan 8 Task 9 despite 0 uses. |
| Emitter sequencing | Unchanged: iteration 4 before iteration 5. Plan 8's tasks state that features "lower onto existing opcodes" and name exactly three fenced VM changes — wording that presupposes an emitter. Growing the surface first would force a much larger emitter later. |
1. Amendment — core builtins (new Part 3 section)
The sample calls 22 unqualified builtin names across ~176 sites, none of
them in any spec: len ×55, push ×17, byte_at ×11, starts_with ×9,
index_of ×8, has ×7, split ×6, split_ws ×6, join ×5, parse_int ×5,
trim ×4, slice ×4, substr ×4, pop ×3, ends_with ×2,
last_index_of ×2, to_lower ×2, sort ×2, char_of ×1, shift ×1,
remove ×1, reverse ×1.
Part 3 gains a core builtins section, distinct from the capability modules:
- Always in scope. No
useline, no namespace — the same status the existingprint,print_int,now,words,count,latestbuiltins already have, and the same flatWO_B_*id space in the VM's builtin table. - Rationale. The sample committed to this spelling at 176 sites before the
spec had an opinion, and "samples force the grammar" (principle 8) makes that
binding. Qualifying them (
text.len) would add an import line to every file and buy nothing: these are language primitives, not capabilities — they touch no syscall, need no audit, and cannot be refused. - Grouping (documentation only, not namespaces): text operations, collection operations, map operations.
- Contract per builtin is fixed arity with typed parameters, resolved at
compile time like every other builtin; out-of-range indices trap
(
T_BOUNDS), never return a sentinel. print_errjoins this set (Part 2 already named it; Part 3 never listed it).
Deliberately not adopted: iteration/closure builtins (map, filter,
reduce) — the sample uses explicit loops throughout, and adding higher-order
functions would require a function-value type the language does not have.
2. Amendment — time gains calendar surface
Part 3's time row lists now(), mono(), sleep(ms). The sample also calls:
| Builtin | Sites | Why |
|---|---|---|
time.iso(ms) -> Text |
2 | JSONL detection timestamps and MCP response fields need a stable textual instant |
time.local(ms) -> {year, month, day, hour, minute, dow} |
1 | cron next-fire computation needs broken-out calendar fields, including day-of-week |
Both are added. mono() is cut (0 uses) and returns when a workload needs
monotonic math. The record time.local returns is a plain value record, so it
needs no new type machinery beyond the typedef records plan 8 Task 4 already
lands.
3. Amendment — boolean operators (new verdict-table row)
The sample uses and at 35 sites and or at 20. Neither exists in the
language, and — the reason this went unnoticed — neither the verdict table nor
any plan ever mentioned boolean operators at all, in either spelling: there is
no &&/|| row, and Haxe's own operators were never enumerated.
The verdict table gains one row: and / or — adopt, spelled as words
rather than &&/||.
- Spelling rationale. The sample chose words; the lexer has no
&case at all (a bare&reportsWO-E001), so words cost nothing to add as keywords, and they read better in the conditional-heavy code the sample is full of. - Precedence. One new level below comparison and above assignment:
orbinds loosest, thenand, then comparison, then the existing arithmetic ladder. This makesif a == 1 and b == 2parse as intended without parentheses — the sample's dominant shape. - Semantics. Short-circuit,
Bool-typed operands only,Boolresult. No truthiness — a non-Booloperand is a type error, consistent with principle 13. - Lowering. Compare-and-jump on existing opcodes (
JZplus a jump), no new opcode and no VM change.
4. Amendment — env is the sixth module
Part 2 specifies env.args(), env.get(name), env.exit(code),
env.stopping(); Part 3's table omits env while calling itself "five builtin
modules". The sample uses env.get ×1 and env.stopping ×4. Part 3's table
gains an env row and the count becomes six.
5. Corrections to false status claims
Both were asserted in the review doc; both are corrected at their real source rather than in the retired file.
Structural interface satisfaction is not implemented. WO-E205 is declared
and never emitted. The review listed satisfaction checking as implemented,
which is false. This amendment originally also called it unreachable by
design, not owed — that half is wrong, and corrected here (plan 3 Task 4
review, 2026-08-11): the check's one legal home, a site where a value is used
at an interface-typed position, is exercised by the milestone grammar. An
interface-typed parameter accepting a concrete class that doesn't structurally
satisfy it compiles clean today, then reaches wovm as an ICALL with no
matching vtable slot, which traps WO_T_BOUNDS at runtime instead of failing
to compile — even though the violation is statically provable (the class's
method set is fully known). See
01-error-catalog.md's "Reachable but
unenforced" section for the repro and
tests/corpus/trap/unsatisfied-interface/ for the pinned current behavior.
This is an owed gap, not a design decision — it stays off the log-watcher
critical path only because the sample declares no interfaces, not because the
gap doesn't exist.
?T is plumbed, not enforced. The review listed "Nullable types ?T" as
implemented — the same conflation already corrected in
docs/plan/compiler/nullable-types-implementation.md. No new action; noted here
so the two documents agree.
6. What the review omitted — the emitter
The review is titled "Compilation Requirements" and its Phase 4 promises
"end-to-end compile + run", but it never lists the bytecode emitter as work.
There is no emit.ml, no byte-writing anywhere in the compiler, no --emit or
-o flag, and wob_kind_of_typ exists but is never called. That is
plan 3 — story iteration 4,
an entire slice — and it is the current NEXT PLAN.
Consequence for iteration 4's scope, to be stated on the board: the emitter proves the pipeline on the milestone grammar only. The sample's ~200 unparseable constructs are iterations 5–6 work; iteration 4 must not be judged against the sample.
7. Plan updates
| Plan | Change |
|---|---|
| plan 8 | Task 2 gains and/or (keywords, new precedence level, compare-and-jump lowering, short-circuit, Bool-only). Task 5 loses throw — catch frames ship without the explicit-raise half, and the error-payload slot plus its .wob version note go with it. Task 7 is deleted (is cut, abstract rejected); later tasks renumber. The Goal line drops is. |
| plan 9 | Gains a core-builtins task covering the 22 bare globals plus print_err. time task gains iso and local, loses mono. env is named as a module rather than loose Part-2 prose. |
| plan 3 | Unchanged. |
| plan 10 | Acceptance gains the diagnostic-count gate: 307 → 0. |
01-error-catalog.md |
WO-E205 re-filed as reachable but unenforced — corrected 2026-08-11, see § 5 — with its repro; WO-E208/E210/E211–E213 keep their existing reserved entries. |
docs/00-status.md |
NEXT PLAN gains the milestone-grammar-only note; pending list gains the three cuts under the parked section. |
docs/00-code-review.md |
Reduced to a stub: one paragraph saying its findings landed here and in the plans, pointing at docs/00-status.md. |
Error handling
Nothing in this amendment adds an error-handling mechanism. and/or produce
ordinary type errors on non-Bool operands (reusing WO-E201 once that code is
wired). Core builtins trap on out-of-range access rather than returning
sentinels, matching the existing container builtins. Cutting throw leaves the
uncaught-trap surface exactly as it is today.
Testing
- Per amendment, corpus fixtures in the task that lands it:
and/orget precedence goldens (includinga == 1 and b == 2without parens), short-circuit behavior, and a must-fail for a non-Booloperand. Each core builtin gets a golden exercising it plus a bounds-trap fixture where indices apply.time.iso/time.localget fixtures against a fixed injected clock so output is deterministic. - The sample is the integration test.
woc docs/examples/log-watcheris run at the end of every iteration from 5 onward and its diagnostic count recorded; the number must fall monotonically from 307 and reach 0 at iteration 7. - No new VM tests from this amendment except the core builtins' own, since
and/oradd no opcode andtime/envextend an existing module pattern.
Success criteria
- The systems-track spec's Part 1 has a boolean-operator row and its Part 3 lists six modules plus a core-builtins section covering all 22 names.
- Plans 8 and 9 reflect every addition and cut; plan 8 Task 7 is gone.
WO-E205is documented as reachable but unenforced (corrected 2026-08-11, see § 5 — an earlier "unreachable-by-design" claim here was wrong), andtypes.ml's header no longer claims a satisfaction set is produced.docs/00-code-review.mdis a stub; no second roadmap exists in the repo.- The 307-diagnostic baseline is recorded in plan 10 as its acceptance gate.
Out of scope
throw, time.mono, is, higher-order/iteration builtins, and interface
satisfaction enforcement — each parked with its reason above. Implementing any
amendment is the plans' job, not this spec's.