Grasm v1.0.0 Get started

More

Every goal, measured.

MASTERPLAN.md §2.3 sets ten measurable goals and §19.3 adds an eleventh; two of them split in two, so the scorecard has 13 rows. 9 are met, 2 are narrowly over, and 2 cannot be measured at all without users. scripts/northstar.sh takes the readings it can take and prints a scorecard rather than failing on a miss — a gate that is red on purpose is a gate people learn to ignore — but it does fail when a reading cannot be taken, which is how a metric quietly stops being collected.

Ship a real service
G1 · ≤ 1 week, Go/TS dev
no users
Geomean vs Rust
G2 · ≥ 0.95×
0.965×
Frontend throughput
G3 · ≥ 500k LOC/s
535–547k
Edit to diagnostic
G3, at this repo's scale · ≤ 50 ms
p95 40 ms
Safe-subset guarantees
G4 · 100%
1 gap, permanent
Hello-world binary
G5 · ≤ 300 KB
85.7 KB
Tasks per node
G6, task count only · ≥ 1M
1,000,000
Capability-sandboxed deps
G7 · 100%
refused
Failure → deterministic replay
G8, the % is unmeasured · ≥ 99%
28 builtins
C ABI import overhead
G9 · zero-cost
zero-cost
Adoption
G10 · ≥ 500 companies
zero
Tokens vs Python
G11 · ≤ 1.00×
1.04×
Tokens vs Go
G11 · ≤ 0.60×
0.61×

Three of those rows carry a qualification that the bar cannot show, and they are the three worth reading twice. G3's 50 ms is met at this repository's scale — p50 21 ms, p95 40 ms on its largest program — and the plan frames that goal at a million lines, which a whole-program re-check will never reach; that needs the query engine nobody has built. G6 is met for the task count and the uncolored half is still open: tasks refuse every effect. G8's mechanism is met on all four engines, and the ≥99% figure is unmeasurable because nobody has run a Grasm program in production.

The gates, and what each one would catch

Judged by exit code alone, 113 of them. These are the figures from the last recorded run on this machine:

GateScopeResult
difftest / corpus511 programs0 differences across the engines
leakcheck226 programs1 leaking — spec/conformance/E-VALUE-SEMANTICS.gr holds 16 allocations at exit, so this gate is red. The ratchet is at zero, which is why one leak fails it. See docs/known-issues.md.
usecheck, the poison build197 programs0 differences
crosstest x86_64 under Rosetta224 programs195 pass, 0 real failures, 60 declined — retaken on a quiet machine on 15 October 2026: all 511, nothing declined
clippy --all-targetsnative and wasm320
unit testsevery crate609 pass
replaytestevery journalled builtineach one refuses under an empty journal
fuzzers15 generatorsclean
conformance258 programsone per normative clause

leakcheck and usecheck are the two no other check replaces: a leaking program produces exactly the right output, and a premature free makes a value less live rather than more, so neither shows up in a diff of what was printed.

One caveat on that table, stated rather than buried. The crosstest figure was taken on a machine at load 38 rising to 134, where two parallel tests differed and then agreed on re-run, 3 of 3 and 2 of 2. They are recorded as load artefacts because that is what they are, and the figure wants taking again on a quiet machine before anyone calls it green.

The three that moved, and what moved them

G5: 351.1 KB → 85.7 KB

About 135 KB of that binary was Rust's own backtrace symbolizer — gimli, addr2line, rustc_demangle — reached from std's default panic hook, and nothing in a hello-world ever called it. All four crates a compiled program links are now no_std, with a new grasm_sys crate underneath them for the operating system and grasm_rt_abi supplying the allocator and the panic handler. nm shows zero symbolizer symbols. Nightly was not needed.

