Release-candidate notes — 84d3c80 (v1 foundation, N40–N48)
Frozen evidence for one tested commit. This file records what was verified at
84d3c801f4b14056297bc6ceadc5f6441873c594 and is not updated as the project moves. Current
implementation truth is ../capability-matrix.md; what is not done is
../limitations.md.
Nothing has been tagged, pushed or published. This is a candidate. Making it a release is a person’s decision, and the procedure for it is at the end of this file.
What this candidate is
Nazm at the end of N48: one checked program lowered once to Core IR (N39) and once to MIR (N40),
interpreted from Core IR and compiled from MIR by either of two backends — LLVM text through clang
(the default) or Cranelift (N41) — with C functions callable through a declared, capability-gated
foreign boundary (N42), a runtime whose every symbol and global is inventoried (N43), a stated
scheduler contract (N44), a standard library of seven modules (N45), exact path dependencies with
a lock file and reproducible executables (N46), restriction profiles (N47), and nazm inspect,
DWARF for --debug builds and --timings (N48).
Identities
| Commit | 84d3c801f4b14056297bc6ceadc5f6441873c594 |
| Toolchain | rustc 1.98.1, pinned in rust-toolchain.toml |
| Semantic epoch | 11 (crates/nazm-cache/src/identity.rs) |
| Interface schema | nazm.interface/7 |
| Runtime ABI revision | 2 (crates/nazm-lir/src/runtime/mod.rs) |
| Cranelift | 0.136.1, pinned exactly (crates/nazm-codegen-clif/Cargo.toml) |
| Package manifest / lock | nazm.package/1 / nazm.lock/1 |
| Machine documents | nazm.inspect/1, nazm.timings/1, nazm.profile-report/1, nazm.mir/1 (internal, unstable) |
| Restriction profiles | general (no rules), embedded (no-io, no-spawn), critical (declared-effects, no-spawn, no-foreign, locked-build), cyber (declared-effects, no-foreign, locked-build) |
Supported platform
| Verified targets | aarch64-apple-darwin (the host, Apple clang) and aarch64-unknown-linux-gnu (inside the contained runner, Debian clang 19). The emitter’s own note: “verified on aarch64-apple-darwin with Apple clang; other targets are unverified rather than unsupported” |
| External at build time | clang (LLVM backend: compile and link; Cranelift backend: link and the runtime); dsymutil on macOS for --debug |
| External at run time | libc and pthreads |
The gate, and what it found
Contained (Docker, offline, nazm-contained:1.98.1), on 2026-10-01. The
gate ran across the seven fix commits it caused, each stage at the commit named; the commits after
74727bb change tests and the mutation catalogue only.
| Stage | Commit | Result |
|---|---|---|
Workspace suite (p4w2t4 tests) | a8a7b3f | passed, 412 s: 2,021 tests passed, 0 failed, 29 ignored, 136 suites |
Lifecycle (xtask --test lifecycle --ignored) | 74727bb | 19 passed, 182 s |
Self-hosting (contained selfhost) | 74727bb | 38 passed, 69 s |
| Bootstrap C1 → C2 → C3 | 74727bb | passed, 39 s; executables byte-identical once the linker UUID is removed |
| Compiler benchmark | 74727bb | measured; see Performance |
xtask check and the docs test | 84d3c80 | passed |
| Mutation, full catalogue | composed, below | 808 of 808 caught |
What the gate found, every item fixed before it closed (commit, then what):
180b541— three mutants of macOS-only code (ZERO_AR_DATE, the link name, the.dSYMstep) could not be killed on Linux, where their effects do not exist; each decision is now a function a unit test reads on every host.1b8903f— the Cranelift agreement tests ran programs with no deadline, so a deadlocking mutant was a 1,200 s timeout (no verdict); every program they run is now killed and named after 30 s.74727bb— a language-service defect: a standard-library definition, reference or call-hierarchy item was reported at<cwd>/@std/…, a path that does not exist (N45, exposed by N48’sexamples/stdlib/words.nz); a standard module is now named like the prelude. Also: three reserved-namespace checks of which the last made the first two unreachable are one rule with a mutant per namespace, and a mutant that had not built since N37 is repaired.41666b1,a8a7b3f— the five-thousand-task test was refused a thread in the container: the 512 MiB address-space ceiling every compiled test program runs under on Linux did not budget glibc’s 64 MiB malloc arena per thread. The scheduler tests run under the container’s 4 GiB; the limitation that tasks alive at once are bounded by the host’s thread limit is documented.984ceef,84d3c80— two mutants whose effect killed a whole test binary (no verdict) were given declared killers that observe it from outside, each verified contained.
Results
cargo test --workspace, run through cargo xtask contained on Linux at a8a7b3f (the
workspace stage; 84d3c80 differs from it in the mutation catalogue alone):
2021 passed, 0 failed, 29 ignored. Across 136 suites.
Added 2026-10-01, in N49, because crates/nazm-cli/tests/counts.rs requires every frozen
report to state its total and a table that sums to it; the numbers are the gate’s, grouped
by listing the same commit’s tests (cargo test --workspace -- --list, 2,050 listed, 29
ignored), and nothing else in this file changed.
| count | what it establishes | |
|---|---|---|
Other integration suites (nazm-cli/tests/*.rs beyond those below, nazm-core, nazm-mcp, nazm-repo, the benches) | 1020 | each milestone’s end-to-end behaviour: modules, packages, profiles, FFI, the runtime, the scheduler, the standard library, the cache, the debugger surfaces and the machine interfaces |
Language service (nazm-service) | 257 | references, rename, completion, hierarchy, context packets and the rest, against the checker’s own answers |
| Unit tests in the crates | 204 | each crate’s local invariants |
Native end-to-end (nazm-cli/tests/build.rs) | 135 | every case compiled at -O0 and -O2 and compared with the interpreter |
Harness (xtask) | 127 | the gates, the mutation harness and the containment rules themselves |
Language semantics (nazm-core/tests/language.rs) | 116 | each rule in docs/spec.md a refactor could quietly reverse |
Syntax, CST, grammar and formatter (nazm-syntax) | 72 | the lossless tree, the grammar against the parser, and the formatter’s preservation laws |
Self-hosting differentials (nazm-cli/tests/selfhost.rs) | 38 | the Nazm-written compiler against the reference |
MIR (nazm-cli/tests/mir.rs) | 35 | the validator’s laws and MIR against Core IR |
Concurrency, native (nazm-cli/tests/concurrent.rs) | 17 | scopes, tasks and channels compiled, with deadlines |
Mutation catalogue accounting
Every one of the catalogue’s 808 entries has a verdict, and every verdict is caught:
| catalogue total | 808 |
| accounted | 808 |
| caught | 808 — 626 by a declared killer, 179 by the owning profile’s tests, 3 by the workspace suite |
| survived | 0 |
| unusable | 0 |
| mutant crash | 0 |
| timed out | 0 |
| not injected | 0 |
| runner error | 0 |
| unexecuted | 0 |
Composed, and how. No single campaign covers all 808, because the gate changed the tree as it
went. The latest verdict per mutant is taken: 574 at 1b8903f (decided by their own killers,
in files and through tests no later commit touches), 46 at 74727bb (every mutant in the files
that commit changed, and every one its changed tests kill), 182 at a8a7b3f (the suite tier,
which no earlier commit could run because its suite was not green, and the scheduler’s mutants),
and 6 at 84d3c80 (the mutants whose killers were declared or reused, verified in one
session: pristine passes, mutant fails, restored passes). Across every resumed session no verdict
was ever reclassified except one runner error re-run to caught. The campaign journals are
retained with the gate’s logs; nothing was counted from a log line that a journal does not hold.
Performance at this candidate
../performance.md, The v1 baseline — N48: the contained figures at this
candidate, which replace the pre-N1 bench/baseline-linux-aarch64.json as the reference. Against
N39’s gate run: interpreter and checker within 0.3–6 %; the native -O0 build of the self-hosted
compiler +17 % since N40, attributed by an interleaved host A/B to the MIR emitter’s slot-per-local
LLVM text (13,836 allocas against 3,275), with no change to any program’s behaviour.
Known limitations
../limitations.md, by area. The ones a user meets first: one OS thread per
task, so the tasks alive at once are bounded by the host’s thread limit; channels carry Int
only; no package registry or version ranges; the foreign boundary passes scalars only; --debug
gives function and statement positions, no variables, and only through the LLVM backend; a live
debugger session was not exercised in this environment (static lldb queries were); verified on
two aarch64 targets only.
The human release procedure
Every step is a person’s, in this order, from a clean checkout of exactly this commit. Stop at the first step that does not pass.
- Check out the commit.
git checkout 84d3c801f4b14056297bc6ceadc5f6441873c594and confirmgit status --porcelainprints nothing. - Build the runner image (network needed here and nowhere after):
docker build -f docker/contained.Dockerfile -t nazm-contained:1.98.1 . - Run the gates, contained and offline, each of which must exit 0:
cargo xtask contained --profile p4w2t4 testscargo xtask contained --profile p1 run "cd /src && cargo test -p xtask --test lifecycle -- --ignored --test-threads 1"cargo xtask contained selfhostcargo xtask contained bootstrapcargo xtask contained bench(compare against this file’s numbers, not the stale baseline)cargo xtask checkandcargo test -p nazm-cli --test docs- the mutation campaign:
cargo xtask contained --profile p4t4 mutate --strategy targeted --verify-killers, resumed with--resumeuntil it completes; it must report 0 survived and no mutant without a verdict.
- Assemble the local candidate:
cargo xtask contained run 'sh scripts/release-candidate.sh'. It runs every gate again, builds the artefact undertarget/, writes a manifest of digests and verifies the artefact against it. It tags, pushes and uploads nothing. - Re-digest independently on the host: extract the artefact and compare every file’s SHA-256 with the manifest; the counts must match both ways.
- Decide. Only then, and only by a person: tag (
git tag -a v1.0.0-rc.1 84d3c80 -m "…"), push the branch and the tag, and publish the artefact with this file beside it. None of this has been done.