Status: CONTRACT FOR REVIEW, revision 2 (2026-09-16), rewritten on the stage-0.1 review's findings (docs/fcb-stage01-review-2026-09-16.md, "Kernellet-cost contract review"): the stale witness total, the wrong gate for transition-only comparators, the overstated marginal-subtraction guarantee, the CLOCK_MONOTONIC wording, and the unproven iret claim. No code exists for this campaign and none is written until Codex has accepted this revision. Nothing here is a number. This file rules nothing; it says what the campaign would measure, on what, under which two gates, which fixed costs the marginal method is hypothesised to cancel and how that hypothesis is tested, and what would falsify it.
The row the scheduler-outcome benchmark calls computedriven-policy (fcb/cd/) is the cd-core policy adapter: cd-core's lifecycle types, the kernellet's step shape, a benchmark-local home (RR-FAIR / CLOCK-AGE / HOT-RESIDENT), explicit parking, one thread, a standard Rust process. It does not execute the production cd-kernellet image or its 48-byte command / 32-byte outcome ABI. It supports a claim about ComputeDriven's scheduling policy and residency mechanism; it cannot support the stronger claim that the shipped no_std floor beats Linux, Go, BEAM or Seastar on transition price or footprint. That claim needs the real image, measured as itself. This is that campaign. The two campaigns are never combined into one winner claim (the review's stage gate, last line; F-KC-4).
What does one admitted semantic transition cost, in retired user-domain instructions, core cycles and L1 traffic, on the production
cd-kernelletELF built from the reviewed source and driven through its own ABI, compared with a semantically equivalent class-S transition loop in C, Go, Erlang and Rust — and what does the image and one live context cost in bytes?
"Semantically equivalent" is defined by §3's shared transition-vector suite, not by the kernellet's full battery (§2): the comparators implement the transition, not the kernellet.
The stage-0.1 review found revision 1 naming "R2's 201 witnesses" and tools/kernellet_abi.py as the battery, and asking transition-only comparators to pass the kernellet's complete external battery — which includes BOOT, table bounds, finalization, fencing, authority evidence, custody and multi-context behaviour those comparators do not implement. A shim supplying those mechanisms would test the shim. So: two different gates.
The production kernellet subject must pass the current full census gate, unchanged, at the exact measured commit: python3 tools/kernellet_census.py --check, which rebuilds the images, drives each through its ABI with tools/kernellet_abi.py, and diffs the receipt receipts/KERNELLET-R1.md (guards.sh runs it; a toolchain or source change fails the build by design). Its external witness battery is what receipts/KERNELLET-R1.json holds under batteries, derived, never hand-typed:
python3 -c "import json; b=json.load(open('receipts/KERNELLET-R1.json'))['batteries']; \
print({k: (len(v['checks']), v['held']) for k, v in b.items()}, sum(len(v['checks']) for v in b.values()))"
At 01031e6 (receipt last changed at 62a1c14) that prints six batteries — custody-n8 46, fastmem-n8 39, prod-n1 38, prod-n128 39, prod-n8 39, ring-n8 39 — 240 witness objects, 240 held, the total the review re-derived. The campaign's receipt re-derives it the same way at its own commit and quotes nothing else. (Revision 1's "201" was R1's count at an earlier commit, copied from memory: exactly the drift tools/counts_gate.py exists to refuse.)
One shared suite, limited to the semantics actually priced, that every row — the kernellet included — must pass before its timing run is admitted:
possession dispatch: ATTACH on Vacant → Attached; DETACH on Attached → Vacant; the inadmissible
op → BAD_POSSESSION (2, 6) with the lineage unchanged;
generation and transition evolution: DETACH increments generation; both increment
transitions; a DETACH whose gen_at_attach ≠ generation is REFUSED WrongGeneration (1, 4);
copy-in / copy-out: the step works on a copy and writes back only on success — **the original
survives every refusal byte-for-byte**;
the common digest (docs/fcb-model.md §4) over a fixed vector of ops from a fixed seed, so
a row that skipped a check or a fold differs in one number.
The suite is a fixed vector file (fcb/kc/vectors.json: op sequences, expected outcomes, expected generation/transitions, expected digests) plus one tiny driver per row that feeds the vector to that row's transition loop and prints the digest and the final state. Its non-vacuity: a `skip-copy-out` mutant (the step writes back on refusal too) and a skip-generation-check mutant, each in one row, must be caught by the suite before the first timing run. The kernellet passes the suite through its ABI (BEGIN, ATTACH/DETACH per vector op, the outcome frames); it passes §2.1 besides. A comparator passes only §2.2, and that is all it claims.
Subject: cd-kernellet built by tools/kernellet_abi.py K.build(features, n) from the commit
named in the receipt, in the two profiles the census names — prod (no features) and fastmem (rep movsb copies) — at n ∈ {1, 8, 32, 128} contexts (the census's own n set is the source of truth; the receipt lists what it used). Layout: the kernellet's own table, 312 B per context (the census's slope of .data + .bss over n), one shared stack.
Drive: the image's own ABI. BOOT, BEGIN per context, then one `BENCH n iters` command
that performs 2 · n · iters attach/detach transitions inside the image, then HIST and STACKHW reads (tools/kernellet_bench.py stream()). The host writes a handful of commands per run; no per-transition IPC exists on this path, so host pipe cost is not in the number. This is the census path that already exists; the campaign adds comparators to it, not a new driver.
NOT the subject: a pipe-per-transition "end-to-end" row. The review forbids calling host IPC
overhead the floor, and this contract does not build one.
| row | code | record layout | what it is |
|---|---|---|---|
cd-kernellet prod | the ELF | 312 B/context in the image's table | the subject |
cd-kernellet fastmem | the ELF, rep movsb copies | 312 B/context | the subject's second profile |
c-class-S | sflr/c/lineage.h + step_inc.h VARIANT 1 in a n × iters loop | 312 B lineage_t, an array of n | the R2 witness battery's C SUT shape |
go-class-S | sflr/go/sut.go step in the same loop | 312 B Lineage, a slice of n | the R2 Go SUT shape |
erl-class-S | sflr/erl/sut.erl step in the same loop | Erlang terms (no byte layout; reported as such) | the R2 Erlang SUT shape |
rust-cd-core | cd-core VacantLocus::attach / LocusAttachment::detach in the same loop | 144 B Lineage (cd-core's types, no authority ring), a Vec of n | the floor's own types without the ring |
Every comparator: the same loop shape as the image's BENCH op (iters iterations, each one ATTACH then one DETACH on every context in index order), the class-S step, the digest folded so partial work is visible, the result printed once at the end. No scheduler, no mailbox, no pipe, no clock read per transition: this campaign prices the transition; the scheduler-outcome campaign prices the scheduling. Toolchains and flags are pinned and printed (rustc 1.75, opt-level = "s" for the image and the Rust comparator; gcc -O2; the Go and OTP versions).
Runs per (row, n): iters = K, 2K and `4K`, K sized so a run is ≥ 200,000 transitions. Per-transition figures are (counter(2K) − counter(K)) / (transitions(2K) − transitions(K)), median of 5 repeats — tools/kernellet_bench.py's method — admitted only if the `K`/`2K`/`4K` points are linear (§4.2).
K/2K subtraction removes costs that are fixed per process at constant `n`. Which costs are fixed is a hypothesis about each row, listed here so the linearity check can refute it: process exec and image load; BOOT and the n BEGINs; the HIST and STACKHW reads; the harness's own instructions before the counters enable; first-touch page faults of the table and stack; and, for the language rows, runtime boot (Go, BEAM), JIT or loader work, and GC or runtime-service work that does not grow with the transition count. Revision 1 stated these as guaranteed by the arithmetic; the arithmetic guarantees nothing about them — a cost that grows with iters (a GC whose work is proportional to allocation, a first-touch that recurs, a service thread that wakes per unit of work) survives the subtraction and belongs in the number, and the only way to know which is to measure a third point.
For each (row, n, counter), the slope from K→2K and from 2K→4K must agree within the repeat dispersion (the larger of the two RSDs, floor 2 %). If they do not, the row is NONLINEAR for that counter: the receipt prints the three raw points and their repeat spread and withholds the marginal; no per-transition figure is quoted for it. A row may be linear on cycles and nonlinear on L1 misses; each counter is judged alone.
The transition itself; the image's command-loop dispatch to it (step(ctx, input) → outcome through the ABI shape, not the ABI's I/O); the rdtsc pair when the image's bench op stamps its histogram (its own column, never subtracted); the language row's per-iteration loop and digest fold (the same fold on every row); cache effects at n (the L1D cliff at n = 128 is a finding, not noise); and any runtime work that is proportional to transitions, which §4.2 has then shown to be linear and which is a real cost of that row.
User-domain hardware instructions, cycles, branches, l1d_access, l1d_miss, l1i_miss (perf_event_paranoid = 2 forces exclude_kernel). The cross-language column is therefore named user-domain transition-loop cost: the subject's path has no kernel work, so the domain is complete for it; a language row's kernel-side runtime work (Go's sysmon wakeups, BEAM's schedulers' syscalls) is outside the domain and is printed beside as sys time and rusage switches, never subtracted and never called zero. Counters are enabled and disabled by the harness around the BENCH command (the stage-0.2 window mechanism), so exec, boot and exit are outside the counted interval as well as cancelled. Multiplexed readings are dropped (R2's rule).
Noise term, stated as what is known and what is not: R1 observed that the instruction column drifts with interrupt rate and load, and reported branches beside it because branches retired is the deterministic counter on this ISA. Revision 1 asserted the mechanism — that a hardware interrupt's iret retires as a user instruction. This contract does not assert it. The campaign either cites direct evidence for the mechanism (vendor documentation for this CPU model, named in the receipt) or demonstrates it with a control (a fixed user loop under two interrupt rates, the instruction delta against the branch delta), or reports the drift as observed and unexplained. What is asserted: the campaign runs only under docs/battery-host-profile.md, and branches is printed beside instructions on every row.
.text + .rodata of the image by readelf (the census); per-context bytes as the slope of .data + .bss over n (312 B/context in R1); for the language rows, the process's own VmHWM (/proc/self/status, read by the row at exit — rusage maxrss is floored at the spawner's address space at exec, a stage-0.1 finding) and its Theil–Sen slope over n ∈ {8, 32, 128} × 3 repeats with min/max — the two footprint numbers are of different kinds (static image vs live process) and are printed in different columns, never compared as one.
CLOCK_MONOTONIC is the shared monotonic clock domain for every timestamp the campaign records (counter edges, run boundaries). It is not changed discontinuously by wall-clock setting; its rate may be adjusted, which every process sees alike. Nothing here needs more than a shared domain.
Nothing about scheduling, fairness, tails, residency or refusal under contention — that is the
other campaign, on the other row.
Nothing about the ABI's I/O cost per transition — the path measured does not pay it.
Nothing about a language row's runtime — only its transition loop, and only in the user domain.
No cross-ISA claim (x86-64, rustc 1.75, opt-level = "s" only).
Nothing before it runs under the dedicated-host profile with the sentinel gates, and nothing
from a development smoke.
Nothing from a row the linearity check marked NONLINEAR, beyond its raw points.
F-KC-1 — a comparator that skips a check the class-S suite names (copy-out, generation match,
the original surviving a refusal, the fold) is not equivalent; the §2.2 suite must reject it, and the skip-copy-out and skip-generation-check mutants must be caught before the first timing run.
F-KC-2 — an image whose feature set or toolchain differs from the reviewed floor's is a
different subject; the receipt names both and the census gate (§2.1) must pass at the same commit with its witness total re-derived there.
F-KC-3 — a marginal quoted from a row whose K/2K/4K slopes disagree beyond the repeat
dispersion (§4.2).
F-KC-4 — any sentence that carries this campaign's number into the scheduler-outcome
frontier, or the reverse.
F-KC-5 — a cross-language cost column not labelled user-domain, or a kernel-side runtime
cost subtracted or read as zero (§4.4).
F-KC-6 — the interrupt-return mechanism asserted without the evidence or the control §4.4
names.
This is the revised contract. Codex reviews it; then, if accepted, code is written to it — the §2.2 suite and its mutants first, the comparators second, the campaign runner last; then the campaign runs only under `docs/battery-host-profile.md` after its own authorization. Not before.