Files
2026-07-13 12:29:49 +08:00

5195 lines
162 KiB
TypeScript

// 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 : <uses x>` 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) <exit>` lowers to `(if (c) f else g) orelse <exit>`
// — 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<Msg>] {
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<Msg>] {
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<Msg> {
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg> {
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<Msg>] {
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<Msg>] {
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<Msg>] {
switch (msg.kind) {
case "load": return [model, Cmd.request("store.read", model.data, {
ok: ((body: Uint8Array) => ({ kind: "loaded", body })) as unknown as BytesKind<Msg>,
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<Msg>] {
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<Msg>] {
switch (msg.kind) {
case "load": return [model, Cmd.request("store.read", model.data, {
ok: "tick" as BytesKind<Msg>,
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<Msg>("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<Msg> {
const stored = Sub.timer<Msg>("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<Msg> {
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<Msg> {
return Sub.timer("load", 100, "loaded" as TimestampKind<Msg>);
}
`,
},
];
// 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<Msg>] {
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<Msg>] {
switch (msg.kind) {
case "go": return [model, Cmd.fetch({ url: asciiBytes("https://a.test") }, { ok: "loaded" as FetchedKind<Msg>, 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<Msg>] {
switch (msg.kind) {
case "go": return [model, Cmd.writeFile(asciiBytes("a.bin"), model.data, { ok: "loaded" as EmptyKind<Msg>, 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<Msg>] {
switch (msg.kind) {
case "go": return [model, Cmd.delay("d", 100, "loaded" as TimestampKind<Msg>)];
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<T>(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<T>(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 = <T>(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<Msg>] {
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<Msg>] {
switch (msg.kind) {
case "go": return [model, Cmd.spawn([asciiBytes("/bin/ps")], { line: "line", exit: "line" as TimestampKind<Msg>, 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<Msg>] {
switch (msg.kind) {
case "go": return [model, Cmd.spawn([asciiBytes("/bin/ps")], { collect: true, exit: "done" as FetchedKind<Msg>, 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<Msg>] {
switch (msg.kind) {
case "go": return [model, Cmd.spawn([asciiBytes("/bin/ps")], { collect: true, line: "line", exit: "sampled", err: "failed" } as SpawnCollectRoute<Msg>)];
${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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg>] {
switch (msg.kind) {
case "go": return [model, Cmd.audioPlay("player", { path: asciiBytes("a.mp3") }, { event: "audio_evt" as AudioEventKind<Msg> })];
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<Msg>] {
switch (msg.kind) {
case "go": return [model, Cmd.audioPlay("player", { path: asciiBytes("a.mp3") }, { event: "sampled" as AudioEventKind<Msg> })];
${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<Msg>] {
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<Msg>] {
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<Msg>] {
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<Msg>] {
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<string, string>;
}
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<T> { 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<Msg>] {
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");
});