writeonce/docs/superpowers/specs/2026-08-10-logwatcher-gap-closure-design.md
shoney.arickathil 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

12 KiB
Raw Permalink Blame History

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 use line, no namespace — the same status the existing print, print_int, now, words, count, latest builtins already have, and the same flat WO_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_err joins 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 & reports WO-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: or binds loosest, then and, then comparison, then the existing arithmetic ladder. This makes if a == 1 and b == 2 parse as intended without parentheses — the sample's dominant shape.
  • Semantics. Short-circuit, Bool-typed operands only, Bool result. No truthiness — a non-Bool operand is a type error, consistent with principle 13.
  • Lowering. Compare-and-jump on existing opcodes (JZ plus 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/or get precedence goldens (including a == 1 and b == 2 without parens), short-circuit behavior, and a must-fail for a non-Bool operand. Each core builtin gets a golden exercising it plus a bounds-trap fixture where indices apply. time.iso/time.local get fixtures against a fixed injected clock so output is deterministic.
  • The sample is the integration test. woc docs/examples/log-watcher is 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/or add no opcode and time/env extend an existing module pattern.

Success criteria

  1. 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.
  2. Plans 8 and 9 reflect every addition and cut; plan 8 Task 7 is gone.
  3. WO-E205 is documented as reachable but unenforced (corrected 2026-08-11, see § 5 — an earlier "unreachable-by-design" claim here was wrong), and types.ml's header no longer claims a satisfaction set is produced.
  4. docs/00-code-review.md is a stub; no second roadmap exists in the repo.
  5. 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.