Files
AILang/examples/fieldtest/kem_3_stub_consumer.ail
T
Brummel aa49a56d5a fieldtest: kernel-extension-mechanics — 6 examples, 9 findings (3 bugs, 1 friction, 1 spec_gap, 4 working)
Post-audit fieldtest for the kernel-extension-mechanics milestone.
Fieldtester wrote 6 .ail consumer programs against the public
interface only (design ledger + spec + ail CLI; no source crate
reads), one per axis with two for the param-in pair (accept +
reject). All artefacts in examples/fieldtest/ + the spec.

**Working (4):** F5 NewTypeNotConstructible diagnostic is precise
(names the home module + missing def in one sentence). F6 Term::New
codegen-deferral diagnostic explicitly names the raw-buf milestone
where support lands. F7 param-in accept-path is end-to-end (check +
build + run prints 17). F8 ParamNotInRestrictedSet names type-arg
+ var + TypeDef.

**Bugs (3, action: debug):**

- F1 (axis 1) — Same-module type-scoped call `(app Type.member …)`
  rejected with phantom-qualified `expected <this>.T, got T`.
  Bare `(app member …)` from inside Type's home module works.
  Spec's "Canonical form decision" promises type-scoped works
  uniformly; the resolver appears to disagree with the workspace
  pre-pass on whether `<this-module>.T` equals bare `T`. Repro:
  examples/fieldtest/kem_2b_min_repro.ail.

- F3 (axis 3) — Kernel-tier auto-import scopes the name but does
  not register the module as a resolvable qualifier prefix. Per
  the pre-pass, a bare `StubT` in a type slot is qualified to
  `kernel_stub.StubT`; the resolver then rejects `kernel_stub`
  as unknown. Asymmetric: prelude's free fns work (per
  prelude_free_fns.rs), but the stub's TypeDef is effectively
  unreachable from any consumer. Repro:
  examples/fieldtest/kem_3_stub_consumer.ail.

- F4 (axis 3, spec/ship coherence) — The spec's prep.3 worked-
  consumer relies on `(new StubT 42)`, but the shipped STUB_AIL
  has only a TypeDef + ctor — the `(fn new ...)` the spec
  designed is missing from the implementation. The diagnostic
  the resolver does emit on the consumer (F5) is precise; the
  bug is the absent def itself. Resolution: re-add the `new` to
  STUB_AIL (the spec's design), refresh the drift pin.

**Friction (1, action: plan-or-defer):**

- F2 — Loader's sibling-only module resolution forces symlinks
  for any cross-module fixture sitting outside the canonical
  `examples/` directory. The kem_1 example required local
  symlinks for std_list.ail + std_maybe.ail. Secondary: the
  diagnostic message names only the .ail.json path even though
  .ail also resolves — actively misleading. Recommended: small
  tidy iter for loader workspace-search-path + diagnostic clarity.

**Spec-gap (1, action: ratify):**

- F9 — `design/models/0007-kernel-extensions.md:80` uses `unit`
  as a value literal of type Unit; the checker treats it as a
  Term::Var lookup and emits [unbound-var]. Either ratify `unit`
  as the canonical Unit-value literal in the language, or tighten
  the design model to use the existing idiom. The current model/
  surface disagreement is a small but real LLM-author trap.

**Symlinks committed** as evidence of the F2 workaround:
examples/fieldtest/std_list.ail and std_maybe.ail are symlinks
into ../. They are the fingerprint of the friction — removing
them silently would erase the evidence.

Per Iron Law, fieldtester did not work around bugs — they were
all surfaced and recorded. The kem_2b_min_repro.ail fixture
exists specifically because F1 surfaced mid-drafting and got
minimised; kem_3_stub_consumer.ail also stays as the F3 RED-side
fixture.

Triage (next-step routing for /boss):

  F4 → small inline fix (add (fn new ...) to STUB_AIL + drift refresh)
  F9 → small inline ratify (whitepaper edit)
  F2 → backlog issue, deferred (single tidy iter someday)
  F1, F3 → debug skill dispatches, then implement mini-mode
  F5-F8 → carry-on, recorded as wins
2026-05-28 19:19:00 +02:00

52 lines
2.1 KiB
Plaintext

; Fieldtest kem.3 (Axis 3, kernel-tier modules + auto-import) — a
; consumer that references `kernel_stub`'s TypeDef without an
; `(import kernel_stub)` declaration. Per spec § "Iteration prep.3":
;
; - The module's top-level defs are accessible bare in every other
; module of the workspace, with no `(import ...)` declaration
; required.
; - The module's types are accessible bare in type position.
;
; Outcome: `ail check` fails with
;
; [unknown-module] unwrap_int: unknown module prefix
; `kernel_stub` in qualified reference
;
; The workspace pre-pass rewrites bare `StubT` to qualified
; `kernel_stub.StubT` (correct per prep.1's `qualify_workspace_term`);
; but the resolver does not accept `kernel_stub` as a valid module
; prefix because the consumer has no explicit `(import kernel_stub)`.
; That is, the qualification pre-pass and the auto-import scope are
; not cooperating — the auto-import does NOT add the kernel module
; to the resolver's known-prefixes set.
;
; Workarounds attempted:
;
; - Adding `(import kernel_stub)`: fails earlier with
; [module-not-found] expected at <sibling>/kernel_stub.ail.json
; — the kernel stub has no on-disk file, it is built into the
; compiler binary.
; - Bare `StubT` everywhere: same outcome as above (the pre-pass
; qualifies it before the resolver sees it).
;
; Prelude's bare fns (`print`, `lt`, etc.) DO work — prelude_free_fns
; ratifies that. So the bug is specifically about TypeDefs in type
; position for kernel-tier modules other than prelude. The shipped
; kernel_stub TypeDef appears unreachable from any consumer in
; practice.
(module kem_3_stub_consumer
(fn unwrap_int
(doc "Project the Int back out of a StubT<Int>. Bare `StubT` in the type slot exercises the kernel-tier auto-import — and currently fails to resolve.")
(type (fn-type (params (con StubT (con Int))) (ret (con Int))))
(params s)
(body (match s (case (pat-ctor Stub x) x))))
(fn main
(type (fn-type (params) (ret (con Unit)) (effects IO)))
(params)
(body
(let s (term-ctor StubT Stub 7)
(seq (app print (app unwrap_int s)) (do io/print_str "\n"))))))