The conversion found nine defects, and the gates would have caught none of them — they are all below the level the corpus exercises. Five of the nine: open and fcntl were declared non-variadic, and arm64 passes variadic arguments on the stack, so the mode argument was garbage; RwLock::write released a mutex rather than the lock it took, so a second writer hung; an exec failure was indistinguishable from exit 127, which the specification requires to be distinguishable; AF_INET6 was 30 on Linux, where it is 10; and thread::scope let its reference escape, which needed somebody to write the line that escapes before anything noticed.

A figure in that story was wrong in public first. It was reported as 68.3 KB for several commits — the branch head was 85.7 KB. The difference is one 16 KB page of __TEXT quantisation around 1.9 KB of real code: on Mach-O a segment is 16 KB-aligned, so a kilobyte of code can move a file by seventeen. docs/binary-size.md bisects it to the commit.

G6: 40,000 tasks in 199 s → 1,000,000 in 22 s

The scheduler resumed every live task every round, so N tasks needed N rounds of N resumes — quadratic, and at that rate a million tasks is hours. The fix that looked obvious was built first and measured at nothing: a version per channel still wakes every blocked sender when the receiver takes one value. What worked is a wait queue per channel and per side, so a send wakes a receiver rather than another sender, and a round costs what is runnable.

That changed an observable rule, so the specification changed with it: [E-SCHEDULE] now wakes the longest-waiting sender or receiver instead of going round-robin. It is an experimental clause, and all 258 conformance programs produce identical output across the change. The interpreter stops near 285,000 tasks and is allowed to: an interpreter frame costs about 10 KB where a compiled one costs 30 bytes.

G2: the compiler did not change, the ruler did

This row used to read "4 of 7 programs at or above Rust", and that was an artefact. bench.sh was adding a constant 21 ms to every cell, and a constant added to every measurement compresses every ratio toward 1 — a 5 ms program and a 10 ms program read as 26 and 31, which is "about the same" if you squint. With the timer fixed, the geomean read 2.49× behind.

What closed it afterwards was real work, and the same 21 ms had been published in two other tables: a wrong measurement does not stay where it was made. It is 0.965× today, or 0.955× with the harness's own floor subtracted from both sides, with five of eight programs at or above parity. tree at 0.51× is what the geomean still carries: a box per node in tree-shaped data. Storing those inline was built, measured at 1.33× slower, and not kept. Every benchmark row, and the measurement rules each mistake bought →

What is still open

OpenWhat it would take
Tasks refuse every effect — G6's uncolored halfThe task count is met; the goal is not. A task that cannot do I/O is not the thing the goal asks for.
Sub-50 ms at a million lines — G3's other halfA query engine. What exists is a batch compiler with an object cache, re-checking the whole program on every keystroke, and at this repository's size that is fast enough to hide the problem.
G11's last 4% and 2%Priced before building: list repetition and a stepped range are what Python has and Grasm does not on the worst row. Not closable by adding library methods.
Linux has never been compiled hereAbout 2,100 lines of the operating-system layer are written for it and no target is installed on this machine. CI's ubuntu runner compiles it; a compile catches code that does not build, and does not catch a wrong constant — which is exactly how AF_INET6 survived.
No remote registryPath and local-registry dependencies work. Nothing fetches or publishes.
G1 and G10 need usersA week to ship a service, and 500 companies. Neither is a number this repository can produce by working harder on it.

How any of this is kept honest

All 101 findings are written down in ProjectGold/FINDINGS.md — including the ones that were the test harness's fault, the ones withdrawn as wrong, and the ones caught before they shipped. Every gate is verified by breaking the thing it guards and confirming it fails, because a gate nobody has broken is a gate nobody has tested. One of them had to be: replaytest was matching 0 of 39 builtins and exiting 0, for weeks, because its pattern expected a struct on one line. It now asserts its own count.

The bar for calling this finished is not on this page, and no number here moves it: zero known defects, every gate green, and two consecutive independent review rounds finding nothing new — each conducted by somebody who has seen only the language pack and not this repository's history. Those rounds have not run.