// Conformance corpus: the transpiler's output contract is that an author who // passes tsc and the subset checker NEVER sees a Zig compile error. Each case // is a small subset-legal module exercising a type-boundary combination // (literal unions x comparisons x assignments x args/returns x elements x // integer inference). A case either EMITS — transpile-clean must imply // zig-build-clean — or is GATED by a named teaching rule at check time. // // The zig-build half runs as one `zig test` over every emitted module // (skipped when no zig toolchain is on PATH; the gating half always runs). import test from "node:test"; import assert from "node:assert/strict"; import { execFileSync, spawnSync } from "node:child_process"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { transpile, transpileFiles } from "./helpers.ts"; const pkg = path.dirname(path.dirname(fileURLToPath(import.meta.url))); const hasZig = spawnSync("zig", ["version"], { stdio: "ignore" }).status === 0; interface Case { readonly name: string; /// Expected teaching rule; omitted means the case must emit Zig that compiles. readonly gate?: string; readonly src: string; } const enumCases: Case[] = [ { name: "cross-enum equality, superset filter over category", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export interface Expense { readonly id: number; readonly category: Category; } export interface Model { readonly expenses: readonly Expense[]; readonly filter: CategoryFilter; } export type Msg = | { readonly kind: "set_filter"; readonly filter: CategoryFilter } | { readonly kind: "clear" }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "set_filter": return { ...model, filter: msg.filter }; case "clear": return { ...model, filter: "all" }; } } export function visible(model: Model): readonly Expense[] { return model.expenses.filter((e) => model.filter === "all" || e.category === model.filter); } `, }, { name: "cross-enum inequality", src: ` export type Small = "a" | "b"; export type Big = "a" | "b" | "c"; export function differs(s: Small, b: Big): boolean { return s !== b; } `, }, { name: "cross-enum against an optional of the other union", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export function matches(category: Category, filter: CategoryFilter | null): boolean { return filter === null || category === filter; } `, }, { name: "cross-enum with both sides optional (null equals only null)", src: ` export type Small = "a" | "b"; export type Big = "a" | "b" | "c"; export function same(s: Small | null, b: Big | null): boolean { return s === b; } `, }, { name: "cross-enum equality with partial overlap", src: ` export type Left = "x" | "y"; export type Right = "y" | "z"; export function overlap(l: Left, r: Right): boolean { return l === r; } `, }, { name: "cross-enum assignment: subset value into superset field", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export interface Model { readonly filter: CategoryFilter; } export type Msg = | { readonly kind: "pick"; readonly category: Category } | { readonly kind: "clear" }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "pick": return { filter: msg.category }; case "clear": return { filter: "all" }; } } `, }, { name: "cross-enum function argument", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export function isShown(filter: CategoryFilter): boolean { return filter !== "all"; } export function categoryShown(category: Category): boolean { return isShown(category); } `, }, { name: "cross-enum function return", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export function asFilter(category: Category): CategoryFilter { return category; } `, }, { name: "cross-enum array literal element", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export function withAll(category: Category): readonly CategoryFilter[] { return [category, "all"]; } `, }, { name: "cross-enum in ternary branches", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export function pick(category: Category, everything: boolean): CategoryFilter { const filter: CategoryFilter = everything ? "all" : category; return filter; } `, }, { name: "reversed literal comparison (literal on the left)", src: ` export type CategoryFilter = "all" | "food" | "travel" | "gear"; export function unfiltered(filter: CategoryFilter): boolean { return "all" === filter; } `, }, { name: "reversed kind comparison (literal on the left)", src: ` export type Msg = { readonly kind: "add" } | { readonly kind: "remove" }; export function isAdd(msg: Msg): boolean { return "add" === msg.kind; } `, }, { name: "optional enum against its own literal", src: ` export type Category = "food" | "travel" | "gear"; export function isFood(category: Category | null): boolean { return category === "food"; } `, }, { name: "same enum, optional against plain (regression)", src: ` export type Category = "food" | "travel" | "gear"; export function sameCategory(a: Category | null, b: Category): boolean { return a === b; } `, }, { name: "relational comparison on literal-union values is taught, not emitted", gate: "NS1004", src: ` export type Rank = "bronze" | "silver" | "gold"; export function before(a: Rank, b: Rank): boolean { return a < b; } `, }, { name: "number-literal unions compare across aliases (shared integer repr)", src: ` export type Bit = 0 | 1; export type Level = 0 | 1 | 2; export function matches(b: Bit, l: Level): boolean { return b === l; } `, }, { name: "plain alias of an enum compares as the same enum", src: ` export type Category = "food" | "travel" | "gear"; export type Chosen = Category; export function same(a: Category, b: Chosen): boolean { return a === b; } `, }, { name: "cross-enum equality under a logical chain in a filter callback", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export interface Item { readonly id: number; readonly category: Category; readonly active: boolean; } export function shown(items: readonly Item[], filter: CategoryFilter): readonly Item[] { return items.filter((i) => i.active && (filter === "all" || i.category === filter)); } `, }, { name: "cross-enum comparison between two narrowed union payloads", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export type Ev = | { readonly kind: "tag"; readonly category: Category } | { readonly kind: "pick"; readonly filter: CategoryFilter }; export function samePick(a: Ev, b: Ev): boolean { if (a.kind !== "tag") return false; if (b.kind !== "pick") return false; return a.category === b.filter; } `, }, { name: "cross-enum through a null-coalescing fallback", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export function effective(stored: CategoryFilter | null, category: Category): CategoryFilter { return stored ?? category; } `, }, ]; const numberCases: Case[] = [ { name: "payload demand reaches the model field it is assigned into", src: ` export interface Model { readonly durationSeconds: number; readonly remainingSeconds: number; readonly running: boolean; } export type Msg = | { readonly kind: "tick" } | { readonly kind: "set_duration"; readonly seconds: number }; export function initialModel(): Model { return { durationSeconds: 300, remainingSeconds: 300, running: false }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "tick": { const remaining = model.remainingSeconds - 1; if (remaining === 0) { return { ...model, remainingSeconds: remaining, running: false }; } return { ...model, remainingSeconds: remaining }; } case "set_duration": { if (msg.seconds <= 0) return model; return { ...model, durationSeconds: msg.seconds, remainingSeconds: msg.seconds }; } } } `, }, { name: "minimal demand-across-assignment edge", src: ` export interface Model { readonly total: number; } export type Msg = | { readonly kind: "set"; readonly value: number } | { readonly kind: "reset" }; export function update(model: Model, msg: Msg, bytes: Uint8Array): Model { switch (msg.kind) { case "set": { const b = bytes[msg.value]; return { total: msg.value + b }; } case "reset": return { total: 0 }; } } `, }, { name: "float taint flows backward: field and payload agree on f64", src: ` export interface Model { readonly ratio: number; } export type Msg = | { readonly kind: "set"; readonly value: number } | { readonly kind: "halve" }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "set": return { ratio: msg.value }; case "halve": return { ratio: model.ratio * 0.5 }; } } `, }, { name: "fractional literal reaching an index slot is taught", gate: "NS1016", src: ` export function read(bytes: Uint8Array): number { let i = 0; i = 1.5; return bytes[i]; } `, }, { name: "payload both indexed and compared with a fraction is taught", gate: "NS1016", src: ` export type Msg = { readonly kind: "at"; readonly pos: number } | { readonly kind: "noop" }; export function read(msg: Msg, bytes: Uint8Array): number { switch (msg.kind) { case "at": { if (msg.pos === 0.5) return 0; return bytes[msg.pos]; } case "noop": return 0; } } `, }, { name: "float-valued field flowing into an index slot is taught", gate: "NS1016", src: ` export interface Model { readonly ratio: number; } export function init(): Model { return { ratio: 0.5 }; } export function sample(model: Model, bytes: Uint8Array): number { const at = model.ratio; return bytes[at]; } `, }, { name: "length scaled by a fraction widens into the float site", src: ` export function half(bytes: Uint8Array): number { return bytes.length * 0.5; } `, }, { name: "float parameter compared against a length read", src: ` export function pastEnd(cursor: number, bytes: Uint8Array): boolean { return cursor * 1.5 > bytes.length; } `, }, { name: "returns mixing a length read with a fractional literal", src: ` export function measure(bytes: Uint8Array, empty: boolean): number { if (empty) return 0.5; return bytes.length; } `, }, { name: "fractional literal used directly as an index is taught", gate: "NS1016", src: ` export function bad(bytes: Uint8Array): number { return bytes[1.5]; } `, }, { name: "optional payload with integer fallback feeding an index", src: ` export interface Model { readonly cursor: number | null; } export function at(model: Model, bytes: Uint8Array): number { const i = model.cursor ?? 0; return bytes[i]; } `, }, { name: "demand travels through a chain of locals into the field", src: ` export interface Model { readonly offset: number; } export type Msg = { readonly kind: "move"; readonly by: number } | { readonly kind: "stay" }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "move": { const step = msg.by; const next = step + model.offset; return { offset: next }; } case "stay": return model; } } export function read(model: Model, bytes: Uint8Array): number { return bytes[model.offset]; } `, }, { name: "callee demand claims the caller's field argument", src: ` export interface Model { readonly at: number; } export function byteAt(bytes: Uint8Array, i: number): number { return bytes[i]; } export function sample(model: Model, bytes: Uint8Array): number { return byteAt(bytes, model.at); } `, }, { name: "Math.max mixing an integer constant with a float demotes the constant", src: ` export const FLOOR = 4; export function clampScale(x: number): number { return Math.max(FLOOR, x * 0.25); } `, }, { name: "Math.min mixing a float expression with a length read widens the read", src: ` export function capped(x: number, bytes: Uint8Array): number { return Math.min(x * 0.5, bytes.length); } `, }, { name: "guarded payload access through and/or chains and an else branch", src: ` export type Msg = { readonly kind: "add"; readonly n: number } | { readonly kind: "zero" }; export function inRange(msg: Msg, bytes: Uint8Array): boolean { return msg.kind === "add" && msg.n < bytes.length; } export function inRangeOrZero(msg: Msg, bytes: Uint8Array): boolean { return msg.kind !== "add" || msg.n < bytes.length; } export function low(msg: Msg): number { if (msg.kind !== "add") { return 0; } else { return msg.n & 255; } } `, }, { name: "template hole fed by a length read stays integer", src: ` import { asciiBytes } from "@native-sdk/core"; export function label(items: Uint8Array): Uint8Array { return asciiBytes(\`count \${items.length}\`); } `, }, { name: "demanded payload appended to a number array widens at the element", src: ` export function record(samples: readonly number[], n: number, bytes: Uint8Array): readonly number[] { const probe = bytes[n]; return [...samples, n + probe]; } `, }, { name: "map over a number array keeps float element math", src: ` export function doubled(samples: readonly number[]): readonly number[] { return samples.map((x) => x * 2); } `, }, { name: "filter over a number array compares floats", src: ` export function positive(samples: readonly number[]): readonly number[] { return samples.filter((x) => x > 0); } `, }, { name: "indexing by a number-array element is taught", gate: "NS1016", src: ` export function gather(indices: readonly number[], bytes: Uint8Array): readonly number[] { return indices.map((x) => bytes[x]); } `, }, { name: "uninitialized integer local assigned from payload and literal", src: ` export type Msg = { readonly kind: "jump"; readonly to: number } | { readonly kind: "home" }; export function land(msg: Msg, bytes: Uint8Array): number { let target: number; switch (msg.kind) { case "jump": { target = msg.to; break; } case "home": { target = 0; break; } } return bytes[target]; } `, }, { name: "compound assignment feeds demand back through the accumulator", src: ` export type Msg = { readonly kind: "add"; readonly n: number } | { readonly kind: "zero" }; export function tally(msg: Msg, bytes: Uint8Array): number { let acc = 0; if (msg.kind === "add") acc += msg.n; return bytes[acc]; } `, }, { name: "float-bounded counting loop stays f64 end to end", src: ` export function steps(limit: number): number { let total = 0.0; for (let i = 0; i < limit * 0.5; i++) { total += 1; } return total; } `, }, { name: "integer counting loop over bytes (regression)", src: ` export function spaces(bytes: Uint8Array): number { let n = 0; for (let i = 0; i < bytes.length; i++) { if (bytes[i] === 32) n += 1; } return n; } `, }, { name: "undemanded payload mixed with a fraction in a ternary goes f64", src: ` export type Msg = { readonly kind: "set"; readonly value: number } | { readonly kind: "half" }; export function level(msg: Msg): number { return msg.kind === "set" ? msg.value : 0.5; } `, }, { name: "demanded payload mixed with a fraction in a ternary is taught", gate: "NS1016", src: ` export type Msg = { readonly kind: "set"; readonly value: number } | { readonly kind: "half" }; export function pick(msg: Msg, flag: boolean, bytes: Uint8Array): number { const v = flag && msg.kind === "set" ? msg.value : 0.5; return bytes[v]; } `, }, { name: "two undecided payloads compare as the same float class", src: ` export type Msg = | { readonly kind: "pair"; readonly a: number; readonly b: number } | { readonly kind: "none" }; export function same(msg: Msg): boolean { if (msg.kind !== "pair") return false; return msg.a === msg.b; } `, }, { name: "comparison against a proven-integer side claims the payload", src: ` export type Msg = { readonly kind: "check"; readonly n: number } | { readonly kind: "skip" }; export function atEnd(msg: Msg, bytes: Uint8Array): boolean { if (msg.kind !== "check") return false; return msg.n === bytes.length; } `, }, { name: "bitwise demand on a payload (R9 regression)", src: ` export type Msg = { readonly kind: "mask"; readonly bits: number } | { readonly kind: "none" }; export function low(msg: Msg): number { if (msg.kind !== "mask") return 0; return msg.bits & 255; } `, }, { name: "optional float field takes fractions and payload values", src: ` export interface Model { readonly hue: number | null; } export type Msg = { readonly kind: "tint"; readonly hue: number } | { readonly kind: "clear" }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "tint": return { hue: msg.hue * 0.1 }; case "clear": return { hue: null }; } } `, }, { name: "orelse fusion on an optional number result (R7 regression)", src: ` export function find(xs: Uint8Array, want: number): number | null { for (let i = 0; i < xs.length; i++) { if (xs[i] === want) return i; } return null; } export function findOrZero(xs: Uint8Array, want: number): number { const hit = find(xs, want); if (hit === null) return 0; return hit; } `, }, { name: "optional numeric equality in every expression position (null-safe, no unwrap)", src: ` export function isZero(cls: number | null): boolean { return cls === 0; } export function nonZero(cls: number | null): boolean { return cls !== 0; } export function reversed(cls: number | null): boolean { return 0 === cls; } export function inTernary(cls: number | null): number { return cls === 0 ? 1 : cls !== 0 ? 2 : 3; } export function inChain(cls: number | null, flag: boolean): boolean { return flag && cls === 1; } export function bothOptional(a: number | null, b: number | null): boolean { return a === b; } export function againstValue(cls: number | null, n: number): boolean { return cls === n; } `, }, { name: "division is float always; integer reads widen into the site", src: ` export function ratio(a: number, b: number): number { return a / b; } export function halfLen(bytes: Uint8Array): number { return bytes.length / 2; } `, }, { name: "remainder on integer and float sites", src: ` export function wrapAt(bytes: Uint8Array, at: number): number { return bytes[at % bytes.length]; } export function frac(x: number): number { return x % 1; } `, }, { name: "bitwise beyond a provable 32-bit range takes the wrap helpers", src: ` export function band(a: number, b: number): number { return a & b; } export function bor(a: number, b: number): number { return a | b; } export function bxor(a: number, b: number): number { return a ^ b; } export function bmask(a: number): number { return a & 255; } `, }, { name: "Math.round emits in value positions", src: ` export function nearest(x: number): number { return Math.round(x); } export interface Model { readonly scale: number; } export function snapped(model: Model): number { return Math.round(model.scale * 1.5); } `, }, { name: "Math.round feeding an index slot is taught, not emitted", gate: "NS1016", src: ` export function sample(bytes: Uint8Array, x: number): number { return bytes[Math.round(x)]; } `, }, { name: "union-typed local built by a selector ternary carries its annotation", src: ` export type Ev = | { readonly kind: "insert"; readonly text: Uint8Array } | { readonly kind: "move"; readonly dx: number; readonly dy: number } | { readonly kind: "clear" }; export function weigh(sel: number, payload: Uint8Array, dx: number, dy: number): number { const ev: Ev = sel === 0 ? { kind: "insert", text: payload } : sel === 1 ? { kind: "move", dx: dx, dy: dy } : { kind: "clear" }; switch (ev.kind) { case "insert": return ev.text.length; case "move": return ev.dx + ev.dy; case "clear": return 0; } } `, }, { // R7d dual: `x === undefined ? A : ` narrows the ELSE branch — // the find-miss ternary the guard-first spelling already covered, in // the miss-first order (both operand orders). name: "=== undefined / === null miss-first ternaries narrow the else branch", src: ` export interface Task { readonly id: number; } export interface Model { readonly tasks: readonly Task[]; readonly sel: number | null; } export function firstOrMinus(model: Model, id: number): number { const found = model.tasks.find((t) => t.id === id); return found === undefined ? -1 : found.id + 1; } export function flipped(model: Model, id: number): number { const found = model.tasks.find((t) => t.id === id); return undefined === found ? -1 : found.id + 1; } export function selPlus(model: Model): number { return model.sel === null ? 0 : model.sel + 1; } `, }, { // R7 dual in statement position: `if (x === null) { A } else { uses x }` // narrows the else branch, and an exiting miss branch narrows the // statements after the if too (else-if chains included). name: "=== null if/else statement narrowing, else-if chains, and post-if reads", src: ` export interface Task { readonly id: number; } export interface Model { readonly tasks: readonly Task[]; } export function branch(model: Model, id: number, bytes: Uint8Array): number { const found = model.tasks.find((t) => t.id === id); if (found === undefined) { return 0; } else { return bytes[found.id]; } } export function chained(model: Model, id: number): number { const found = model.tasks.find((t) => t.id === id); if (found === undefined) { return -1; } else if (found.id > 5) { return found.id * 2; } return found.id; } `, }, { // R7 fusion over a TERNARY initializer: `const x = c ? f(a) : g(a); // if (x === null) ` lowers to `(if (c) f else g) orelse ` // — the conditional must parenthesize, or Zig binds the orelse to the // ELSE arm alone (the system-monitor-ts memory-sampler shape). name: "orelse fusion over a ternary initializer parenthesizes the conditional", src: ` export interface Sample { readonly used: number; } function parseA(bytes: Uint8Array): Sample | null { if (bytes.length === 0) return null; return { used: bytes[0] }; } function parseB(bytes: Uint8Array): Sample | null { if (bytes.length < 2) return null; return { used: bytes[1] }; } export function pick(first: boolean, bytes: Uint8Array): number { const sample = first ? parseA(bytes) : parseB(bytes); if (sample === null) { return -1; } return sample.used; } export function pickInline(first: boolean, bytes: Uint8Array): number { const sample = first ? parseA(bytes) : parseB(bytes); if (sample === null) return -1; return sample.used; } `, }, { // Mixed-class optional equality: an optional slot the number tier // classes i64 compared against a float value routes through the // null-safe widening helper instead of emitting \`?i64 == f64\`. name: "optional integer slot against a float value widens null-safely", src: ` export interface Model { readonly sel: number | null; readonly frac: number; } export function pickAt(model: Model, bytes: Uint8Array): number { if (model.sel !== null) return bytes[model.sel]; return 0; } export function atHalf(model: Model): boolean { const half = model.frac * 0.5; return model.sel === half; } export function offHalf(model: Model): boolean { const half = model.frac * 0.5; return model.sel !== half; } export function atFractionLiteral(model: Model): boolean { return model.sel === 0.5; } `, }, ]; const structuralCases: Case[] = [ { // The five wiring channels together: the emitted module must carry // compilable fns, arm consts, and the envMsgs tuple. name: "the host-event wiring channels emit and compile", src: ` export type ColorScheme = "light" | "dark"; export interface FrameEvent { readonly width: number; readonly height: number; readonly timestampMs: number; readonly intervalMs: number; } export interface KeyEvent { readonly key: string; readonly shift: boolean; readonly control: boolean; readonly alt: boolean; readonly super: boolean; } export interface ChromeInsets { readonly top: number; readonly right: number; readonly bottom: number; readonly left: number; } export interface ChromeButtons { readonly x: number; readonly y: number; readonly width: number; readonly height: number; } export interface Model { readonly width: number; readonly dark: boolean; readonly chromeTop: number; readonly base: Uint8Array; } export type Msg = | { readonly kind: "resized"; readonly width: number } | { readonly kind: "toggled" } | { readonly kind: "appearance_changed"; readonly colorScheme: ColorScheme; readonly reduceMotion: boolean; readonly highContrast: boolean } | { readonly kind: "chrome_changed"; readonly insets: ChromeInsets; readonly buttons: ChromeButtons; readonly tabsProjected: boolean } | { readonly kind: "base_set"; readonly value: Uint8Array }; export function frameMsg(model: Model, frame: FrameEvent): Msg | null { if (frame.width !== model.width) return { kind: "resized", width: frame.width }; return null; } export function keyMsg(key: KeyEvent): Msg | null { if (key.control || key.alt || key.super || key.shift) return null; if (key.key === "space") return { kind: "toggled" }; return null; } export const appearanceMsg = "appearance_changed"; export const chromeMsg = "chrome_changed"; export const envMsgs = [{ env: "APP_BASE", msg: "base_set" }] as const; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "resized": return { ...model, width: msg.width }; case "toggled": return model; case "appearance_changed": return { ...model, dark: msg.colorScheme === "dark" }; case "chrome_changed": return { ...model, chromeTop: msg.insets.top }; case "base_set": return { ...model, base: msg.value }; } } `, }, { name: "record array update with spread, map, and filter (R15-R17 regression)", src: ` export interface Task { readonly id: number; readonly done: boolean; } export interface Model { readonly tasks: readonly Task[]; readonly nextId: number; } export type Msg = | { readonly kind: "add" } | { readonly kind: "toggle"; readonly id: number } | { readonly kind: "purge" }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "add": return { ...model, tasks: [...model.tasks, { id: model.nextId, done: false }], nextId: model.nextId + 1 }; case "toggle": return { ...model, tasks: model.tasks.map((t) => (t.id === msg.id ? { ...t, done: !t.done } : t)) }; case "purge": return { ...model, tasks: model.tasks.filter((t) => !t.done) }; } } `, }, { name: "multi-field union arm mixing a cross-enum value and a demanded number", src: ` export type Category = "food" | "travel" | "gear"; export type CategoryFilter = "all" | "food" | "travel" | "gear"; export type Msg = | { readonly kind: "place"; readonly filter: CategoryFilter; readonly at: number } | { readonly kind: "none" }; export function place(category: Category, at: number, bytes: Uint8Array): Msg { const probe = bytes[at]; if (probe === 0) return { kind: "none" }; return { kind: "place", filter: category, at: at }; } `, }, { name: "switch payload capture feeding integer math (R13 regression)", src: ` export type Ev = | { readonly kind: "insert"; readonly text: Uint8Array } | { readonly kind: "move"; readonly dx: number; readonly dy: number } | { readonly kind: "clear" }; export function weight(ev: Ev): number { switch (ev.kind) { case "insert": return ev.text.length; case "move": return ev.dx + ev.dy; case "clear": return 0; } } export function at(ev: Ev, bytes: Uint8Array): number { return bytes[weight(ev)]; } `, }, ]; const cmdCases: Case[] = [ { name: "Cmd pair-return with every v1 factory (effects channel regression)", src: ` import { Cmd } from "@native-sdk/core"; export interface Model { readonly count: number; readonly saved: number; } export type Msg = | { readonly kind: "add" } | { readonly kind: "save" } | { readonly kind: "stamp" } | { readonly kind: "tick"; readonly at: number }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "add": return { ...model, count: model.count + 1 }; case "save": return [{ ...model, saved: model.count }, Cmd.persist()]; case "stamp": return [model, Cmd.batch([Cmd.now("tick"), Cmd.host("beep", model.count)])]; case "tick": return { ...model, count: msg.at }; } } `, }, { name: "conditional command in the return slot", src: ` import { Cmd } from "@native-sdk/core"; export interface Model { readonly count: number; } export type Msg = { readonly kind: "add" } | { readonly kind: "noop" }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "add": return [{ count: model.count + 1 }, model.count > 10 ? Cmd.persist() : Cmd.none]; case "noop": return model; } } `, }, { name: "Cmd escaping into a helper is taught, not emitted", gate: "NS1017", src: ` import { Cmd } from "@native-sdk/core"; export interface Model { readonly count: number; } export type Msg = { readonly kind: "add" } | { readonly kind: "noop" }; function saveCmd(): Cmd { return Cmd.persist(); } export function update(model: Model, msg: Msg): Model { return model; } `, }, ]; // The Cmd v2 surface: bytes/record payloads, keyed routed requests, cancel, // the initialModel boot pair, and declarative subscriptions — each either // emitting zig-compile-clean or gated by its teaching rule. const cmdV2Cases: Case[] = [ { name: "Cmd.host bytes payloads: model bytes, fresh bytes, empty bytes", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; export interface Model { readonly draft: Uint8Array; } export type Msg = { readonly kind: "save" } | { readonly kind: "flush" } | { readonly kind: "zero" }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "save": return [model, Cmd.host("store.write", model.draft)]; case "flush": return [model, Cmd.host("store.write", asciiBytes(\`\${model.draft.length} bytes\`))]; case "zero": return [model, Cmd.host("store.write", new Uint8Array(0))]; } } `, }, { name: "Cmd.host record payload lowers through the derived encoder", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; export interface Model { readonly gain: number; readonly on: boolean; } export type Msg = { readonly kind: "save" } | { readonly kind: "noop" }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "save": return [model, Cmd.host("cfg.save", { gain: model.gain, on: model.on, tag: asciiBytes("v2") })]; case "noop": return model; } } `, }, { name: "Cmd.request routes results by arm name, keyed and unkeyed; cancel drops a key", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; export interface Model { readonly data: Uint8Array; readonly errs: number; } export type Msg = | { readonly kind: "load" } | { readonly kind: "probe" } | { readonly kind: "stop" } | { readonly kind: "loaded"; readonly body: Uint8Array } | { readonly kind: "failed"; readonly why: Uint8Array }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "load": return [model, Cmd.request("store.read", asciiBytes("notes.json"), { key: "load", ok: "loaded", err: "failed" })]; case "probe": return [model, Cmd.request("store.read", model.data, { ok: "loaded", err: "failed" })]; case "stop": return [model, Cmd.batch([Cmd.cancel("load"), Cmd.persist()])]; case "loaded": return { ...model, data: msg.body }; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "initialModel boot pair: the init command runs once at install", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; export interface Model { readonly data: Uint8Array; } export type Msg = | { readonly kind: "loaded"; readonly body: Uint8Array } | { readonly kind: "failed"; readonly why: Uint8Array }; export function initialModel(): [Model, Cmd] { return [{ data: new Uint8Array(0) }, Cmd.request("store.read", asciiBytes("boot.bin"), { key: "boot", ok: "loaded", err: "failed" })]; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "loaded": return { data: msg.body }; case "failed": return model; } } `, }, { name: "subscriptions: timers derived from the model, batched, paused via Sub.none", src: ` import { Sub } from "@native-sdk/core"; export interface Model { readonly running: boolean; readonly fast: boolean; readonly ticks: number; } export type Msg = | { readonly kind: "toggle" } | { readonly kind: "tick"; readonly at: number } | { readonly kind: "blink"; readonly at: number }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "toggle": return { ...model, running: !model.running }; case "tick": return { ...model, ticks: model.ticks + 1 }; case "blink": return model; } } export function subscriptions(model: Model): Sub { if (!model.running) return Sub.none; return Sub.batch([ Sub.timer("tick", model.fast ? 40 : 100, "tick"), Sub.timer("blink", 250, "blink"), ]); } `, }, { name: "a payload mixed with extra arguments is taught", gate: "NS1026", src: ` import { Cmd } from "@native-sdk/core"; export interface Model { readonly draft: Uint8Array; readonly count: number; } export type Msg = { readonly kind: "save" } | { readonly kind: "noop" }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "save": return [model, Cmd.host("store.write", model.draft as never, model.count as never)]; case "noop": return model; } } `, }, { name: "a nested record payload field is taught (no wire encoding)", gate: "NS1026", src: ` import { Cmd } from "@native-sdk/core"; export interface Inner { readonly a: number; } export interface Model { readonly inner: Inner; } export type Msg = { readonly kind: "save" } | { readonly kind: "noop" }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "save": return [model, Cmd.host("cfg.save", { nested: model.inner as never })]; case "noop": return model; } } `, }, { name: "a routing callback is taught, not run (routing is data)", gate: "NS1027", src: ` import { Cmd, type BytesKind } from "@native-sdk/core"; export interface Model { readonly data: Uint8Array; } export type Msg = | { readonly kind: "load" } | { readonly kind: "loaded"; readonly body: Uint8Array } | { readonly kind: "failed"; readonly why: Uint8Array }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "load": return [model, Cmd.request("store.read", model.data, { ok: ((body: Uint8Array) => ({ kind: "loaded", body })) as unknown as BytesKind, err: "failed", })]; case "loaded": return { ...model, data: msg.body }; case "failed": return model; } } `, }, { name: "a non-literal routing arm is taught (decoders derive at build time)", gate: "NS1027", src: ` import { Cmd } from "@native-sdk/core"; export interface Model { readonly data: Uint8Array; readonly alt: boolean; } export type Msg = | { readonly kind: "load" } | { readonly kind: "loaded"; readonly body: Uint8Array } | { readonly kind: "failed"; readonly why: Uint8Array }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "load": return [model, Cmd.request("store.read", model.data, { ok: model.alt ? "loaded" : "loaded", err: "failed", })]; case "loaded": return { ...model, data: msg.body }; case "failed": return model; } } `, }, { name: "a routing arm without a bytes payload is taught", gate: "NS1027", src: ` import { Cmd, type BytesKind } from "@native-sdk/core"; export interface Model { readonly data: Uint8Array; readonly ticks: number; } export type Msg = | { readonly kind: "load" } | { readonly kind: "tick"; readonly at: number } | { readonly kind: "failed"; readonly why: Uint8Array }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "load": return [model, Cmd.request("store.read", model.data, { ok: "tick" as BytesKind, err: "failed", })]; case "tick": return { ...model, ticks: model.ticks + 1 }; case "failed": return model; } } `, }, { name: "a Sub in update's return is taught (subscriptions are declared, not issued)", gate: "NS1025", src: ` import { Sub } from "@native-sdk/core"; export interface Model { readonly ticks: number; } export type Msg = { readonly kind: "go" } | { readonly kind: "tick"; readonly at: number }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "go": { const sub = Sub.timer("tick", 100, "tick"); return model; } case "tick": return { ...model, ticks: model.ticks + 1 }; } } `, }, { name: "a Sub stored in a local inside subscriptions is taught", gate: "NS1025", src: ` import { Sub } from "@native-sdk/core"; export interface Model { readonly ticks: number; } export type Msg = { readonly kind: "noop" } | { readonly kind: "tick"; readonly at: number }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "noop": return model; case "tick": return { ...model, ticks: model.ticks + 1 }; } } export function subscriptions(model: Model): Sub { const stored = Sub.timer("tick", 100, "tick"); return stored; } `, }, { name: "a Sub-typed return outside subscriptions is taught", gate: "NS1025", src: ` import { Sub } from "@native-sdk/core"; export interface Model { readonly ticks: number; } export type Msg = { readonly kind: "noop" } | { readonly kind: "tick"; readonly at: number }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "noop": return model; case "tick": return { ...model, ticks: model.ticks + 1 }; } } function timers(model: Model): Sub { return Sub.timer("tick", 100, "tick"); } `, }, { name: "a timer target without a single number payload is taught", gate: "NS1027", src: ` import { Sub, type TimestampKind } from "@native-sdk/core"; export interface Model { readonly data: Uint8Array; } export type Msg = { readonly kind: "noop" } | { readonly kind: "loaded"; readonly body: Uint8Array }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "noop": return model; case "loaded": return { data: msg.body }; } } export function subscriptions(model: Model): Sub { return Sub.timer("load", 100, "loaded" as TimestampKind); } `, }, ]; // A shared preamble for the named-op cases: every arm shape a routed op // can target, plus one of each wrong shape to gate against. const namedOpMsg = ` export interface Model { readonly code: number; readonly data: Uint8Array; readonly errs: number; } export type Msg = | { readonly kind: "go" } | { readonly kind: "loaded"; readonly body: Uint8Array } | { readonly kind: "wrote" } | { readonly kind: "fetched"; readonly status: number; readonly body: Uint8Array } | { readonly kind: "fired"; readonly at: number } | { readonly kind: "failed"; readonly why: Uint8Array }; export function initialModel(): Model { return { code: -1, data: new Uint8Array(0), errs: 0 }; } `; // Slice C: the named buffered engine ops (readFile/writeFile/fetch/ // clipboard) and the one-shot delay — emit-clean in their exact shapes, // gated with the taught rules everywhere else. const namedOpCases: Case[] = [ { name: "every named op emits in its documented shape", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; export interface Model { readonly code: number; readonly data: Uint8Array; readonly saved: boolean; readonly errs: number; readonly at: number; } export type Msg = | { readonly kind: "go"; readonly which: number } | { readonly kind: "loaded"; readonly body: Uint8Array } | { readonly kind: "wrote" } | { readonly kind: "fetched"; readonly status: number; readonly body: Uint8Array } | { readonly kind: "fired"; readonly at: number } | { readonly kind: "failed"; readonly why: Uint8Array }; export function initialModel(): Model { return { code: -1, data: new Uint8Array(0), saved: false, errs: 0, at: -1 }; } export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": if (msg.which === 0) return [model, Cmd.readFile(asciiBytes("a.bin"), { key: "r", ok: "loaded", err: "failed" })]; if (msg.which === 1) return [model, Cmd.writeFile(asciiBytes("a.bin"), model.data, { key: "w", ok: "wrote", err: "failed" })]; if (msg.which === 2) return [model, Cmd.fetch({ url: asciiBytes("https://a.test"), method: "PUT", headers: { accept: "text/plain" }, body: model.data, timeoutMs: 1000 }, { ok: "fetched", err: "failed" })]; if (msg.which === 3) return [model, Cmd.fetch({ url: model.data }, { key: "g", ok: "fetched", err: "failed" })]; if (msg.which === 4) return [model, Cmd.clipboardWrite(model.data)]; if (msg.which === 5) return [model, Cmd.clipboardRead({ key: "p", ok: "loaded", err: "failed" })]; if (msg.which === 6) return [model, Cmd.delay("d", model.at + 100, "fired")]; return [model, Cmd.batch([Cmd.delay("d", 250, "fired"), Cmd.cancel("d")])]; case "loaded": return { ...model, data: msg.body }; case "wrote": return { ...model, saved: true }; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return { ...model, at: msg.at }; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "a fetch ok arm that is not a {status, body} record is taught", gate: "NS1027", src: ` import { Cmd, asciiBytes, type FetchedKind } from "@native-sdk/core"; ${namedOpMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.fetch({ url: asciiBytes("https://a.test") }, { ok: "loaded" as FetchedKind, err: "failed" })]; case "loaded": return { ...model, data: msg.body }; case "wrote": return model; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return model; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "a writeFile ok arm carrying a payload is taught", gate: "NS1027", src: ` import { Cmd, asciiBytes, type EmptyKind } from "@native-sdk/core"; ${namedOpMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.writeFile(asciiBytes("a.bin"), model.data, { ok: "loaded" as EmptyKind, err: "failed" })]; case "loaded": return { ...model, data: msg.body }; case "wrote": return model; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return model; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "a delay target without a single number payload is taught", gate: "NS1027", src: ` import { Cmd, type TimestampKind } from "@native-sdk/core"; ${namedOpMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.delay("d", 100, "loaded" as TimestampKind)]; case "loaded": return { ...model, data: msg.body }; case "wrote": return model; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return model; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "a runtime bytes fetch header value emits and compiles (names stay compile-time)", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${namedOpMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.fetch({ url: asciiBytes("https://a.test"), headers: { authorization: model.data, accept: "text/plain", "x-trace": asciiBytes("t-1") } }, { ok: "fetched", err: "failed" })]; case "loaded": return { ...model, data: msg.body }; case "wrote": return model; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return model; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "a smuggled string fetch header value is taught (values are literals or bytes)", gate: "NS1029", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${namedOpMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.fetch({ url: asciiBytes("https://a.test"), headers: { etag: model.errs > 0 ? "a" : "b" } }, { ok: "fetched", err: "failed" })]; case "loaded": return { ...model, data: msg.body }; case "wrote": return model; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return model; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "a non-flat headers record is taught", gate: "NS1029", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${namedOpMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.fetch({ url: asciiBytes("https://a.test"), headers: { nested: { deep: "x" } } as unknown as { readonly [name: string]: string } }, { ok: "fetched", err: "failed" })]; case "loaded": return { ...model, data: msg.body }; case "wrote": return model; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return model; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "a string path smuggled past the bytes rule is taught", gate: "NS1029", src: ` import { Cmd } from "@native-sdk/core"; ${namedOpMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.readFile("store.bin" as unknown as Uint8Array, { ok: "loaded", err: "failed" })]; case "loaded": return { ...model, data: msg.body }; case "wrote": return model; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return model; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "an over-bound path literal stops at compile time", gate: "NS1030", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${namedOpMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.readFile(asciiBytes(${JSON.stringify("p".repeat(1025))}), { ok: "loaded", err: "failed" })]; case "loaded": return { ...model, data: msg.body }; case "wrote": return model; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return model; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "more headers than the engine accepts stops at compile time", gate: "NS1030", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${namedOpMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.fetch({ url: asciiBytes("https://a.test"), headers: { a: "1", b: "2", c: "3", d: "4", e: "5", f: "6", g: "7", h: "8", i: "9" } }, { ok: "fetched", err: "failed" })]; case "loaded": return { ...model, data: msg.body }; case "wrote": return model; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return model; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "a literal delay outside the 1ms..one-year bound stops at compile time", gate: "NS1030", src: ` import { Cmd } from "@native-sdk/core"; ${namedOpMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.delay("d", 0, "fired")]; case "loaded": return { ...model, data: msg.body }; case "wrote": return model; case "fetched": return { ...model, code: msg.status, data: msg.body }; case "fired": return model; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, ]; // The emit-contract hardening round: constructs that once transpiled into // invalid Zig now either emit correctly (optional chains, string equality, // the asciiBytes intrinsic) or stop with a taught rule (concatenation, // parameter defaults, host-arg smuggling, chain null tests, Map/Set). const contractCases: Case[] = [ { name: "optional chains: ?? folds, value comparisons, boolean conditions", src: ` export type Tone = "info" | "warn"; export interface Badge { readonly count: number; readonly label: Uint8Array; readonly urgent: boolean; readonly tone: Tone | null; } export interface Panel { readonly badge: Badge | null; readonly width: number; } export interface Model { readonly panel: Panel | null; readonly fallback: number; } export function badgeCount(model: Model): number { return model.panel?.badge?.count ?? 0; } export function labelLen(model: Model): number { return model.panel?.badge?.label.length ?? -1; } export function isUrgent(model: Model): boolean { return model.panel?.badge?.urgent ?? false; } export function urgentGate(model: Model, on: boolean): boolean { if (model.panel?.badge?.urgent) return true; return on && !model.panel?.badge?.urgent; } export function isWarn(model: Model): boolean { return model.panel?.badge?.tone === "warn"; } export function countIsFive(model: Model): boolean { return model.panel?.badge?.count === 5; } export function widthOrFallback(model: Model): number { const w = model.panel?.width ?? model.fallback; return w * 2; } export function toneOrNull(model: Model): Tone | null { return model.panel?.badge?.tone ?? null; } `, }, { name: "optional chain on a local holding an optional record", src: ` export interface Sel { readonly at: number; readonly len: number; } export interface Model { readonly sel: Sel | null; } export function span(model: Model): number { const sel = model.sel; return (sel?.at ?? 0) + (sel?.len ?? 0); } `, }, { name: "string equality: the command-mapper idiom emits and compiles", src: ` export interface Model { readonly count: number; } export type Msg = { readonly kind: "add" } | { readonly kind: "remove" }; export function commandMsg(name: string): Msg | null { if (name === "app.add") return { kind: "add" }; if (name === "app.remove") return { kind: "remove" }; return null; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "add": return { count: model.count + 1 }; case "remove": return { count: model.count - 1 }; } } `, }, { name: "string equality against optional strings keeps the null table", src: ` export function pick(name: string | null): number { if (name === "left") return 1; if (name !== "right") return 2; return 3; } export function same(a: string | null, b: string | null): boolean { return a === b; } `, }, { name: "literal-union value equals a plain string by tag name", src: ` export type Filter = "all" | "active" | "done"; export function matchesName(f: Filter, name: string): boolean { return f === name; } `, }, { name: "SDK asciiBytes intrinsic: literal to rodata, template to arena bytes", src: ` import { asciiBytes } from "@native-sdk/core"; export interface Model { readonly count: number; } export function banner(): Uint8Array { return asciiBytes("expenses"); } export function summary(model: Model): Uint8Array { return asciiBytes(\`\${model.count} items\`); } `, }, { name: "string + concatenation is taught, not emitted", gate: "NS1018", src: ` export function shout(s: string): string { return s + "!"; } `, }, { name: "parameter defaults are taught, not silently dropped", gate: "NS1019", src: ` function step(n: number, by: number = 1): number { return n + by; } export function next(n: number): number { return step(n); } `, }, { name: "Cmd.host argument smuggled past the types is taught", gate: "NS1020", src: ` import { Cmd } from "@native-sdk/core"; export interface Model { readonly count: number; } export type Msg = { readonly kind: "go"; readonly path: string } | { readonly kind: "noop" }; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.host("open", msg.path as unknown as number)]; case "noop": return model; } } `, }, { name: "null test on an optional chain is taught (undefined vs null would diverge)", gate: "NS1021", src: ` export interface Inner { readonly x: number | null; } export interface Model { readonly inner: Inner | null; } export function f(model: Model): boolean { return model.inner?.x === null; } `, }, { name: "bare new Map() is the taught container rule, not an internal stop", gate: "NS1011", src: ` export function f(): number { const m = new Map(); return m.size; } `, }, { name: "a relative import of a missing module is taught, before resolution matters", gate: "NS1037", src: ` // @ts-expect-error the sibling module deliberately does not exist: the rule // must fire before resolution matters. import { helper } from "./helper_mod.ts"; export function f(n: number): number { return helper(n); } `, }, ]; // The iteration round: for...of over arrays and bytes, and the array-method // lowerings (find/findIndex/some/every/reduce/slice/concat/indexOf/includes/ // join). Emitting cases must compile; the JS corners with no mapping are // gated by their teaching rules. const bindingSurfaceCases: Case[] = [ { name: "exported model helpers forward as Model declarations and viewUnbound emits the opt-out", src: ` export interface Task { readonly id: number; readonly done: boolean; } export interface Model { readonly tasks: readonly Task[]; readonly nextId: number; } export type Msg = { readonly kind: "add" } | { readonly kind: "chrome_changed"; readonly inset: number }; export const viewUnbound = ["nextId", "chrome_changed", "openTasks"] as const; export function initialModel(): Model { return { tasks: [], nextId: 1 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "add": return { ...model, tasks: [...model.tasks, { id: model.nextId, done: false }], nextId: model.nextId + 1 }; case "chrome_changed": return model; } } export function remainingCount(model: Model): number { return model.tasks.filter((t) => !t.done).length; } export function openTasks(model: Model): readonly Task[] { return model.tasks.filter((t) => !t.done); } export function total(model: Model): number { return model.nextId - 1; } `, }, { name: "a helper colliding with a field's emitted name is gated", gate: "NS1031", src: ` interface Totals { readonly doneCount: number; } export interface Model { readonly totals: Totals; readonly doneCount: number; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; export function initialModel(): Model { return { totals: { doneCount: 0 }, doneCount: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "a": return model; case "b": return model; } } export function doneCount(model: Model): number { return model.totals.doneCount; } `, }, { name: "helpers and fields with different spellings never collide (names emit verbatim)", src: ` export interface Model { readonly done_count: number; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; export function initialModel(): Model { return { done_count: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "a": return model; case "b": return model; } } export function doneCount(model: Model): number { return model.done_count; } `, }, { name: "a viewUnbound entry outside the model surface is gated", gate: "NS1032", src: ` export interface Model { readonly count: number; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; export const viewUnbound = ["typoedName"] as const; export function initialModel(): Model { return { count: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "a": return model; case "b": return model; } } `, }, ]; const stackedUnionCases: Case[] = [ { name: "stacked union-switch labels sharing a body coalesce into one arm", src: ` export type Ev = { readonly kind: "a"; readonly n: number } | { readonly kind: "b" } | { readonly kind: "c" }; export function pick(e: Ev): number { switch (e.kind) { case "a": return e.n; case "b": case "c": return -1; } } `, }, { name: "stacked labels whose shared body reads a payload are gated", gate: "NS9001", src: ` export type Ev = { readonly kind: "a"; readonly n: number } | { readonly kind: "b"; readonly n: number }; export function pick(e: Ev): number { switch (e.kind) { case "b": case "a": return e.n; } } `, }, ]; const iterationCases: Case[] = [ { name: "for...of over a record array with break and continue", src: ` export interface Task { readonly id: number; readonly done: boolean; } export function firstOpenId(tasks: readonly Task[]): number { let hit = -1; for (const t of tasks) { if (t.done) continue; hit = t.id; break; } return hit; } `, }, { name: "for...of over bytes: integer widening, demand, and float use", src: ` export function total(bytes: Uint8Array): number { let n = 0; for (const b of bytes) { n += b; } return n; } export function probe(bytes: Uint8Array, table: Uint8Array): number { let acc = 0; for (const b of bytes) { acc += table[b]; } return acc; } export function scaled(bytes: Uint8Array): number { let n = 0.0; for (const b of bytes) { n += b * 0.5; } return n; } `, }, { name: "for...of over a number array keeps float element math", src: ` export function product(xs: readonly number[]): number { let p = 1; for (const x of xs) { p = p * x; } return p; } `, }, { name: "for...of over a filtered array and an unused binding", src: ` export interface Task { readonly id: number; readonly done: boolean; } export function doneTally(tasks: readonly Task[]): number { let n = 0; for (const t of tasks.filter((x) => x.done)) { n += 1; } return n; } `, }, { name: "for...of over .entries() emits the indexed loop (the [i, x] pair form)", src: ` export function sum(xs: readonly number[]): number { let total = 0; for (const [i, x] of xs.entries()) { total += x + i; } return total; } `, }, { name: "for...of over .entries() beyond the [i, x] pair form is taught", gate: "NS9001", src: ` export function sum(xs: readonly number[]): number { let total = 0; for (const [i] of xs.entries()) { total += i; } return total; } `, }, { name: "for...of with a let binding is taught, not emitted", gate: "NS9001", src: ` export function last(xs: readonly number[]): number { let hit = 0; for (let x of xs) { hit = x; } return hit; } `, }, { name: "find consumed through the miss-test fusion and payload reads", src: ` export interface Task { readonly id: number; readonly done: boolean; } export function firstDoneId(tasks: readonly Task[]): number { const hit = tasks.find((t) => t.done); if (hit === undefined) return -1; return hit.id; } `, }, { name: "find consumed through ?? and an identifier guard block", src: ` export function firstOver(xs: readonly number[], lim: number): number { return xs.find((x) => x > lim) ?? -1; } export interface Task { readonly id: number; readonly done: boolean; } export function doubledId(tasks: readonly Task[]): number { const hit = tasks.find((t) => !t.done); if (hit !== undefined) { const twice = hit.id * 2; return twice; } return 0; } `, }, { name: "findIndex, some, every, indexOf, and includes over scalar arrays", src: ` export type Category = "food" | "travel" | "gear"; export interface Task { readonly id: number; readonly done: boolean; } export function doneAt(tasks: readonly Task[]): number { return tasks.findIndex((t) => t.done); } export function anyDone(tasks: readonly Task[]): boolean { return tasks.some((t) => t.done); } export function allDone(tasks: readonly Task[]): boolean { return tasks.every((t) => t.done); } export function whereIs(xs: readonly number[], v: number): number { return xs.indexOf(v); } export function hasCategory(cats: readonly Category[], c: Category): boolean { return cats.includes(c); } `, }, { name: "findIndex demand: the result indexes memory", src: ` export interface Task { readonly id: number; readonly done: boolean; } export function markByte(tasks: readonly Task[], bytes: Uint8Array): number { const at = tasks.findIndex((t) => t.done); if (at === -1) return 0; return bytes[at]; } `, }, { name: "reduce with an initial value over numbers and records", src: ` export interface Expense { readonly cents: number; } export function total(xs: readonly number[]): number { return xs.reduce((sum, x) => sum + x, 0); } export function centsTotal(expenses: readonly Expense[]): number { return expenses.reduce((sum, e) => sum + e.cents, 0); } export function countBig(xs: readonly number[], lim: number): number { return xs.reduce((n, x) => (x > lim ? n + 1 : n), 0); } `, }, { name: "reduce without an initial value is taught (empty-array throw)", gate: "NS1007", src: ` export function total(xs: readonly number[]): number { return xs.reduce((sum, x) => sum + x); } `, }, { name: "reduce result flowing into an index slot is taught (float-classed)", gate: "NS1016", src: ` export function pick(xs: readonly number[], bytes: Uint8Array): number { const at = xs.reduce((sum, x) => sum + x, 0); return bytes[at]; } `, }, { name: "array slice and concat over records and numbers", src: ` export interface Task { readonly id: number; readonly done: boolean; } export function firstTwo(tasks: readonly Task[]): readonly Task[] { return tasks.slice(0, 2); } export function lastTwo(xs: readonly number[]): readonly number[] { return xs.slice(-2); } export function trimmed(xs: readonly number[], from: number, to: number): readonly number[] { return xs.slice(from, to); } export function stitched(a: readonly Task[], b: readonly Task[]): readonly Task[] { return a.concat(b); } export function tripled(a: readonly number[], b: readonly number[], c: readonly number[]): readonly number[] { return a.concat(b, c); } `, }, { name: "indexOf on a record array is taught (JS reference identity)", gate: "NS9001", src: ` export interface Task { readonly id: number; readonly done: boolean; } export function has(tasks: readonly Task[], t: Task): number { return tasks.indexOf(t); } `, }, { name: "join over bytes emits; join over a number array is taught", src: ` export function csv(bytes: Uint8Array): string { return bytes.join("-"); } export function bare(bytes: Uint8Array): string { return bytes.join(""); } export function commas(bytes: Uint8Array): string { return bytes.join(); } `, }, { name: "join on a number array is taught (float elements)", gate: "NS9001", src: ` export function csv(xs: readonly number[]): string { return xs.join(","); } `, }, { name: "the wrong empty test is taught in both directions (R7c)", gate: "NS9001", src: ` export function f(cursor: number | null): boolean { return cursor === undefined; } `, }, { name: "=== null on a find result is taught (the miss is JS undefined)", gate: "NS9001", src: ` export function f(xs: readonly number[]): number { const hit = xs.find((x) => x > 0); if (hit === null) return -1; return 0; } `, }, ]; // The building-and-sorting round: block-body callbacks in the array methods, // the push-builder, prepend/multi-spread literals, toSorted, and the two // comptime/clamping fixes. Emitting cases must compile; the shapes with no // mapping are gated by their teaching rules. const builderSortCases: Case[] = [ { name: "block-body callbacks across map, filter, find, findIndex, some, every, reduce", src: ` export interface Task { readonly id: number; readonly streak: number; readonly done: boolean; } export interface Model { readonly tasks: readonly Task[]; } export function capped(model: Model, lim: number): readonly Task[] { return model.tasks.map((t) => { if (t.streak > lim) return { ...t, streak: lim }; return t; }); } export function margins(model: Model, lim: number): readonly Task[] { return model.tasks.filter((t) => { if (t.done) return false; const margin = lim - t.streak; return margin > 0; }); } export function pickId(model: Model, want: number): number { const hit = model.tasks.find((t) => { if (t.id === want) return true; return t.streak > want; }); if (hit === undefined) return -1; return hit.id; } export function whereDone(model: Model): number { return model.tasks.findIndex((t) => { if (t.streak === 0) return false; return t.done; }); } export function anyOpen(model: Model): boolean { return model.tasks.some((t) => { const open = !t.done; return open; }); } export function allSeeded(model: Model): boolean { return model.tasks.every((t) => { if (t.done) return true; return t.streak > 0; }); } export function streakTotal(model: Model): number { return model.tasks.reduce((sum, t) => { if (t.done) return sum; return sum + t.streak; }, 0); } `, }, { name: "block-body callback with orelse fusion and a nested expression callback", src: ` export interface Task { readonly id: number; readonly streak: number; readonly done: boolean; } export function pairSum(tasks: readonly Task[], others: readonly Task[]): number { return tasks.reduce((sum, t) => { const twin = others.find((o) => o.id === t.id); if (twin === undefined) return sum; return sum + twin.streak; }, 0); } `, }, { name: "push-builder: for...of, classic for, while, and pushes inside if/else", src: ` export interface Task { readonly id: number; readonly done: boolean; } export function openIds(tasks: readonly Task[]): readonly number[] { const out: number[] = []; for (const t of tasks) { if (t.done) { out.push(-t.id); } else { out.push(t.id); } } return out; } export function evens(bytes: Uint8Array): readonly number[] { const out: number[] = []; for (let i = 0; i < bytes.length; i++) { if (bytes[i] % 2 === 0) out.push(bytes[i]); } return out; } export function countdown(n: number): readonly number[] { const out: number[] = []; let left = n; while (left > 0) { out.push(left); left -= 1; } return out; } `, }, { name: "push-builder of records escaping into the model (commit walkers see the prefix)", src: ` export interface Task { readonly id: number; readonly done: boolean; } export interface Model { readonly tasks: readonly Task[]; } export type Msg = { readonly kind: "mark"; readonly id: number } | { readonly kind: "noop" }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "mark": { const next: Task[] = []; for (const t of model.tasks) { if (t.id === msg.id) next.push({ ...t, done: true }); else next.push(t); } return { tasks: next }; } case "noop": return model; } } `, }, { name: "builder length and element reads see the filled prefix", src: ` export function firstBig(xs: readonly number[], lim: number): number { const out: number[] = []; for (const x of xs) { if (x > lim) out.push(x); } if (out.length === 0) return -1; return out[0]; } `, }, { name: "prepend and multi-spread literals over numbers and records", src: ` export interface Task { readonly id: number; readonly done: boolean; } export function pre(xs: readonly number[], x: number): readonly number[] { return [x, ...xs]; } export function preTask(tasks: readonly Task[], t: Task): readonly Task[] { return [t, ...tasks]; } export function stitch(a: readonly number[], b: readonly number[], x: number): readonly number[] { return [...a, x, ...b]; } export function wrap(xs: readonly number[], lo: number, hi: number): readonly number[] { return [lo, ...xs, hi]; } `, }, { name: "toSorted over records, numbers, and a block-body comparator", src: ` export interface Task { readonly id: number; readonly streak: number; readonly done: boolean; } export interface Model { readonly tasks: readonly Task[]; } export function byStreak(model: Model): readonly Task[] { return model.tasks.toSorted((a, b) => a.streak - b.streak); } export function descending(xs: readonly number[]): readonly number[] { return xs.toSorted((a, b) => b - a); } export function doneLast(model: Model): readonly Task[] { return model.tasks.toSorted((a, b) => { if (a.done === b.done) return a.streak - b.streak; if (a.done) return 1; return -1; }); } `, }, { name: "bytes slice with out-of-range and negative bounds compiles to the clamped copy", src: ` export function tail(bytes: Uint8Array, from: number): Uint8Array { return bytes.slice(from); } export function window(bytes: Uint8Array, from: number, to: number): Uint8Array { return bytes.slice(from, to); } export function lastTwo(bytes: Uint8Array): Uint8Array { return bytes.slice(-2); } `, }, { name: "comptime division folds to the JS f64 value (0/0 once emitted an illegal divide)", src: ` export const RATE = 1 / 0; export function nanv(): number { return 0 / 0; } export function half(): number { return 5 / 2; } export function negZero(): number { return 0 / -1; } `, }, { name: "number const from a ternary of literal branches carries its runtime type", src: ` export function step(flag: boolean): number { const delta = flag ? -1 : 1; return delta; } export interface Habit { readonly id: number; readonly streak: number; readonly doneToday: boolean; } export function toggled(habits: readonly Habit[], id: number): readonly Habit[] { return habits.map((h) => { if (h.id !== id) return h; const bump = h.doneToday ? -1 : 1; return { ...h, doneToday: !h.doneToday, streak: h.streak + bump }; }); } `, }, { name: "toSorted without a comparator is taught (JS ToString ordering)", gate: "NS9001", src: ` export function f(xs: readonly number[]): readonly number[] { return xs.toSorted(); } `, }, { name: "in-place .sort() is taught toward .toSorted", gate: "NS1022", src: ` export function f(xs: number[]): number[] { xs.sort((a, b) => a - b); return xs; } `, }, { name: "push on a parameter array is the mutation rule", gate: "NS1001", src: ` export function f(xs: number[], x: number): number[] { xs.push(x); return xs; } `, }, { name: "push on a MIXED reassigned binding is taught (an alias assignment ends ownership)", gate: "NS1001", src: ` export function f(xs: number[], n: number): readonly number[] { let out: number[] = []; out.push(n); out = xs; return out; } `, }, { name: "R17m: a reassigned binding whose every assignment is a fresh construction mutates freely", src: ` export function f(n: number): readonly number[] { let out: number[] = []; out.push(n); out = [n, n]; out.push(n + 1); return out; } `, }, { name: "push in value position is taught (the JS value is the new length)", gate: "NS9001", src: ` export function f(n: number): number { const out: number[] = []; const len = out.push(n); return len; } `, }, { name: "an un-annotated spread local is taught its array-type annotation (NS1052)", gate: "NS1052", src: ` export interface Turn { readonly id: number; readonly text: Uint8Array; } export interface Model { readonly turns: readonly Turn[]; readonly nextId: number; } export type Msg = { readonly kind: "add"; readonly text: Uint8Array } | { readonly kind: "clear" }; export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "add": { const turns = [...model.turns, { id: model.nextId, text: msg.text }]; return { ...model, turns: turns, nextId: model.nextId + 1 }; } case "clear": return { ...model, turns: [] }; } } `, }, { name: "push with a spread argument is taught (one element per call)", gate: "NS9001", src: ` export function f(xs: readonly number[]): readonly number[] { const out: number[] = []; out.push(...xs); return out; } `, }, { name: "pushing to the array a for...of iterates is taught, not silently snapshotted", gate: "NS9001", src: ` export function f(n: number): readonly number[] { const out: number[] = []; out.push(n); for (const x of out) { if (x > 0) out.push(x - 1); } return out; } `, }, { name: "a callback path falling off the end is taught (implicit undefined)", gate: "NS9001", src: ` export function f(xs: readonly number[]): readonly number[] { return xs.filter((x) => { if (x > 0) return true; }); } `, }, ]; // The local-mutation round: mutating array methods are legal on arrays the // function creates and still owns (the push-builder generalized to the full // method set); the teaching rules fire only at the true semantic boundaries // (shared inputs NS1001/NS1022, mutation after an escape NS1051). const localMutationCases: Case[] = [ { name: "R17m: recursion over borrowed readonly slices keeps the caller's ownership", src: ` function sumFrom(xs: readonly number[], i: number): number { if (i >= xs.length) return 0; return xs[i] + sumFrom(xs, i + 1); } export function f(n: number): number { const out: number[] = [n, n + 1]; const a = sumFrom(out, 0); out.push(n + 2); return a + sumFrom(out, 0); } `, }, { name: "NS1051: a readonly param handed onward into a MUTABLE position ends the borrow", gate: "NS1051", src: ` function scrub(xs: number[]): number { xs.pop(); return xs.length; } function relay(xs: readonly number[]): number { return scrub(xs as number[]); } export function f(): number { const out: number[] = [1, 2]; const t = relay(out); out.push(3); return t; } `, }, { name: "NS1051: a readonly param the callee aliases through a cast is no borrow", gate: "NS1051", src: ` function sneak(xs: readonly number[]): number { const grabbed = xs as number[]; return grabbed.length; } export function f(): number { const out: number[] = [1]; const t = sneak(out); out.push(2); return t; } `, }, { name: "owned mutation: a parser stack (push/pop) over a byte scan", src: ` export function maxDepth(bytes: Uint8Array): number { const stack: number[] = []; let max = 0; for (const b of bytes) { if (b === 40) stack.push(b); if (b === 41) stack.pop(); if (stack.length > max) max = stack.length; } return max; } `, }, { name: "owned mutation: pop and shift values ride the find-miss optional machinery", src: ` export function lastOr(xs: readonly number[], fallback: number): number { const work = xs.slice(); const v = work.pop(); if (v === undefined) return fallback; return v; } export function firstOr(xs: readonly number[], fallback: number): number { const work = xs.slice(); return work.shift() ?? fallback; } `, }, { name: "owned mutation: the canonical in-place sort (slice copy, then sort)", src: ` export interface Task { readonly id: number; readonly streak: number; } export function byStreak(tasks: readonly Task[]): readonly Task[] { const copy = tasks.slice(); copy.sort((a, b) => a.streak - b.streak); return copy; } export function ordered(xs: readonly number[]): readonly number[] { const copy = xs.slice(); copy.sort((a, b) => a - b); return copy; } `, }, { name: "owned mutation: splice in value and statement position, unshift, reverse, fill", src: ` export function surgery(xs: readonly number[]): readonly number[] { const work = xs.slice(); const removed = work.splice(1, 2, 9, 8); work.splice(0, 1); work.unshift(-1, -2); work.reverse(); work.fill(0, 1, 2); return removed.concat(work); } `, }, { name: "owned mutation: non-empty starts (literal seed, map/filter/concat/toSorted copies)", src: ` export function seeded(n: number): readonly number[] { const st = [1, 2, 3]; for (let i = 0; i < n; i++) st.push(i); return st; } export function doubledThenTrimmed(xs: readonly number[]): readonly number[] { const work = xs.map((x) => x * 2); work.pop(); return work; } export function keptThenGrown(xs: readonly number[], lim: number): readonly number[] { const work = xs.filter((x) => x > lim); work.push(lim); return work; } export function joinedThenRotated(a: readonly number[], b: readonly number[]): readonly number[] { const work = a.concat(b); const head = work.shift(); if (head !== undefined) work.push(head); return work; } export function sortedThenCapped(xs: readonly number[], cap: number): readonly number[] { const work = xs.toSorted((a, b) => a - b); work.fill(cap, -1); return work; } `, }, { name: "owned mutation: indexed writes and interleaved reads on owned arrays", src: ` export function swap(xs: readonly number[]): readonly number[] { const work = xs.slice(); if (work.length >= 2) { const tmp = work[0]; work[0] = work[work.length - 1]; work[work.length - 1] = tmp; } return work; } export function builderWrites(n: number): readonly number[] { const out: number[] = []; for (let i = 0; i < n; i++) out.push(i); if (out.length > 0) out[0] = out[out.length - 1] + 1; return out; } `, }, { name: "owned mutation: records pop into an optional record, splice moves them", src: ` export interface Task { readonly id: number; readonly done: boolean; } export function dropLastDone(tasks: readonly Task[]): readonly Task[] { const work = tasks.slice(); const last = work.pop(); if (last === undefined) return work; if (!last.done) work.push(last); return work; } export function promote(tasks: readonly Task[], at: number): readonly Task[] { const work = tasks.slice(); const moved = work.splice(at, 1); return moved.concat(work); } `, }, { name: "owned mutation: an early exit return is terminal, not an escape", src: ` export function padded(xs: readonly number[], min: number): readonly number[] { const work = xs.slice(); if (work.length >= min) return work; while (work.length < min) work.push(0); return work; } `, }, { name: "escape then mutate: push after the array was passed into a mutable position", gate: "NS1051", src: ` function total(xs: number[]): number { return xs.length; } export function f(): number { const out: number[] = [1]; const t = total(out); out.push(2); return t + out.length; } `, }, { name: "R17m: a readonly reader call is a borrow — mutation continues after it", src: ` function total(xs: readonly number[]): number { return xs.length; } export function f(): number { const out: number[] = [1]; const t = total(out); out.push(2); return t + out.length; } `, }, { name: "escape then mutate: pop after the array was stored into the returned record", gate: "NS1051", src: ` export interface Pair { readonly xs: readonly number[]; readonly n: number; } export function f(b: boolean): Pair { const out: number[] = [1, 2]; const pair: Pair = { xs: out, n: 0 }; if (b) out.pop(); return pair; } `, }, { name: "escape then mutate: aliasing ends the original's ownership", gate: "NS1051", src: ` export function f(): number { const a: number[] = [1]; const b = a; a.push(2); return b.length; } `, }, { name: "escape inside a loop gates the whole loop body (second iteration mutates after the pass)", gate: "NS1051", src: ` function probe(xs: number[]): number { return xs.length; } export function f(n: number): number { const out: number[] = []; let t = 0; for (let i = 0; i < n; i++) { out.push(i); t += probe(out); } return t; } `, }, { name: "never owned: mutating the alias of an owned array", gate: "NS1001", src: ` export function f(): number { const a: number[] = [1]; const b = a; b.push(2); return a.length; } `, }, { name: "never owned: pop on a parameter", gate: "NS1001", src: ` export function f(xs: number[]): number { return xs.pop() ?? -1; } `, }, { name: "never owned: splice on a model field through an as-cast", gate: "NS1001", src: ` export interface Model { readonly xs: readonly number[]; } export function f(model: Model): readonly number[] { (model.xs as number[]).splice(0, 1); return model.xs; } `, }, { name: "never owned: push on a module-level table", gate: "NS1001", src: ` const TABLE: number[] = [1, 2]; export function f(): number { TABLE.push(3); return TABLE.length; } `, }, { name: "never owned: an array produced by a helper call (copy with .slice to own it)", gate: "NS1001", src: ` function make(): number[] { return [1, 2]; } export function f(): readonly number[] { const xs = make(); xs.push(3); return xs; } `, }, { name: "never owned: indexed write through a parameter", gate: "NS1001", src: ` export function f(xs: number[]): number { xs[0] = 1; return xs[0]; } `, }, { name: "in-place sort keeps NS1022 on shared arrays, naming the local-copy idiom", gate: "NS1022", src: ` export function f(xs: number[]): number[] { xs.sort((a, b) => a - b); return xs; } `, }, { name: "in-place sort without a comparator is taught (JS ToString ordering)", gate: "NS9001", src: ` export function f(xs: readonly number[]): readonly number[] { const copy = xs.slice(); copy.sort(); return copy; } `, }, { name: "copyWithin stays out of v1 even on an owned array", gate: "NS1001", src: ` export function f(xs: readonly number[]): readonly number[] { const copy = xs.slice(); copy.copyWithin(0, 1); return copy; } `, }, { name: "sort/reverse in value position is taught (JS returns the same array)", gate: "NS9001", src: ` export function f(xs: readonly number[]): readonly number[] { const copy = xs.slice(); return copy.sort((a, b) => a - b); } `, }, { name: "unshift in value position is taught (the JS value is the new length)", gate: "NS9001", src: ` export function f(xs: readonly number[]): number { const copy = xs.slice(); const n = copy.unshift(0); return n; } `, }, { name: "splice with a spread argument is taught", gate: "NS9001", src: ` export function f(xs: readonly number[], ys: readonly number[]): readonly number[] { const copy = xs.slice(); copy.splice(0, 0, ...ys); return copy; } `, }, { name: "R17m: the appending write IS a push (the one growth shape)", src: ` export function f(): readonly number[] { const out = [1, 2]; out[out.length] = 3; return out; } `, }, { name: "a compound appending write is taught (it reads the missing slot first)", gate: "NS9001", src: ` export function f(): readonly number[] { const out = [1, 2]; out[out.length] += 3; return out; } `, }, { name: "length-changing mutation of the array a for...of iterates is taught", gate: "NS9001", src: ` export function f(): number { const out: number[] = [1, 2, 3]; let t = 0; for (const x of out) { t += x; out.pop(); } return t; } `, }, { name: "length-changing mutation from inside an iterating callback is taught", gate: "NS9001", src: ` export function f(xs: readonly number[]): number { const out: number[] = [1, 2, 3]; return out.reduce((acc, x) => { out.pop(); return acc + x; }, 0); } `, }, { name: "mutating a MIXED reassigned binding is taught (a shared array could ride in)", gate: "NS1001", src: ` export function f(xs: number[]): readonly number[] { let work = xs.slice(); work = xs; work.pop(); return work; } `, }, { name: "R17m: a reassigned binding of fresh copies stays owned (pop through the reassignment)", src: ` export function f(xs: readonly number[]): readonly number[] { let work = xs.slice(); work = xs.slice(); work.pop(); return work; } `, }, ]; const arrayStaticCases: Case[] = [ { name: "NS1059: Array.from is taught toward the spread copy", gate: "NS1059", src: `export function f(xs: readonly number[]): number { const c = Array.from(xs); return c.length; }`, }, { name: "NS1059: Array.of is taught toward the literal", gate: "NS1059", src: `export function f(): number { const c = Array.of(1, 2, 3); return c.length; }`, }, { name: "NS1041: Array.isArray stays the runtime type test it is", gate: "NS1041", src: `export function f(x: unknown): boolean { return Array.isArray(x); }`, }, ]; const mathAndTableCases: Case[] = [ { name: "Math batch: float sites, integer identities, and mixed min/max arities", src: ` export function flo(x: number): number { return Math.floor(x); } export function cei(x: number): number { return Math.ceil(x); } export function tru(x: number): number { return Math.trunc(x); } export function ab(x: number): number { return Math.abs(x); } export function sg(x: number): number { return Math.sign(x); } export function sq(x: number): number { return Math.sqrt(x); } export function floInt(bytes: Uint8Array): number { return Math.floor(bytes.length); } export function abInt(bytes: Uint8Array): number { return Math.abs(bytes.length - 10); } export function sgInt(bytes: Uint8Array): number { return Math.sign(bytes.length - 2); } export function sqInt(bytes: Uint8Array): number { return Math.sqrt(bytes.length); } export function noArgs(): number { return Math.min() + Math.max(); } export function oneArg(x: number): number { return Math.max(x); } export function three(a: number, b: number, c: number): number { return Math.min(a, b, c); } export function threeMixed(bytes: Uint8Array, x: number): number { return Math.max(bytes.length, x, 0); } `, }, { name: "Math comptime folds: module consts and expression positions", src: ` export const HALF = Math.floor(5 / 2); export const DOWN = Math.floor(-5 / 2); export const ROOT = Math.sqrt(2); export const NANV = Math.sign(0 / 0); export function pick(bytes: Uint8Array): number { return bytes[HALF]; } export function low(): number { return Math.min(3, 2.5); } export function ceilNegHalf(): number { return Math.ceil(-0.5); } `, }, { name: "a float Math.floor result used as an index is the taught NS1016, not invalid Zig", gate: "NS1016", src: ` export function pick(bytes: Uint8Array, x: number): number { return bytes[Math.floor(x / 2)]; } `, }, { name: "Math methods outside the v1 set are taught by name", gate: "NS9001", src: ` export function powed(x: number): number { return Math.pow(x, 2); } `, }, { name: "Number classifiers compile on float and integer-classed arguments", src: ` export function isInt(x: number): boolean { return Number.isInteger(x); } export function isFin(x: number): boolean { return Number.isFinite(x); } export function isNan(x: number): boolean { return Number.isNaN(x); } export function intAlways(bytes: Uint8Array): boolean { return Number.isInteger(bytes.length); } export function intFinite(bytes: Uint8Array): boolean { return Number.isFinite(bytes.length); } export function intNever(bytes: Uint8Array): boolean { return Number.isNaN(bytes.length); } export function guard(xs: readonly number[]): readonly number[] { return xs.filter((x) => Number.isFinite(x) && !Number.isNaN(x)); } `, }, { name: "Number methods outside the v1 classifiers are taught by name", gate: "NS9001", src: ` export function parsed(): number { return Number.parseFloat("1.5"); } `, }, { name: "the NaN and Infinity globals emit as f64 literals in every position", src: ` export function nanv(): number { return NaN; } export function inf(): number { return Infinity; } export function negInf(): number { return -Infinity; } export function isMax(x: number): boolean { return x === Infinity; } export function clamped(x: number): number { return Math.min(x, Infinity); } `, }, { name: "comptime % folds to the JS value (zero divisor, -0 dividend results, fractions)", src: ` export const REM_NAN = 5 % 0; export function nanv(): number { return 5 % 0; } export function negZero(): number { return -5 % 5; } export function frac(): number { return 5.5 % 2; } export function pick(bytes: Uint8Array): number { return bytes[6 % 4]; } `, }, { name: "module const tables: number/enum/string arrays, records, nested record arrays", src: ` import { asciiBytes } from "@native-sdk/core"; export type Filter = "all" | "active" | "done"; export const WEEKDAYS = [3, 5, 2, 8]; export const FACTORS: readonly number[] = [0.5, 1, 2]; export const ORDER: readonly Filter[] = ["done", "active", "all"]; export const NAMES: readonly string[] = ["mon", "tue"]; export const SEED_NAME = asciiBytes("Stretch"); export const DEFAULT_FILTER: Filter = "active"; export interface Limits { readonly lo: number; readonly hi: number; } export const LIMITS: Limits = { lo: 1, hi: 9 }; export interface Task { readonly id: number; readonly title: Uint8Array; readonly done: boolean; } export interface Model { readonly tasks: readonly Task[]; } export const SEEDS: readonly Task[] = [ { id: 1, title: asciiBytes("Ship"), done: false }, { id: 2, title: asciiBytes("Test"), done: true }, ]; export function initialModel(): Model { return { tasks: SEEDS }; } export function weekdayAt(i: number): number { return WEEKDAYS[i]; } export function weekdayCount(): number { return WEEKDAYS.length; } export function weekdayTotal(): number { let t = 0; for (const w of WEEKDAYS) t += w; return t; } export function bigWeekdays(lim: number): readonly number[] { return WEEKDAYS.filter((w) => w > lim); } export function orderAt(i: number): Filter { return ORDER[i]; } export function nameMatches(n: string): boolean { return NAMES[0] === n; } export function seedTitle(i: number): Uint8Array { return SEEDS[i].title; } export function inRange(x: number): boolean { return x >= LIMITS.lo && x <= LIMITS.hi; } `, }, { name: "an unannotated module const record is taught toward the interface annotation", gate: "NS9001", src: ` export const LIMITS = { lo: 1, hi: 9 }; export function f(): number { return 1; } `, }, { name: "a spread in a module const table is a taught stop (tables are comptime data)", gate: "NS9001", src: ` export interface Limits { readonly lo: number; readonly hi: number; } export const BASE: Limits = { lo: 1, hi: 9 }; export const WIDE: Limits = { ...BASE, hi: 99 }; export function f(): number { return 1; } `, }, { name: "a table number that does not fold at compile time is a taught stop", gate: "NS9001", src: ` function seed(): number { return 3; } export const TABLE: readonly number[] = [1, seed()]; export function f(): number { return TABLE[0]; } `, }, { name: "type-changing map: scalars, bytes, block bodies, optional results, chained reads", src: ` export interface Task { readonly id: number; readonly title: Uint8Array; readonly streak: number; } export function ids(tasks: readonly Task[]): readonly number[] { return tasks.map((t) => t.id); } export function titles(tasks: readonly Task[]): readonly Uint8Array[] { return tasks.map((t) => t.title); } export function doubled(tasks: readonly Task[]): readonly number[] { return tasks.map((t) => t.streak * 2); } export function orNull(xs: readonly number[]): readonly (number | null)[] { return xs.map((x) => (x > 0 ? x : null)); } export function capped(tasks: readonly Task[], lim: number): readonly number[] { return tasks.map((t) => { if (t.streak > lim) return lim; return t.streak; }); } export function mappedCount(tasks: readonly Task[]): number { return tasks.map((t) => t.id).length; } export function firstTwoIds(tasks: readonly Task[]): readonly number[] { const all = tasks.map((t) => t.id); return all.slice(0, 2); } `, }, { name: "callback index parameters across map/filter/find/findIndex/some/every", src: ` export interface Task { readonly id: number; readonly streak: number; } export function weighted(xs: readonly number[]): readonly number[] { return xs.map((x, i) => x * i); } export function evenSlots(xs: readonly number[]): readonly number[] { return xs.filter((x, i) => i % 2 === 0); } export function lateBig(xs: readonly number[], at: number): number { return xs.find((x, i) => i > at && x > 0) ?? -1; } export function lateAt(xs: readonly number[], at: number): number { return xs.findIndex((x, i) => i >= at && x > 0); } export function anyLate(xs: readonly number[], at: number): boolean { return xs.some((x, i) => i > at); } export function frontLoaded(tasks: readonly Task[]): boolean { return tasks.every((t, i) => t.streak >= i); } `, }, { name: "a callback declaring the third (array) parameter is a taught stop", gate: "NS9001", src: ` export function f(xs: readonly number[]): readonly number[] { return xs.map((x, i, all) => x + all.length); } `, }, { name: "a reduce callback with an index parameter is a taught stop", gate: "NS9001", src: ` export function f(xs: readonly number[]): number { return xs.reduce((sum, x, i) => sum + x * i, 0); } `, }, { name: "bytes subarray with out-of-range and negative bounds compiles to the clamped view", src: ` export function window(bytes: Uint8Array, from: number, to: number): Uint8Array { return bytes.subarray(from, to); } export function tail(bytes: Uint8Array, from: number): Uint8Array { return bytes.subarray(from); } export function whole(bytes: Uint8Array): Uint8Array { return bytes.subarray(); } export function chained(bytes: Uint8Array, from: number): Uint8Array { return bytes.subarray(from).subarray(-2); } `, }, { name: "array-method calls lower directly inside if and else-if conditions", src: ` export interface Task { readonly id: number; readonly done: boolean; } export function grade(xs: readonly number[], flag: boolean): number { if (flag) return -1; else if (xs.some((x) => x > 3)) return 1; else if (xs.every((x) => x < 0)) return 2; return 0; } export function firstDone(tasks: readonly Task[]): number { if (tasks.some((t) => t.done)) { const hit = tasks.find((t) => t.done); if (hit === undefined) return -1; return hit.id; } return 0; } export function countIf(xs: readonly number[], lim: number): number { if (xs.filter((x) => x > lim).length > 1) return 2; return xs.findIndex((x) => x > lim) >= 0 ? 1 : 0; } `, }, { name: "a while condition still may not lower statements (re-evaluated per iteration)", gate: "NS9001", src: ` export function f(xs: readonly number[]): number { let n = 0; while (xs.some((x) => x > n)) { n += 1; } return n; } `, }, { name: "switch on a literal-union value: full coverage, shared labels, defaults, partial + break", src: ` export type Filter = "all" | "active" | "done"; export type Bit = 0 | 1; export function label(f: Filter): number { switch (f) { case "all": return 0; case "active": return 1; case "done": return 2; } } export function sharedBody(f: Filter): number { switch (f) { case "active": case "done": return 1; default: return 0; } } export function partial(f: Filter): number { let n = 0; switch (f) { case "done": n = 5; break; case "active": { n = 2; break; } } return n; } export function flip(b: Bit): number { switch (b) { case 0: return 1; case 1: return 0; } } export function bitDefault(b: Bit): number { switch (b) { case 0: return 7; default: return 9; } } `, }, { name: "a value-switch default that is not the last clause is a taught stop", gate: "NS9001", src: ` export type Filter = "all" | "active" | "done"; export function f(x: Filter): number { switch (x) { case "all": return 0; default: return 9; case "done": return 2; } return 1; } `, }, { name: "case labels falling through into a value-switch default are a taught stop", gate: "NS9001", src: ` export type Filter = "all" | "active" | "done"; export function f(x: Filter): number { switch (x) { case "all": default: return 9; } } `, }, { name: "switching on a plain number value emits the if/else chain", src: ` export function f(x: number): number { switch (x) { case 1: return 1; default: return 0; } } `, }, ]; // The model tier (round 3): tagged unions as model fields, primitive arrays // in the model, optional fields end to end, null-guarded `&&`/`||` chains, // the -0 slot rule, and the NS1024 string-field gate. const modelTierCases: Case[] = [ { name: "a tag-discriminated union as a model field: construction, switch, kind guards", src: ` export type View = | { readonly kind: "list" } | { readonly kind: "detail"; readonly id: number }; export interface Model { readonly view: View; readonly n: number; } export type Msg = { readonly kind: "open"; readonly id: number } | { readonly kind: "back" }; export function initialModel(): Model { return { view: { kind: "list" }, n: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "open": return { ...model, view: { kind: "detail", id: msg.id } }; case "back": return { ...model, view: { kind: "list" } }; } } export function shownId(model: Model): number { if (model.view.kind === "detail") return model.view.id; return -1; } export function viewCode(model: Model): number { switch (model.view.kind) { case "list": return 0; case "detail": return model.view.id; } } `, }, { name: "model union arms with deep payloads: records, bytes, and primitive arrays", src: ` import { asciiBytes } from "@native-sdk/core"; export interface Note { readonly id: number; readonly title: Uint8Array; } export type View = | { readonly kind: "list"; readonly scroll: number } | { readonly kind: "detail"; readonly note: Note; readonly tags: readonly number[] } | { readonly kind: "compose"; readonly draft: Uint8Array }; export interface Model { readonly view: View | null; readonly flags: readonly boolean[]; } export type Msg = { readonly kind: "open"; readonly id: number } | { readonly kind: "close" }; export function initialModel(): Model { return { view: null, flags: [] }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "open": return { ...model, view: { kind: "detail", note: { id: msg.id, title: asciiBytes("note") }, tags: [1, 2, 3] } }; case "close": return { ...model, view: { kind: "list", scroll: 0 } }; } } export function weight(model: Model): number { if (model.view !== null && model.view.kind === "detail") return model.view.note.id + model.view.tags.length; return 0; } `, }, { name: "primitive arrays in the model: numbers, booleans, tags, nested and optional", src: ` export type Grade = "low" | "high"; export interface Series { readonly points: readonly number[]; readonly name: Uint8Array; } export interface Model { readonly xs: readonly number[]; readonly flags: readonly boolean[]; readonly grades: readonly Grade[]; readonly series: readonly Series[]; readonly pending: readonly number[] | null; } export type Msg = { readonly kind: "push"; readonly v: number } | { readonly kind: "clear" }; export function initialModel(): Model { return { xs: [], flags: [], grades: [], series: [], pending: null }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "push": return { ...model, xs: [...model.xs, msg.v], flags: [...model.flags, msg.v > 0], pending: model.xs }; case "clear": return { ...model, xs: [], flags: [], pending: null }; } } export function total(model: Model): number { return model.xs.reduce((sum, x) => sum + x, 0); } `, }, { name: "null-guarded && chains: statement, else-bearing, ternary, both orders, relational optionals", src: ` export interface Sel { readonly items: readonly number[]; readonly at: number; } export interface Model { readonly sel: Sel | null; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; export function initialModel(): Model { return { sel: null }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "a": return model; case "b": return { sel: null }; } } export function hasItems(model: Model): boolean { if (model.sel !== null && model.sel.items.length > 0) return true; return false; } export function branchy(model: Model): number { if (model.sel !== null && model.sel.at > 0) return model.sel.at; else return -1; } export function ternary(model: Model): number { return model.sel !== null && model.sel.at > 0 ? model.sel.at : -1; } export function flipped(model: Model): boolean { return null !== model.sel && model.sel.at >= 0; } export function below(cls: number | null, lim: number): boolean { return cls !== null && cls < lim; } `, }, { name: "null-guarded || chains: or-else shape, exit narrowing, ternary dual", src: ` export interface Sel { readonly items: readonly number[]; readonly at: number; } export function emptyish(sel: Sel | null): boolean { return sel === null || sel.items.length === 0; } export function firstOrMinus(sel: Sel | null): number { if (sel === null || sel.items.length === 0) return -1; return sel.items[0]; } export function clamp(cls: number | null): number { if (cls === null || cls < 0) return 0; return cls; } export function pick(sel: Sel | null): number { return sel === null || sel.at < 0 ? -1 : sel.at; } `, }, { name: "a null guard in a while condition re-tests per iteration", src: ` export interface Sel { readonly at: number; readonly len: number; } export function walk(start: Sel | null): number { let cur: Sel | null = start; let hops = 0; while (cur !== null && cur.len > 0) { hops += cur.len; cur = cur.len > 2 ? { at: cur.at, len: cur.len - 1 } : null; } return hops; } `, }, { name: "-0 literals and -0-producing constant arithmetic take float slots", src: ` export function negZero(): number { return -0; } export function prodNegZero(): number { return 0 * -1; } export function viaConst(): number { const z = -0; return z; } export function timesNeg(x: number): number { return x * -1; } `, }, { name: "nested callbacks with colliding element and index names emit uniquely", src: ` export function weights(xs: readonly number[]): number { return xs.map((x, i) => xs.map((y, i2) => y * i2 + i).reduce((acc, v) => acc + v, 0) + x * i).reduce((acc, v) => acc + v, 0); } export function pairs(xs: readonly number[]): number { return xs.map((x, i) => xs.map((x2, j) => x2 * x + j * i).reduce((a, v) => a + v, 0)).reduce((a, v) => a + v, 0); } `, }, { name: "a string-typed model field is a taught stop at the declaration", gate: "NS1024", src: ` export interface Model { readonly title: string; readonly n: number; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; export function initialModel(): Model { return { title: "x", n: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "a": return model; case "b": return model; } } `, }, { name: "a string field nested in a model union arm is the same taught stop", gate: "NS1024", src: ` export type View = | { readonly kind: "list" } | { readonly kind: "detail"; readonly caption: string }; export interface Model { readonly view: View; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; export function initialModel(): Model { return { view: { kind: "list" } }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "a": return model; case "b": return model; } } `, }, { name: "a string-array model field is the same taught stop", gate: "NS1024", src: ` export interface Model { readonly names: readonly string[]; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; export function initialModel(): Model { return { names: [] }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "a": return model; case "b": return model; } } `, }, { name: "an array of unions in the model stays a loud stop (not in v1)", gate: "NS9001", src: ` export type Item = { readonly kind: "a" } | { readonly kind: "b"; readonly n: number }; export interface Model { readonly items: readonly Item[]; } export type Msg = { readonly kind: "x" } | { readonly kind: "y" }; export function initialModel(): Model { return { items: [] }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "x": return model; case "y": return model; } } `, }, { name: "an array of byte-strings in the model stays a loud stop (not in v1)", gate: "NS9001", src: ` export interface Model { readonly rows: readonly Uint8Array[]; } export type Msg = { readonly kind: "x" } | { readonly kind: "y" }; export function initialModel(): Model { return { rows: [] }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "x": return model; case "y": return model; } } `, }, ]; // A shared preamble for the streaming-op cases (slice D): every arm shape // a spawn/audio stream can target, plus the audio event record. const streamMsg = ` export type AudioState = "loaded" | "position" | "completed" | "failed" | "rejected" | "spectrum"; export interface Model { readonly lines: number; readonly out: Uint8Array; readonly code: number; readonly errs: number; readonly pos: number; } export type Msg = | { readonly kind: "go"; readonly which: number } | { readonly kind: "line"; readonly text: Uint8Array } | { readonly kind: "done"; readonly code: number } | { readonly kind: "sampled"; readonly code: number; readonly output: Uint8Array } | { readonly kind: "audio_evt"; readonly state: AudioState; readonly positionMs: number; readonly durationMs: number; readonly playing: boolean; readonly buffering: boolean; readonly bands: Uint8Array } | { readonly kind: "failed"; readonly why: Uint8Array }; export function initialModel(): Model { return { lines: 0, out: new Uint8Array(0), code: -1, errs: 0, pos: 0 }; } `; // The tail arms every streaming case's update must cover. const streamTail = ` case "line": return { ...model, lines: model.lines + 1 }; case "done": return { ...model, code: msg.code }; case "sampled": return { ...model, code: msg.code, out: msg.output }; case "audio_evt": return { ...model, pos: msg.positionMs }; case "failed": return { ...model, errs: model.errs + 1 }; } } `; // Slice E: grammar-completeness round — the new statement/operator/ // declaration mappings in REALISTIC combinations (the minimal per-production // pins live in grammar_matrix.test.ts), plus the new teaching gates. const grammarCases: Case[] = [ { name: "do-while inside update with model narrowing and a builder", src: ` export interface Model { readonly xs: readonly number[]; readonly cursor: number | null; } export type Msg = { readonly kind: "walk" } | { readonly kind: "noop" }; export function initialModel(): Model { return { xs: [3, 1, 2], cursor: null }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "walk": { const out: number[] = []; let i = 0; do { if (i < model.xs.length) out.push(model.xs[i] * 2); i += 1; } while (i < model.xs.length); return { ...model, xs: out }; } case "noop": return model; } }`, }, { name: "a do-while whose body always exits emits no unreachable trailing test", src: ` export function firstByte(xs: Uint8Array): number { do { if (xs.length > 0) return xs[0]; return -1; } while (true); }`, }, { name: "labeled loops drive nested scans over record arrays", src: ` export interface Cell { readonly row: number; readonly col: number; } export function firstMatch(cells: readonly Cell[], rows: number, cols: number): number { let hit = -1; outer: for (let r = 0; r < rows; r++) { for (let c = 0; c < cols; c++) { for (const cell of cells) { if (cell.row === r && cell.col === c) { hit = r * 100 + c; break outer; } } } } return hit; }`, }, { name: "a default arm coexists with payload captures on the named cases", src: ` export interface Model { readonly n: number; } export type Msg = | { readonly kind: "set"; readonly v: number } | { readonly kind: "bump"; readonly by: number } | { readonly kind: "reset" } | { readonly kind: "noop" }; export function initialModel(): Model { return { n: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "set": return { n: msg.v }; case "bump": return { n: model.n + msg.by }; default: return model; } }`, }, { name: "exponent, shifts, and the compound family flow through inference soundly", src: ` export function checksum(xs: Uint8Array): number { let h = 0; for (const b of xs) { h ^= b; h <<= 1; h >>>= 0; h &= 0xffff; } return h; } export function decay(base: number, steps: Uint8Array): number { let v = base; for (const s of steps) { v *= 0.5; v += s; v **= 1; } v /= 2; return v; }`, }, { name: "destructured const fields feed integer and float domains per field", src: ` export interface Frame { readonly width: number; readonly height: number; readonly scale: number; } export function area(frame: Frame, bytes: Uint8Array): number { const { width, height, scale } = frame; let cells = 0; for (let i = 0; i < bytes.length; i++) { if (bytes[i] > 0) cells += 1; } return width * height * scale + cells; }`, }, { name: "NS1039: the intrinsic SDK module is imported by name", gate: "NS1039", src: ` import * as sdk from "@native-sdk/core"; export function f(): number { return 1; }`, }, { name: "R15d: a const-bound local arrow hoists to a module-level function", src: `export function f(): number { const g = (x: number): number => x + 1; return g(1); }`, }, { name: "NS1054: a capturing local function value is taught toward parameters", gate: "NS1054", src: `export function f(n: number): number { const g = (): number => n + 1; return g(); }`, }, { name: "export lists bind names over declarations: un-renamed exports pub, renames alias", src: `function base(): number { return 2; } const SCALE = 3; export { base, SCALE as FACTOR }; export function f(): number { return base() * SCALE; }`, }, { name: "NS1047: re-exporting the SDK surface is not the core's to bind", gate: "NS1047", src: `import { Cmd } from "@native-sdk/core"; export { Cmd }; export function f(): number { return 1; }`, }, { name: "NS1047: renaming a generic template has no single value to bind", gate: "NS1047", src: `function pick(a: T, b: T, first: boolean): T { return first ? a : b; } export { pick as choose }; export function f(x: number, y: number): number { return pick(x, y, x < y); }`, }, { name: "NS1014: a renamed export cannot bind an entry-point name", gate: "NS1014", src: ` export interface Model { readonly n: number; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; function step(model: Model, msg: Msg): Model { return model; } export { step as update }; export function initialModel(): Model { return { n: 0 }; }`, }, { name: "NS1048: loose equality is taught toward strict", gate: "NS1048", src: `export function f(a: number, b: number): boolean { return a != b; }`, }, { name: "NS1049: var in a for-init is taught toward let", gate: "NS1049", src: `export function f(n: number): number { let t = 0; for (var i = 0; i < n; i++) { t += i; } return t; }`, }, { name: "R15e: a generic helper monomorphizes per call site", src: `export function pick(a: T, b: T, first: boolean): T { return first ? a : b; } export function f(x: number, y: number): number { return pick(x, y, x < y); }`, }, { name: "NS1050: a generic function VALUE is taught toward a module-level declaration", gate: "NS1050", src: `export function f(): number { const id = (x: T): T => x; return id(1); }`, }, ]; // Slice D: the streaming multi-result ops — subprocess spawn and the audio // event stream — emit-clean in their documented shapes, gated with the // taught rules everywhere else. const streamingCases: Case[] = [ { name: "spawn and the audio verbs emit in their documented shapes", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": if (msg.which === 0) return [model, Cmd.spawn([asciiBytes("/bin/ps"), asciiBytes("-axo")], { key: "ps", line: "line", exit: "done", err: "failed" })]; if (msg.which === 1) return [model, Cmd.spawn([asciiBytes("/usr/bin/pbcopy")], { key: "copy", stdin: model.out, exit: "done", err: "failed" })]; if (msg.which === 2) return [model, Cmd.spawn([asciiBytes("/usr/bin/vm_stat")], { key: "mem", collect: true, exit: "sampled", err: "failed" })]; if (msg.which === 3) return [model, Cmd.cancel("ps")]; if (msg.which === 4) return [model, Cmd.audioPlay("player", { path: asciiBytes("music/track.mp3") }, { event: "audio_evt" })]; if (msg.which === 5) return [model, Cmd.audioPlay("player", { url: asciiBytes("https://cdn.test/track.mp3"), cachePath: model.out, expectedBytes: 4096 }, { event: "audio_evt" })]; if (msg.which === 6) return [model, Cmd.batch([Cmd.audioPause("player"), Cmd.audioResume("player")])]; if (msg.which === 7) return [model, Cmd.audioSeek("player", 45000)]; if (msg.which === 8) return [model, Cmd.audioSetVolume("player", 0.5)]; return [model, Cmd.audioStop("player")]; ${streamTail} `, }, { name: "a line-mode spawn exit arm without a single number payload is taught", gate: "NS1027", src: ` import { Cmd, asciiBytes, type TimestampKind } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.spawn([asciiBytes("/bin/ps")], { line: "line", exit: "line" as TimestampKind, err: "failed" })]; ${streamTail} `, }, { name: "a collect spawn exit arm that is not a { code, output } record is taught", gate: "NS1027", src: ` import { Cmd, asciiBytes, type FetchedKind } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.spawn([asciiBytes("/bin/ps")], { collect: true, exit: "done" as FetchedKind, err: "failed" })]; ${streamTail} `, }, { name: "a line arm on a collect spawn is taught (collect has no line framing)", gate: "NS1027", src: ` import { Cmd, asciiBytes, type SpawnCollectRoute } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.spawn([asciiBytes("/bin/ps")], { collect: true, line: "line", exit: "sampled", err: "failed" } as SpawnCollectRoute)]; ${streamTail} `, }, { name: "a dynamic argv value is taught (argv is an inline array literal)", gate: "NS1029", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${streamMsg} const PS: readonly Uint8Array[] = [asciiBytes("/bin/ps")]; export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.spawn(PS, { exit: "done", err: "failed" })]; ${streamTail} `, }, { name: "an empty argv stops at compile time", gate: "NS1030", src: ` import { Cmd } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.spawn([], { exit: "done", err: "failed" })]; ${streamTail} `, }, { name: "more argv elements than the engine accepts stops at compile time", gate: "NS1030", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.spawn([${Array.from({ length: 17 }, (_, i) => `asciiBytes("a${i}")`).join(", ")}], { exit: "done", err: "failed" })]; ${streamTail} `, }, { name: "an argv block over the engine's byte bound stops at compile time", gate: "NS1030", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.spawn([asciiBytes("/bin/echo"), asciiBytes(${JSON.stringify("a".repeat(2048))})], { exit: "done", err: "failed" })]; ${streamTail} `, }, { name: "an over-bound stdin literal stops at compile time", gate: "NS1030", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.spawn([asciiBytes("/usr/bin/pbcopy")], { stdin: asciiBytes(${JSON.stringify("s".repeat(4097))}), exit: "done", err: "failed" })]; ${streamTail} `, }, { name: "an audio event arm whose state union misses a member is taught", gate: "NS1027", src: ` import { Cmd, asciiBytes, type AudioEventKind } from "@native-sdk/core"; export type NarrowState = "loaded" | "position" | "completed" | "failed" | "rejected"; export interface Model { readonly pos: number; readonly errs: number; } export type Msg = | { readonly kind: "go" } | { readonly kind: "audio_evt"; readonly state: NarrowState; readonly positionMs: number; readonly durationMs: number; readonly playing: boolean; readonly buffering: boolean; readonly bands: Uint8Array } | { readonly kind: "failed"; readonly why: Uint8Array }; export function initialModel(): Model { return { pos: 0, errs: 0 }; } export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.audioPlay("player", { path: asciiBytes("a.mp3") }, { event: "audio_evt" as AudioEventKind })]; case "audio_evt": return { ...model, pos: msg.positionMs }; case "failed": return { ...model, errs: model.errs + 1 }; } } `, }, { name: "an audio event arm with a wrong field shape is taught", gate: "NS1027", src: ` import { Cmd, asciiBytes, type AudioEventKind } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.audioPlay("player", { path: asciiBytes("a.mp3") }, { event: "sampled" as AudioEventKind })]; ${streamTail} `, }, { name: "an audio source without a path or url is taught (nothing could play)", gate: "NS1029", src: ` import { Cmd, asciiBytes } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.audioPlay("player", { cachePath: asciiBytes("cache/a.mp3") }, { event: "audio_evt" })]; ${streamTail} `, }, { name: "a dynamic audio key is taught (keys are compile-time routing data)", gate: "NS1027", src: ` import { Cmd } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.audioPause(model.errs > 0 ? "a" : "b")]; ${streamTail} `, }, { name: "an audio volume literal outside 0..1 stops at compile time", gate: "NS1030", src: ` import { Cmd } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.audioSetVolume("player", 1.5)]; ${streamTail} `, }, { name: "a negative audio seek literal stops at compile time", gate: "NS1030", src: ` import { Cmd } from "@native-sdk/core"; ${streamMsg} export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "go": return [model, Cmd.audioSeek("player", -250)]; ${streamTail} `, }, ]; // The multi-file round: a core may split into modules under src/ (relative // imports with real .ts filenames), and SDK library modules // ("@native-sdk/core/text") transpile in when imported. Emit cases join the // zig-compile corpus below; boundary mistakes are gated by NS1034-NS1038 // and the narrowed NS1014 (entry contract). interface MultiFileCase { readonly name: string; readonly gate?: string; readonly files: Record; } const multiFileCases: MultiFileCase[] = [ { name: "namespace imports alias in-graph modules: values, calls, qualified types, cross-class args", files: { "core.ts": ` import * as util from "./util.ts"; export interface Model { readonly n: number; } export type Msg = { readonly kind: "bump" } | { readonly kind: "reset" }; export function initialModel(): Model { return { n: util.SEED }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "bump": { const cfg: util.Cfg = { step: 2, scale: 1.5 }; return { n: util.grow(model.n, cfg) }; } case "reset": return { n: util.SEED }; } }`, "util.ts": ` export interface Cfg { readonly step: number; readonly scale: number; } export const SEED = 5; export function grow(n: number, cfg: Cfg): number { return n + cfg.step * cfg.scale; }`, }, }, { name: "NS1039: a namespace alias used as a value is taught", gate: "NS1039", files: { "core.ts": ` import * as util from "./util.ts"; const grabbed = util; export function f(): number { return grabbed.SEED; }`, "util.ts": `export const SEED = 5;`, }, }, { name: "NS1038: a type and a same-file exported value cannot share a name", gate: "NS1038", files: { "core.ts": ` export interface Config { readonly n: number; } export const Config = { n: 1 }; export function f(c: Config): number { return c.n; }`, }, }, { name: "value re-exports chain across modules and renames bind new names", files: { "core.ts": ` import { bump } from "./api.ts"; function tripled(n: number): number { return n * 3; } export { tripled as thrice }; export { bump } from "./api.ts"; export function f(n: number): number { return bump(n) + tripled(n); }`, "api.ts": `export { bump } from "./impl.ts";`, "impl.ts": `export function bump(n: number): number { return n + 1; }`, }, }, { name: "NS1014: an imported module list-exporting an entry point is taught", gate: "NS1014", files: { "core.ts": ` import { helper } from "./extra.ts"; export interface Model { readonly n: number; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; export function initialModel(): Model { return { n: helper() }; } export function update(model: Model, msg: Msg): Model { return model; }`, "extra.ts": ` export function helper(): number { return 1; } function subscriptions(): number { return 2; } export { subscriptions };`, }, }, { name: "NS1014: the entry re-exporting an entry point from an imported module is taught", gate: "NS1014", files: { "core.ts": ` export interface Model { readonly n: number; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; export { update } from "./logic.ts"; export function initialModel(): Model { return { n: 0 }; }`, "logic.ts": ` import type { Model, Msg } from "./core.ts"; export function update(model: Model, msg: Msg): Model { return model; }`, }, }, { name: "a renamed export-list helper joins the model binding surface under its exported name", files: { "core.ts": ` export interface Model { readonly tasks: readonly number[]; } export type Msg = { readonly kind: "a" } | { readonly kind: "b" }; export function initialModel(): Model { return { tasks: [] }; } export function update(model: Model, msg: Msg): Model { return model; } function taskTotal(model: Model): number { return model.tasks.length; } export { taskTotal as taskCount }; export const viewUnbound = ["taskCount"] as const;`, }, }, { name: "NS1038: a renamed export colliding with another module's exported value is taught", gate: "NS1038", files: { "core.ts": ` import { pickOne } from "./util.ts"; function localPick(): number { return 2; } export { localPick as pickOne }; export function f(): number { return pickOne() + localPick(); }`, "util.ts": `export function pickOne(): number { return 1; }`, }, }, { name: "cross-file types, tables, consts, and helpers resolve and emit", files: { "core.ts": ` import { asciiBytes } from "@native-sdk/core"; import { LIMIT, SEEDS, capped, label, type Item, type Level } from "./tables.ts"; export interface Model { readonly items: readonly Item[]; readonly count: number; readonly level: Level; } export type Msg = { readonly kind: "add" } | { readonly kind: "reset" }; export function initialModel(): Model { return { items: SEEDS, count: 0, level: "low" }; } export function title(model: Model): Uint8Array { return label(model.level); } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "add": return { ...model, count: capped(model.count + 1), level: model.count + 1 >= LIMIT ? "high" : "low" }; case "reset": return { ...model, count: LIMIT - LIMIT, level: "low" }; } } `, "tables.ts": ` import { asciiBytes } from "@native-sdk/core"; export type Level = "low" | "high"; export interface Item { readonly id: number; readonly name: Uint8Array; } export const LIMIT = 3; export const SEEDS: readonly Item[] = [ { id: 1, name: asciiBytes("one") }, { id: 2, name: asciiBytes("two") }, ]; export function capped(n: number): number { return n > LIMIT ? LIMIT : n; } export function label(level: Level): Uint8Array { return level === "low" ? asciiBytes("Low") : asciiBytes("High"); } `, }, }, { name: "cross-file discriminated union payloads and subdirectory modules", files: { "core.ts": ` import { emptyView, viewName, type View } from "./ui/views.ts"; export interface Model { readonly view: View; } export type Msg = { readonly kind: "open"; readonly id: number } | { readonly kind: "close" }; export function initialModel(): Model { return { view: emptyView() }; } export function currentView(model: Model): Uint8Array { return viewName(model.view); } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "open": return { view: { kind: "detail", id: msg.id } }; case "close": return { view: emptyView() }; } } `, "ui/views.ts": ` import { asciiBytes } from "@native-sdk/core"; export type View = { readonly kind: "list" } | { readonly kind: "detail"; readonly id: number }; export function emptyView(): View { return { kind: "list" }; } export function viewName(view: View): Uint8Array { switch (view.kind) { case "list": return asciiBytes("list"); case "detail": return asciiBytes("detail"); } return asciiBytes("list"); } `, }, }, { name: "the SDK text library transpiles in when imported", files: { "core.ts": ` import { asciiBytes } from "@native-sdk/core"; import { applyTextInputEvent, containsIgnoreCase, trimAsciiSpaces, type TextEditState, type TextInputEvent } from "@native-sdk/core/text"; export interface Model { readonly draft: Uint8Array; } export type Msg = { readonly kind: "edit"; readonly edit: TextInputEvent } | { readonly kind: "clear" }; export function initialModel(): Model { return { draft: new Uint8Array(0) }; } export function matchesHello(model: Model): boolean { return containsIgnoreCase(trimAsciiSpaces(model.draft), asciiBytes("hello")); } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "edit": { const state: TextEditState = { text: model.draft, selection: { anchor: model.draft.length, focus: model.draft.length }, composition: null }; const next = applyTextInputEvent(state, msg.edit, 64); if (next === null) return model; return { draft: next.text }; } case "clear": return { draft: new Uint8Array(0) }; } } `, }, }, { name: "type-only back-edges are legal (helpers over the entry's Model)", files: { "core.ts": ` import { bump } from "./logic.ts"; export interface Model { readonly count: number; } export type Msg = { readonly kind: "add" } | { readonly kind: "noop" }; export function initialModel(): Model { return { count: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "add": return bump(model); case "noop": return model; } } `, "logic.ts": ` import type { Model } from "./core.ts"; export function bump(model: Model): Model { return { ...model, count: model.count + 1 }; } `, }, }, { name: "colliding PRIVATE helpers unique with a per-module prefix", files: { "core.ts": ` import { first } from "./a.ts"; import { second } from "./b.ts"; export interface Model { readonly count: number; } export type Msg = { readonly kind: "go" } | { readonly kind: "noop" }; export function initialModel(): Model { return { count: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "go": return { count: first(model.count) + second(model.count) }; case "noop": return model; } } `, "a.ts": ` function scale(n: number): number { return n * 2; } export function first(n: number): number { return scale(n); } `, "b.ts": ` function scale(n: number): number { return n * 3; } export function second(n: number): number { return scale(n); } `, }, }, { name: "an import escaping src/ is taught (NS1034)", gate: "NS1034", files: { "core.ts": ` // @ts-expect-error the escape is rejected before resolution matters. import { helper } from "../outside.ts"; export const y = helper; `, }, }, { name: "a bare npm runtime import is taught (NS1035)", gate: "NS1035", files: { "core.ts": ` // @ts-expect-error the package deliberately does not resolve. import { thing } from "lodash"; export const y = thing; `, }, }, { name: "a runtime import cycle is taught (NS1036)", gate: "NS1036", files: { "core.ts": ` import { a } from "./a.ts"; export const y = a; `, "a.ts": ` import { b } from "./b.ts"; export const a = b + 1; `, "b.ts": ` import { a } from "./a.ts"; export const b = a + 1; `, }, }, { name: "a missing module file is taught (NS1037)", gate: "NS1037", files: { "core.ts": ` // @ts-expect-error the module deliberately does not exist. import { gone } from "./gone.ts"; export const y = gone; `, }, }, { name: "an unknown @native-sdk module is taught (NS1037)", gate: "NS1037", files: { "core.ts": ` // @ts-expect-error the SDK ships no such module. import { nope } from "@native-sdk/core/nope"; export const y = nope; `, }, }, { name: "a cross-file type-name collision is taught (NS1038)", gate: "NS1038", files: { "core.ts": ` import { seed } from "./other.ts"; export interface Item { readonly id: number; } export const first: Item = { id: 1 }; export const second = seed; `, "other.ts": ` export interface Item { readonly id: number; readonly extra: boolean; } export function seed(): Item { return { id: 2, extra: true }; } `, }, }, { name: "a cross-file EXPORTED value collision is taught (NS1038)", gate: "NS1038", files: { "core.ts": ` import { helper } from "./other.ts"; export function scale(n: number): number { return n * 2; } export const y = helper(scale(2)); `, "other.ts": ` export function scale(n: number): number { return n * 3; } export function helper(n: number): number { return scale(n); } `, }, }, { name: "update exported from an imported module is taught (NS1014, the entry contract)", gate: "NS1014", files: { "core.ts": ` import { seed } from "./logic.ts"; export interface Model { readonly count: number; } export type Msg = { readonly kind: "add" } | { readonly kind: "noop" }; export function initialModel(): Model { return seed(); } `, "logic.ts": ` import type { Model, Msg } from "./core.ts"; export function seed(): Model { return { count: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "add": return { count: model.count + 1 }; case "noop": return model; } } `, }, }, { name: "viewUnbound declared in an imported module is taught (NS1014)", gate: "NS1014", files: { "core.ts": ` import { seed } from "./logic.ts"; export interface Model { readonly count: number; } export type Msg = { readonly kind: "add" } | { readonly kind: "noop" }; export function initialModel(): Model { return seed(); } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "add": return { count: model.count + 1 }; case "noop": return model; } } `, "logic.ts": ` import type { Model } from "./core.ts"; export function seed(): Model { return { count: 0 }; } export const viewUnbound = ["count"] as const; `, }, }, ]; const completeLangTier2Cases: Case[] = [ { name: "arrays of byte buffers follow array ownership, not the bytes legacy branch", src: ` export function concatAll(parts: readonly Uint8Array[]): Uint8Array { let total = 0; for (const p of parts) total += p.length; const out = new Uint8Array(total); let off = 0; for (const p of parts) { out.set(p, off); off += p.length; } return out; } export function join(a: Uint8Array, b: Uint8Array): Uint8Array { const parts: Uint8Array[] = []; parts.push(a); parts.push(b); return concatAll(parts); } `, }, { name: "a shared array of byte buffers still teaches ownership on push", gate: "NS1001", src: ` export function collect(parts: Uint8Array[], extra: Uint8Array): number { parts.push(extra); return parts.length; } `, }, { name: "bare module-function references inline as array callbacks", src: ` function double(n: number): number { return n * 2; } function isPositive(n: number): boolean { return n > 0; } function add(a: number, b: number): number { return a + b; } function byAscending(a: number, b: number): number { return a - b; } export function f(xs: readonly number[]): number { return xs.map(double).filter(isPositive).toSorted(byAscending).reduce(add, 0); } `, }, { name: "a bare reference to a hoisted function-expression helper is a callback too", src: ` export function f(xs: readonly number[]): readonly number[] { const scale = function (x: number): number { return x * 3; }; return xs.map(scale); } `, }, ]; const dataClassCases: Case[] = [ { name: "R19b: static methods and static readonly consts lower to module-level declarations", src: ` import { asciiBytes } from "@native-sdk/core"; export class Task { id: number; done: boolean = false; static readonly LIMIT = 9; static readonly LABEL = asciiBytes("task"); constructor(id: number) { this.id = id; } static clampId(n: number): number { return n > Task.LIMIT ? Task.LIMIT : n; } static labelLength(): number { return Task.LABEL.length; } bump(): void { this.id += 1; } } export function f(n: number): number { const t = new Task(Task.clampId(n)); t.bump(); return t.id + Task.LIMIT + Task.labelLength(); } `, }, { name: "R19b: private and protected keywords erase (tsc enforces them at the type level)", src: ` export class Counter { private n: number = 0; protected step: number = 1; private raise(): void { this.n += this.step; } bump(): void { this.raise(); } value(): number { return this.n; } } export function f(): number { const c = new Counter(); c.bump(); c.bump(); return c.value(); } `, }, { name: "NS1010: a mutable static field is module state", gate: "NS1010", src: ` export class Config { static shared: number = 2; } export function f(): number { return 1; } `, }, { name: "NS1056: this inside a static member is taught toward the class name", gate: "NS1056", src: ` export class Config { static readonly K = 1; static bad(): number { return this.K; } } export function f(): number { return 1; } `, }, { name: "data class: fields, constructor, mutating and reading methods", src: ` export class Counter { count: number = 0; step: number; constructor(step: number) { this.step = step; } bump(): void { this.count += this.step; } value(): number { return this.count; } } export function f(): number { const c = new Counter(2); c.bump(); c.bump(); return c.value(); } `, }, { name: "data class: bytes and array fields, rebuild-style field assignment", src: ` import { asciiBytes } from "@native-sdk/core"; export class Log { title: Uint8Array; entries: readonly number[] = []; constructor(title: Uint8Array) { this.title = title; } add(n: number): void { this.entries = [...this.entries, n]; } total(): number { let sum = 0; for (const e of this.entries) sum += e; return sum; } } export function f(): number { const log = new Log(asciiBytes("run")); log.add(1.5); log.add(2); return log.total() + log.title.length; } `, }, { name: "class instances flow as record-shaped values between functions (read-only)", src: ` export class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } norm(): number { return this.x * this.x + this.y * this.y; } } function sumNorms(ps: readonly Point[]): number { let total = 0; for (const p of ps) total += p.norm(); return total; } export function f(): number { const ps: readonly Point[] = [new Point(1, 2), new Point(3, 4)]; return sumNorms(ps); } `, }, { name: "extends teaches inheritance", gate: "NS1055", src: ` class Base { n: number = 0; } export class Derived extends Base { m: number = 1; } export function f(): number { return 1; } `, }, { name: "accessors, statics, and #-privates teach the member surface", gate: "NS1056", src: ` export class Config { #secret: number = 1; static shared: number = 2; get doubled(): number { return 4; } } export function f(): number { return 1; } `, }, { name: "an unannotated class field teaches the annotation form", gate: "NS1056", src: ` export class Counter { n = 0; } export function f(): number { return 1; } `, }, { name: "`this` escaping as a value teaches", gate: "NS1056", src: ` export class Chain { n: number = 0; add(x: number): Chain { this.n += x; return this; } } export function f(): number { return 1; } `, }, { name: "generic classes teach the concrete-struct rule", gate: "NS1053", src: ` export class Box { v: T | null = null; } export function f(): number { return 1; } `, }, { name: "a mutating method on a parameter instance teaches ownership", gate: "NS1001", src: ` export class Counter { n: number = 0; bump(): void { this.n += 1; } } export function f(c: Counter): number { c.bump(); return c.n; } `, }, { name: "a mutating method after the instance escaped teaches NS1051", gate: "NS1051", src: ` export class Counter { n: number = 0; bump(): void { this.n += 1; } } function observe(c: Counter): number { return c.n; } export function f(): number { const c = new Counter(); const seen = observe(c); c.bump(); return seen; } `, }, { name: "instanceof on a class instance still teaches runtime type tests", gate: "NS1041", src: ` export class Counter { n: number = 0; } export function f(v: Counter | null): number { if (v instanceof Counter) return 1; return 0; } `, }, { name: "class instances in the Model tree teach the record form (flagged follow-up)", gate: "NS1056", src: ` export class Task { id: number; constructor(id: number) { this.id = id; } } export interface Model { readonly tasks: readonly Task[]; } export function initialModel(): Model { return { tasks: [] }; } `, }, { name: "records built FROM class data keep the Model record-shaped", src: ` export class Builder { count: number = 0; bump(): void { this.count += 1; } } export interface Model { readonly count: number; } export type Msg = | { readonly kind: "recount"; readonly upTo: number } | { readonly kind: "noop" }; export function initialModel(): Model { return { count: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "recount": { const b = new Builder(); for (let i = 0; i < msg.upTo; i++) b.bump(); return { count: b.count }; } case "noop": return model; } } `, }, ]; const exceptionCases: Case[] = [ { name: "heterogeneous throws merge into the thrown union; catch narrows by kind", src: ` export interface ParseError { readonly kind: "parse"; readonly at: number; } export interface IoError { readonly kind: "io"; readonly code: number; readonly hard: boolean; } function go(n: number): number { if (n < 0) throw { kind: "parse", at: n } as ParseError; if (n > 100) throw { kind: "io", code: n, hard: n > 1000 } as IoError; return n * 2; } export function f(n: number): number { try { return go(n); } catch (e) { if (e.kind === "parse") return e.at - 1000; if (e.kind === "io") return e.hard ? -e.code : e.code; return -1; } } `, }, { name: "a declared union whose arms equal the thrown set carries the slot (as stays legal)", src: ` export interface ParseError { readonly kind: "parse"; readonly at: number; } export type AppError = { readonly kind: "parse"; readonly at: number } | { readonly kind: "empty" }; function go(n: number): number { if (n < 0) throw { kind: "parse", at: n } as ParseError; if (n === 0) throw { kind: "empty" } as AppError; return n; } export function f(n: number): number { try { return go(n); } catch (e) { const err = e as AppError; if (err.kind === "parse") return err.at; return -2; } } `, }, { name: "a member union's value rethrows through the thrown union (re-tagged arm by arm)", src: ` export type Low = { readonly kind: "under"; readonly by: number } | { readonly kind: "zero" }; export interface High { readonly kind: "over"; readonly by: number; readonly hard: boolean; } function check(n: number): number { if (n < 0) { const e: Low = n === -1 ? { kind: "zero" } : { kind: "under", by: n }; throw e; } if (n > 10) throw { kind: "over", by: n - 10, hard: n > 100 } as High; return n; } export function f(n: number): number { try { return check(n); } catch (e) { switch (e.kind) { case "under": return e.by - 100; case "zero": return -1; case "over": return e.hard ? e.by + 1000 : e.by; default: return -999; } } } `, }, { name: "single-shape catch reads its fields directly, no as ceremony", src: ` export interface Bad { readonly kind: "bad"; readonly at: number; } function go(n: number): number { if (n < 0) throw { kind: "bad", at: n } as Bad; return n; } export function f(n: number): number { try { return go(n); } catch (e) { return e.at; } } `, }, { name: "NS1057: a shape without a kind tag cannot join a heterogeneous thrown set", gate: "NS1057", src: ` export interface ParseError { readonly kind: "parse"; readonly at: number; } export function f(n: number): number { if (n < 0) throw { kind: "parse", at: n } as ParseError; if (n > 100) throw n; return n; } `, }, { name: "NS1057: two thrown shapes sharing a kind with different payloads are ambiguous", gate: "NS1057", src: ` export interface AErr { readonly kind: "boom"; readonly at: number; } export interface BErr { readonly kind: "boom"; readonly code: boolean; } export function f(n: number): number { if (n < 0) throw { kind: "boom", at: n } as AErr; if (n > 100) throw { kind: "boom", code: true } as BErr; return n; } `, }, { name: "NS1057: asserting one member shape in a heterogeneous core is taught toward kind tests", gate: "NS1057", src: ` export interface ParseError { readonly kind: "parse"; readonly at: number; } export interface IoError { readonly kind: "io"; readonly code: number; } function go(n: number): number { if (n < 0) throw { kind: "parse", at: n } as ParseError; if (n > 100) throw { kind: "io", code: n } as IoError; return n; } export function f(n: number): number { try { return go(n); } catch (e) { const err = e as ParseError; return err.at; } } `, }, { name: "NS1057: the catch binding escaping into a call is taught toward narrowing", gate: "NS1057", src: ` export interface Bad { readonly kind: "bad"; readonly at: number; } function width(x: Bad): number { return x.at; } function go(n: number): number { if (n < 0) throw { kind: "bad", at: n } as Bad; return n; } export function f(n: number): number { try { return go(n); } catch (e) { return width(e); } } `, }, { name: "try/catch/finally: parser throws a tagged error, caller narrows it", src: ` export type ParseError = | { readonly kind: "bad_digit"; readonly at: number } | { readonly kind: "empty" }; function parseDigits(bytes: Uint8Array): number { if (bytes.length === 0) throw { kind: "empty" } as ParseError; let n = 0; for (let i = 0; i < bytes.length; i++) { const b = bytes[i]; if (b < 48 || b > 57) throw { kind: "bad_digit", at: i } as ParseError; n = n * 10 + (b - 48); } return n; } export function safeParse(bytes: Uint8Array): number { try { return parseDigits(bytes); } catch (e) { const err = e as ParseError; if (err.kind === "bad_digit") return -err.at - 1; return -1000; } } `, }, { name: "throw inside a map callback unwinds out of the lowered loop", src: ` export type Bad = { readonly kind: "bad"; readonly at: number } | { readonly kind: "none" }; export function firstBad(xs: readonly number[]): number { try { const doubled = xs.map((x, i) => { if (x < 0) throw { kind: "bad", at: i } as Bad; return x * 2; }); return doubled.length; } catch (e) { const err = e as Bad; return err.kind === "bad" ? -err.at - 1 : -99; } } `, }, { name: "rethrow and nested try; finally runs on both paths", src: ` export type Fail = { readonly kind: "inner"; readonly n: number } | { readonly kind: "outer"; readonly n: number }; export function f(x: number): number { let log = 0; try { try { if (x > 0) throw { kind: "inner", n: x } as Fail; log += 1; } catch (e) { const err = e as Fail; if (err.kind === "inner") { if (err.n > 5) throw { kind: "outer", n: err.n } as Fail; } throw e; } finally { log += 10; } } catch (e) { const err = e as Fail; const tag = err.kind === "outer" ? 2 : 1; return log * 100 + tag; } return log; } `, }, { name: "an uncaught throw at an exported boundary compiles to a defined panic", src: ` export type Boom = { readonly kind: "boom" } | { readonly kind: "other" }; export function mustBePositive(n: number): number { if (n <= 0) throw { kind: "boom" } as Boom; return n; } `, }, { name: "throw mid-mutation of an owned array: prior pushes persist into the catch", src: ` export type Halt = { readonly kind: "halt" } | { readonly kind: "never" }; export function f(stop: number): number { const xs: number[] = []; try { xs.push(1); xs.push(2); if (xs.length >= stop) throw { kind: "halt" } as Halt; xs.push(3); } catch { return xs.length; } return xs.length * 10; } `, }, { name: "class methods can throw; the constructor can too", src: ` export type RangeError2 = { readonly kind: "range"; readonly v: number } | { readonly kind: "none" }; export class Gauge { v: number; constructor(v: number) { if (v < 0) throw { kind: "range", v } as RangeError2; this.v = v; } add(d: number): void { if (this.v + d > 100) throw { kind: "range", v: this.v + d } as RangeError2; this.v += d; } } export function f(start: number, d: number): number { try { const g = new Gauge(start); g.add(d); return g.v; } catch (e) { const err = e as RangeError2; return err.kind === "range" ? -err.v : -1; } } `, }, { name: "two different thrown shapes teach the one-shape rule", gate: "NS1057", src: ` export function f(x: number): number { if (x < 0) throw 1; if (x > 10) throw true; return x; } `, }, { name: "a directly-used catch binding teaches the single-narrowing rule", gate: "NS1057", src: ` export function f(): number { try { return 1; } catch (e) { return e === null ? 0 : 2; } } `, }, { name: "`throw new Error` teaches the subset-value rule", gate: "NS1057", src: `export function f(): number { throw new Error("x"); }`, }, { name: "`return` inside finally teaches no-unsafe-finally", gate: "NS1058", src: `export function f(): number { try { return 1; } finally { return 0; } }`, }, ]; // Shapes that first failed in RELEASE-mode app builds (wave-2 eval trials): // Debug-lane-only compilation let them escape, which is why the compile test // below runs the driver in both Debug and ReleaseFast. const releaseModeCases: Case[] = [ { name: "annotated enum local from a runtime ternary (pomodoro phase flip)", src: ` export type Phase = "focus" | "rest"; export interface Model { readonly phase: Phase; readonly remaining: number; readonly completed: number; } export type Msg = { readonly kind: "tick" } | { readonly kind: "reset" }; export function initialModel(): Model { return { phase: "focus", remaining: 1500, completed: 0 }; } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "tick": { const nextPhase: Phase = model.phase === "focus" ? "rest" : "focus"; const nextDuration = nextPhase === "focus" ? 1500 : 300; const nextCompleted = model.phase === "focus" ? model.completed + 1 : model.completed; return { phase: nextPhase, remaining: nextDuration, completed: nextCompleted }; } case "reset": return { ...model, phase: "focus" }; } } `, }, { name: "reassigned enum local anchors its enum type", src: ` export type Phase = "focus" | "rest"; export function flip(count: number): Phase { let phase: Phase = "focus"; if (count > 1) phase = "rest"; return phase; } `, }, { name: "bytes parameter written through set() and indexed stores (notes serializer)", src: ` function writeChunk(out: Uint8Array, offset: number, chunk: Uint8Array): number { out.set(chunk, offset); out[offset] = 65; return offset + chunk.length; } export function pack(chunks: readonly Uint8Array[]): Uint8Array { let total = 0; for (const c of chunks) total += c.length; const out = new Uint8Array(total); let offset = 0; for (const c of chunks) offset = writeChunk(out, offset, c); return out; } `, }, ]; // The byte-text method surface (R11t): the everyday string methods on core // bytes, exercised through the type boundaries the per-method matrix // (grammar_matrix.test.ts) does not cover — model integration, aliases, // optional receivers, result classes feeding integer flows, split // ownership — plus the taught edges that need FLOW (not literal) fixtures. const textMethodCases: Case[] = [ { name: "case-mapped search filter through a Bytes alias in the update path", src: ` import { asciiBytes } from "@native-sdk/core"; export type Bytes = Uint8Array; export interface Item { readonly id: number; readonly title: Bytes; } export interface Model { readonly items: readonly Item[]; readonly query: Bytes; } export type Msg = | { readonly kind: "set_query"; readonly text: Bytes } | { readonly kind: "clear" }; export function initialModel(): Model { return { items: [{ id: 1, title: asciiBytes("Alpha") }], query: new Uint8Array(0) }; } export function visible(model: Model): readonly Item[] { const q = model.query.toLowerCase(); return model.items.filter((it) => it.title.toLowerCase().includes(q)); } export function update(model: Model, msg: Msg): Model { switch (msg.kind) { case "set_query": return { ...model, query: msg.text.trim() }; case "clear": return { ...model, query: new Uint8Array(0) }; } } `, }, { name: "indexOf result guards a subarray bound (integer-classed offset)", src: ` export function afterColon(line: Uint8Array, sep: Uint8Array): Uint8Array { const at = line.indexOf(sep); if (at === -1) return line; return line.subarray(at + sep.length); } export function tail(line: Uint8Array): number { const last = line.lastIndexOf(32); return last === -1 ? line.length : last; } `, }, { name: "split parts are locally owned (push after split) and iterate", src: ` import { asciiBytes } from "@native-sdk/core"; export function fields(row: Uint8Array): number { const parts = row.split(asciiBytes(",")); parts.push(asciiBytes("total")); let bytes = 0; for (const p of parts) bytes += p.trim().length; return bytes + parts.length; } `, }, { name: "at() folds with ?? and tests === undefined (the one-empty rule)", src: ` export function lastByte(s: Uint8Array): number { const b = s.at(-1); if (b === undefined) return -1; return b; } export function firstOrZero(s: Uint8Array): number { return s.at(0) ?? 0; } `, }, { name: "optional-chained text methods over a nullable receiver", src: ` export interface Model { readonly note: Uint8Array | null; } export function noteLen(model: Model): number { return (model.note?.trim() ?? new Uint8Array(0)).length; } export function shout(model: Model): Uint8Array { return model.note?.toUpperCase() ?? new Uint8Array(0); } `, }, { name: "pad targets and repeat counts ride integer flows into the helpers", src: ` import { asciiBytes } from "@native-sdk/core"; export function gauge(width: number, used: number): Uint8Array { const bar = asciiBytes("#").repeat(used); return bar.padEnd(width, asciiBytes(".")); } export function label(name: Uint8Array, col: number): Uint8Array { return name.padStart(col); } `, }, { name: "dispatch by argument type: byte membership vs substring on one receiver", src: ` export function hasBoth(s: Uint8Array, sub: Uint8Array, byte: number): boolean { return s.includes(sub) && s.includes(byte); } `, }, { name: "repeat count fed by a float FLOW (not a literal) is the taught slot conflict", gate: "NS1016", src: ` export function f(s: Uint8Array, x: number): Uint8Array { const n = x / 2; return s.repeat(n); } `, }, { name: "padStart target fed by a fractional literal is the taught slot conflict", gate: "NS1016", src: ` export function f(s: Uint8Array): Uint8Array { return s.padStart(4.5); } `, }, { name: "split parts cannot be pushed after the array escapes", gate: "NS1051", src: ` import { asciiBytes } from "@native-sdk/core"; function count(xs: readonly Uint8Array[]): number { return xs.length; } export function f(row: Uint8Array, sink: Uint8Array[][]): number { const parts = row.split(asciiBytes(",")); sink.push(parts); parts.push(asciiBytes("late")); return count(parts); } `, }, ]; const corpus: Case[] = [ ...textMethodCases, ...releaseModeCases, ...completeLangTier2Cases, ...dataClassCases, ...exceptionCases, ...enumCases, ...numberCases, ...structuralCases, ...cmdCases, ...cmdV2Cases, ...namedOpCases, ...contractCases, ...bindingSurfaceCases, ...stackedUnionCases, ...iterationCases, ...builderSortCases, ...localMutationCases, ...mathAndTableCases, ...arrayStaticCases, ...modelTierCases, ...streamingCases, ...grammarCases, ]; test("corpus: gated cases teach at check time, emit cases transpile clean", () => { for (const c of corpus) { const result = transpile(c.src); assert.equal(result.typeErrors.length, 0, `${c.name}: tsc errors\n${result.typeErrors.join("\n")}`); if (c.gate) { assert.equal(result.ok, false, `${c.name}: expected ${c.gate}, but transpile succeeded`); const ids = result.diagnostics.map((d) => d.id); assert.ok(ids.includes(c.gate), `${c.name}: expected ${c.gate}, got ${ids.join(", ") || "none"}`); } else { const details = result.diagnostics.map((d) => `${d.id} ${d.message}`).join("\n"); assert.equal(result.ok, true, `${c.name}: transpile failed\n${details}`); } } }); test("multi-file corpus: gated cases teach, emit cases transpile clean", () => { for (const c of multiFileCases) { const result = transpileFiles(c.files); if (c.gate) { assert.equal(result.ok, false, `${c.name}: expected ${c.gate}, but transpile succeeded`); const ids = result.diagnostics.map((d) => d.id); assert.ok(ids.includes(c.gate), `${c.name}: expected ${c.gate}, got ${ids.join(", ") || "none"}`); } else { assert.equal(result.typeErrors.length, 0, `${c.name}: tsc errors\n${result.typeErrors.join("\n")}`); const details = result.diagnostics.map((d) => `${d.id} ${d.message}`).join("\n"); assert.equal(result.ok, true, `${c.name}: transpile failed\n${details}`); // The staleness contract: every module of the graph is an input. assert.ok(result.inputs.length >= Object.keys(c.files).length, `${c.name}: inputs missing (${result.inputs.length})`); } } }); test("private cross-file collisions take a per-module prefix in the emitted Zig", () => { const c = multiFileCases.find((x) => x.name.includes("PRIVATE helpers"))!; const result = transpileFiles(c.files); assert.equal(result.ok, true); // One `scale` keeps its name (first claim); the other gets `b_scale`. assert.ok(result.zig!.includes("fn scale("), "first claimer keeps its spelling"); assert.ok(result.zig!.includes("fn b_scale("), `the collider takes the module prefix:\n${result.zig}`); assert.ok(result.zig!.includes("b_scale(n)"), "references land on the prefixed name"); }); test("corpus: emitted Zig always compiles", { skip: !hasZig, timeout: 600_000 }, () => { const work = fs.mkdtempSync(path.join(os.tmpdir(), "native-core-conformance-")); try { fs.copyFileSync(path.join(pkg, "rt", "rt.zig"), path.join(work, "rt.zig")); const imports: string[] = []; corpus.forEach((c, i) => { if (c.gate) return; const result = transpile(c.src); assert.equal(result.ok, true, `${c.name}: transpile failed before the zig step`); const file = `case_${String(i).padStart(2, "0")}.zig`; fs.writeFileSync(path.join(work, file), result.zig!); imports.push(` // ${c.name}\n refAllDecls(@import("${file}"));`); }); multiFileCases.forEach((c, i) => { if (c.gate) return; const result = transpileFiles(c.files); assert.equal(result.ok, true, `${c.name}: transpile failed before the zig step`); const file = `multi_${String(i).padStart(2, "0")}.zig`; fs.writeFileSync(path.join(work, file), result.zig!); imports.push(` // ${c.name}\n refAllDecls(@import("${file}"));`); }); const driver = [ `// Generated driver: reference every public decl of every emitted core so`, `// the compiler semantically analyzes all of them (nothing runs).`, `const refAllDecls = @import("std").testing.refAllDecls;`, ``, `test {`, ...imports, `}`, ``, ].join("\n"); fs.writeFileSync(path.join(work, "driver.zig"), driver); // Both optimize modes, because they analyze differently: the wave-2 // release-only miscompiles (comptime-only enum literals under runtime // control flow; @memcpy into a `[]const u8` parameter) surfaced only // when an app's ReleaseFast build was the first release-mode analysis // the emitted core ever got. for (const mode of [[], ["-OReleaseFast"]] as const) { try { execFileSync("zig", ["test", ...mode, "driver.zig"], { cwd: work, encoding: "utf8", stdio: "pipe" }); } catch (e) { const err = e as { stderr?: string; stdout?: string }; assert.fail(`emitted Zig failed to compile (${mode[0] ?? "Debug"}):\n${err.stderr ?? ""}${err.stdout ?? ""}`); } } } finally { fs.rmSync(work, { recursive: true, force: true }); } }); test("NS1028: Cmd.persist still compiles but teaches the writeFile path as a warning", () => { const result = transpile(` import { Cmd } from "@native-sdk/core"; export interface Model { readonly count: number; } export type Msg = { readonly kind: "add" } | { readonly kind: "noop" }; export function initialModel(): Model { return { count: 0 }; } export function update(model: Model, msg: Msg): Model | [Model, Cmd] { switch (msg.kind) { case "add": return [{ count: model.count + 1 }, Cmd.persist()]; case "noop": return model; } } `); // The warning never gates: the op compiles, emits its wire record, and // the notice rides the separate channel. assert.equal(result.ok, true, "persist must keep compiling"); assert.equal(result.diagnostics.length, 0); const w = result.warnings.find((d) => d.id === "NS1028"); assert.ok(w, "reports NS1028 as a warning"); assert.ok(w.message.includes("writeFile"), "points at the writeFile path"); assert.ok(result.zig!.includes("rt.cmdPersist()"), "wire support stays"); }); test("NS1016 speaks in rule, fix, and why", () => { const result = transpile(` export function read(bytes: Uint8Array): number { let i = 0; i = 1.5; return bytes[i]; } `); assert.equal(result.ok, false); const d = result.diagnostics.find((x) => x.id === "NS1016"); assert.ok(d, "reports NS1016"); assert.ok(d.message.includes("must be an integer"), "names the conflict"); assert.ok(d.message.toLowerCase().includes("machine type"), "says why"); });