The tables conformance harness

September 9, 2026 · View on GitHub

A port of the tables layer is "make the driver pass" — and fill its column on docs/PORTING.md, the techniques register. The register is read before the port brief is written; the port PR is not ready until every technique on it is carried or cited in the port's column; and a blind read of the port reports two lists against it — methods the port uses that the register lacks, and methods the register has that the port lacks.

The data lives under testdata/conformance/tables and names no language (FORMAT.md there states every file shape). This page states what a language's DRIVER must do. Registering a port is one driver at <lang>/driver: the harness discovers it, and nothing lists it.

make conformance                     run every registered driver, print the matrix
make conformance-generate            rewrite the generated half of the data
make conformance-pin                 rewrite the half the reference leg writes
make conformance-negative-control    prove the harness can go red

Seven negative controls stand behind it, and each localises a different thing — a harness that has never gone red is watching nothing, and one that goes red everywhere localises nothing:

controlwhat it breakswhat must go redwhat must stay green
conformance-negative-controlone byte of a C++ dumpcpp / json-writewire
conformance-negative-control-block-dumpone byte INSIDE A ROW of the block imageblock-dumpblock, forgery
conformance-negative-control-csthe C# walker, in the emittercs / json-readjson-write
conformance-negative-control-gothe Go leg, in the emitterits own surfacethe rest
conformance-negative-control-go-walkthe Go walk's field offsetgo / json-readjson-write
conformance-negative-control-java-blockthe array PITCH CHECK in the Java openjava / forgeryblock, block-dump

Two of those rows are the reason two surfaces exist at all. The row-dump one is why block-dump is separate from block: Open reads the prologue and the triples and nothing else, so a byte inside a row cannot move its answer. And the pitch one is why forgery is separate from both: it removes a CHECK rather than moving a value, so the reader still READS correctly and has stopped REFUSING — which no valid image can show you.

A PER-BACKEND WALK CONTROL, one per port with a text form, because a walker's break is the backend's and not the data's: conformance-negative-control-go-walk breaks the Go walk's offset arithmetic. It has the same second half as every control here, and it is the point: json-read goes red and json-write stays green, which is what says the break is the READER's. (Elixir emits no text form and has no walk control; schema#515 brings its wire.)

The shape

A driver is a command, not a binary — so a leg can be assembled from what a backend already has rather than from a second copy of it. Some registered drivers are shell scripts that dispatch: the C++ one answers the table and block surfaces from build/conformance-cpp and hands the two COOK surfaces to build/schema_test_cook, which already opens that unit and already runs that battery. Others are one binary that answers everything, and the JavaScript one answers every surface from one module, because a node process starts in tens of milliseconds and there was nothing to assemble — see "Registering a language" below, where both shapes are stated.

<command> <manifest> list
<command> <manifest> <surface> <outdir>
  • The working directory is the repository root. Every path in the manifest is repo-relative, so a driver never resolves one itself.
  • <manifest> is a DERIVED manifest the harness writes into build/: the committed one with the materialised fixture paths folded in and every expected answer removed. A driver cannot pass by reading the answer.
  • list prints the surfaces this backend implements, one per line, to stdout.
  • A surface run writes ONE FILE PER CASE into <outdir>, named by the case, and prints nothing that matters. The harness holds the expectations and does the comparing.

Exit codes

codemeaning
0the surface ran
2this backend does not implement it — the matrix prints ABSENT
anything elsethe driver failed; the matrix prints FAIL and the harness prints stderr

A CASE may be absent too, and it is said the same way. A driver that cannot answer one case of a surface it otherwise implements writes <case>.absent — an empty file, beside where the answer would go — and the harness counts it. The cell then reads pass 16/16 +4a: what the leg answered, and how many it said it cannot. The distinction is the surface-level one at a finer grain, and the corpus needed it the day it gained VARIABLE-class instances: a backend with no variable class still answers the wire surface over every FIXED instance, and a leg that failed the whole surface for them would say nothing about what it does carry.

THE REFERENCE LEG MAY NOT ANSWER ABSENT, AT EITHER GRAIN, and that rule is what makes absence safe rather than a place to hide: an absence from the reference leg — cpp, first in the discovered registry, and the one conformance-pin takes its pins from — is the corpus losing its own expectation, not a port's missing feature. All three ways of saying it are a FAILURE there, named in the matrix and in the failure list: a surface left out of list, exit code 2 on a surface, and <case>.absent for a single case. The harness prints FAIL absent for the two coarse ones, and the success footer cannot print beside any of them. The rule belongs to that registry alone: a run handed a SUBSTITUTED one with --drivers, as the big-endian leg does for its single Go driver, is one leg of a port and not the matrix, so its first line is not the reference and its absences are ordinary.

THE MATRIX IS THE COMPLETION TRACKER. Green cells over total cells is what "done" means for the tables layer, and an absence — per surface or per case — is the row of work that is left, named where it can be seen. The eight ports read +28a on the wire surfaces and +26a on the text surfaces today — the four variable-class instances, the fifteen of the message class (a union whose arms are tables, an array of unions, and an optional array, docs/SPEC-TABLES.md §2.6, §2.3), the three of the wide-scalar class (§3) and the six of the byte buffer class (§2.5, one of them wire-only) — and the reference answers them all; they become part of the count as schema#349 and the per-construct follow-ons land them, one language at a time, with nothing in this data or this contract moving as they do.

Wire-form coverage is separate from storage coverage. C++, C, C# and the independent compiler engine carry the id-table wire (form 1, the variable form) and bitpacked message form. C and C# also carry variable regions, builders, retained unknowns and canonical cooks. Their pipe drivers compare values, re-saved bytes, measured sizes and reports with the independent engine. make tables-c-wire-fuzz and make tables-c-retain run C natively and under ASan/UBSan; the corresponding C# managed, native, builder and retention targets are in make/cs.mk.

Unsupported roots are printed as N seeds absent (roots the leg has no codec for). Absence is explicit and never counted as a passing fixture. PORTING.md M20 records the coverage and gates.

Absent is not failure, and the distinction is the whole reason the matrix exists. A backend with no text form is missing a FEATURE; a backend whose text form writes the wrong bytes is failing a TEST. A harness that printed both the same way would be telling a port to implement nothing in particular. The C# leg is the worked example: it registered with json-read and json-write ABSENT, and both cells moved to pass 18/18 when the C# walk landed — nothing in the data or in this contract moved with them.

A DRIVER MAY TAKE ITS GENERATED TREE FROM THE ENVIRONMENT, and the JavaScript leg does (SCHEMA_JS_GENERATED). That is not a contract change — the harness still hands a manifest, a surface and an output directory and nothing else — but it is what lets conformance-negative-control-js point the SAME driver at a sabotaged copy of the generated modules and require the matrix to go red. A leg whose generated tree is baked in has nothing for a control to aim at.

The surfaces

One process per surface, so a runtime starts once rather than once per case.

surfacefor eachthe driver writesthe harness compares against
wireinstanceLoad the wire file, Save, the bytesthe wire golden
messagemessageAnnounceRead the connection's announcement, LoadMessages the message-form batch against it, SaveMessages, the bytesthe message-form golden
reportreportLoad the wire file, the report as u,k,w,c,d,m,verdict\nreports.txt
retainretain, retain-messageLoadRetain the wire at the row's two capacities, MeasureRetain, SaveRetain, the counters as <retained>,<retain_lost>,<unknown> <save lost>\nthe counters in the manifest
retain-savethe rows that name a savethe same round trip, the SAVED BYTES, one body after anotherthe pinned saves, back to back
json-readinstanceFromJson json/<name>.json, Save, the bytesthe wire golden
json-writeinstanceLoad the wire file, ToJson, the text, as <name>.jsonjson/<name>.json
json-hostilejson-hostileFromJson <tree>/<root>.json, the report as u,k,w,c,d,m,verdict\n, or refused\nthe verdict in the manifest
cookcookOpen the cook, the canonical node dumpcook/<case>.dump
cook-writecook-writeLoad the instance's wire, Cook it in each byte order, the bytes, as <instance> and <instance>-bethe two files schema cook wrote
cook-foreigncookbyte-swap the file's MAGIC word, Open, open\n or refuse\nrefuse\n
blockblockOpen the image, open\n or refuse\nopen\n
block-foreignblockbyte-swap the image's MAGIC word, Open, open\n or refuse\nrefuse\n
block-dumpblockOpen the image, the canonical ROW dumpblock/<name>.dump
forgeryforgery (block)Open the forged file at the claimed extent, open\n or refuse\nthe verdict in the manifest
cook-forgeryforgery (cook)the same, over the cook battery's 111the verdict in the manifest
cook-reasonrefusal (cook)Open the forged cook, the reason beside the null as the enum's value name, or okthe reason in the manifest
block-reasonrefusal (block)Open the forged block, the reason beside the false as the enum's value name, or okthe reason in the manifest

wire and json-read write a file named by the instance; json-write writes <instance>.json; the others write a file named by the case.

message IS THE ONE SURFACE THAT READS TWO FILES, because a message's id table is somewhere else (docs/SPEC-TABLES.md §3.3): the CONNECTION's announcement carries it, the driver reads that first into one direction's VOCABULARY, and the batch resolves against it. The manifest's connection line names the announcement and the message line names the pair of wires, so the driver joins the two by key and never derives a vocabulary of its own. The verbs are PLURAL, because the form's primitive is a BATCH of bodies of one root and a single message is the batch of one, so a message case whose batch wire holds one body still drives LoadMessages and SaveMessages with a count of one. The C++ reference answers the surface and the eight ports print ABSENT, which is the wire form's own absence one grain up: a port carries the VARIABLE form alone, and its LoadMessages, MeasureMessages and SaveMessages are the follow-on PORTING.md M20 already registers.

THE TWO RETAIN SURFACES ARE ONE ROUND TRIP AND TWO SHAPES (docs/SPEC-TABLES.md §6.6): retain prints the COUNTERS and retain-save writes the BYTES, split for the reason the block surfaces are: a counter cannot see a record that moved out of a body, and a byte string cannot say which of the two stores was short. Both run the same pair, so a leg that answers one answers the other.

A ROW'S TWO CAPACITIES ARE RULES A DRIVER APPLIES, and one of them is the whole reason they are not numbers. A retained record's byte cost is the port's own, so short means ONE BYTE SHORT OF THE LAST RECORD: the driver loads once at a roomy capacity, reads what its own buffer used, and loads again one byte under that. The ID LIST's capacity is a COUNT and travels as one. The C++ reference answers both surfaces and the eight ports print ABSENT, which is the same absence the message and wire surfaces already carry one grain up: a port carries no retention at all, so LoadRetain, MeasureRetain and SaveRetain are a missing FEATURE and not a failing test, and §6.6's own backend status says so. A retain-message row needs the form-2 read beside them, which no port has either, and its capacity is full only: short is one buffer's rule, a batch takes one buffer a body, and the manifest loader refuses the pair by name rather than let each leg read it its own way (schema#681).

cook-write IS THE ONE SURFACE WHERE A LANGUAGE WRITES AN ACCELERATOR RATHER THAN READING ONE, and the expectation is the TOOL's file. Every other cook surface asks whether a reader agrees about bytes somebody else produced; this one asks whether a WRITER produces the bytes schema cook produces, in both byte orders, from the same wire (SPEC-TABLES.md §7.6). It needs no big-endian host on either side, because the order is a parameter of the write rather than a fact of the machine. A leg with no writer prints ABSENT, which is the whole point of the distinction: C++ answers it today and every other leg is missing a FEATURE rather than failing a test.

The two forgery surfaces are one shape and two KINDS, split so the matrix can say which reader a backend has: a leg with a block reader and no cook reader prints absent on one and a verdict on the other, rather than one blaming the other.

THE TWO FOREIGN SURFACES ARE THE CROSS-ENDIAN REFUSAL, and they are the one answer a leg can give on ANY host. A block and a cook are produced in the byte order of the build that wrote them (§19.1, §7), so a reader of the other order must REFUSE — and the check that does it is the magic, read first in the machine's own order precisely so a foreign file stops there. Every other accelerator surface has a host-dependent expectation and a big-endian leg can only mark them absent; these two do not, because THE DRIVER MAKES THE FILE FOREIGN TO ITSELF: it reverses the eight bytes at offset 0 — the magic — and opens the result. Whatever this build's order is, the magic it now reads is not this build's, and the verdict is refuse for every leg on every host.

It is one word and no builder: the driver reads eight bytes, reverses them, writes them back, and opens. A leg that has the reader can answer it, which is what makes it a REFUSAL a big-endian leg reports green rather than an ABSENCE it reports as a missing feature.

A forgery line carries an EXTENT and a POINTER, and neither is a fact a file can hold. The extent is the length the caller CLAIMS: larger than the file — two rows of the block battery are about exactly that — or shorter, which is what a truncation is. The pointer is the buffer that caller holds: 0 an aligned base, 1..63 that many bytes past one, null no buffer at all. A driver allocates EXACTLY the claim, places the base as the pointer column says, copies what fits and zeroes the rest. -1 as the extent means the file's own length.

What the BLOCK surfaces do not cover, by design

§19's block form is a FIXED-size table's third layout, and it does not admit a variable one: a block is one contiguous image of rows at a stride, and a pointered table has no stride. So the block surfaces carry no variable case and never will — that is ABSENT BY DESIGN and not a gap anyone is tracking, which is why it is written here rather than left to look like an oversight in the matrix. The variable class's accelerator is the COOK (§7), and the cook, cook-foreign and cook-forgery surfaces have carried pointered roots since they landed.

Why there is no dump-read

The contract asks a driver to write a dump and never to parse one. wire proves the writer against the reader; json-write proves the reader's VALUES against a text a third implementation wrote; json-read proves the writer against an instance the driver did not build. A dump parser would add a component to every port and cover nothing those three do not. Where a backend has no text form, the gap is real and the matrix says so rather than a parser papering over it.

Registering a language

  1. Write a driver at test/conformance/<lang>/driver that answers list and the surfaces the backend has.
  2. Write test/conformance/<lang>/ci.json, the leg's row in the pull-request matrix.
  3. make conformance.
  4. Fill the language's column on docs/PORTING.md; go test ./compiler holds it to the tree.

THE REGISTRY IS DISCOVERED, NOT LISTED. The harness reads every test/conformance/<lang>/driver that exists, and harness matrix reads every ci.json beside one; no file names every language, so a port adds its directory and touches nothing another port touches (docs/CONTRIBUTING.md, "Adding a language"). The reference leg is cpp — the harness's own constant, sorted first — and the rest follow by name.

ci.json is one JSON object of strings, and .github/workflows/ci.yml's conformance job reads it as the leg's matrix row:

keywhat it is
targetsthe make targets that build the leg (required)
envVAR=value assignments the make and run steps carry — a toolchain on PATH rather than in dist/
runtime, runtime_tagthe sibling checkout the leg needs (serialize.cs) and the workflow variable that pins it (SERIALIZE_CS_TAG)
node, rust, dart, java, otp + elixirthe toolchain step to run, and the version it installs
dotnetthe .NET SDK step to run, and the file holding the version — .github/dotnet-version, the repo's one pin, because nine csproj files under test/ and bench/ target it and certify.yml builds all of them (issue #470)

A leg that names a toolchain with no step yet adds one step to the workflow, keyed on its new field; that is the one edit a port makes there. A driver with no ci.json fails harness matrix, and the registry gate (harness/registry_test.go) plants a fake language in a copy of the tree and requires the harness, the bench pass and the Makefile to discover it with no shared file edited.

THE ELIXIR LEG's shape, because its cost is all start-up. Its driver's own modules are compiled to .beam WITH the unit corpus rather than at every start: an .exs compiled per invocation cost 0.4 s on top of the BEAM's own 0.26 s boot, twelve times over. The leg answers all twelve surfaces it carries in 5.6 s, and none of that is the cases.

The reference leg is cpp, and the harness sorts it first: make conformance-pin takes the cook dumps, the block row dumps and both forgery batteries' offsets from it. That is the repo's standing convention — C++ writes the pins, every other leg compares. The two batteries print their manifest rows on stdout rather than editing the manifest: a manifest that rewrites itself is a manifest nobody reviews.

A leg may be assembled from more than one binary, and it may be one. The C++ and C# drivers dispatch the cook's dump to a binary each backend already had; the Go driver is a single binary that answers every surface in process, which is why its cook surface costs one exec rather than five, and the Java driver is one class on one classpath for the same reason — its generated units, the wire ones and the block and pointered ones, are packages of a single classpath, so the cook's node dump and the 111-row cook forgery battery ride inside processes that were already starting. Both shapes satisfy the contract, because the contract is a COMMAND.

The wire-fuzz driver

harness wire-fuzz (docs/SPEC-TABLES.md §4.2) is the tolerant wire's fuzzer, and its leg is a different shape from the surface drivers above: ONE process for the whole run, on a pipe, that only reads. The harness generates every mutant and holds the oracle; the leg loads each mutant through the generated tolerant read, saves whatever it decoded, and answers what happened. It decides nothing about what a mutant means.

make tables-wire-fuzz                      the C++ reference, plain and sanitized
make tables-wire-fuzz-negative-control     both controls: a check removed, the fuzzer red
make tables-wire-fuzz-retain               the same mutants through the RETAINING paths
make tables-wire-fuzz-retain-negative-control   its own pair, one control per engine
./build/conformance-harness wire-fuzz --driver <cmd> [--seed S] [--n N]
./build/conformance-harness wire-fuzz --driver <cmd> --replay <file> --unit <key> --root <table>

The stream, little-endian throughout. The working directory is the repository root; the driver is a command, split on whitespace, as every driver is.

directionwhatwhen
inu32 roster count, then per root: u16 n, the unit key, u16 n, the root table's name, u8 the FORM, u8 RETAINonce, first
outone byte per roster entry: 1 when this leg has a codec for it, else 0once, in reply
inper mutant: u32 roster index, u32 length, the bytesuntil EOF
outper mutant: u8 loaded; i32 unknown, kind_mismatch, widened, clamped, duplicate; u8 malformed; u8 refused; i64 measure; i32 retained, retain_lost; i64 saved, then that many bytesone reply per mutant, flushed before the next is read
  • loaded is whether a root came back. A FIXED root always loads — its Load fills a value and reports — so the byte is 1 and the report says the rest. A VARIABLE root's Load returns NULL when the caller's region was wrong, and a 0 here fails the run: the leg sized the region from LoadMeasure, so a refusal is the measure and the load disagreeing.
  • measure is what LoadMeasure asked for, region bytes in total; a FIXED root answers -1. The harness holds it to the framing's bound (§4.2, §6.5).
  • saved is the length Save wrote, or -1 when Measure or Save refused the value. The bytes follow only when it is positive.
  • Every buffer is allocated at exactly its size — the mutant, the region, the save — so that a sanitized build's redzone begins at the last byte a reader may touch, and every reply is flushed before the next mutant is read, so a crash is attributed to the mutant that caused it. A buffer of ZERO bytes is the one exception to the sizing: it is allocated at one byte, because malloc(0) may answer null and null is how a leg reports an allocation that failed.
  • The FORM is the wire's own byte (docs/SPEC-TABLES.md §3, §3.3): 1 is a file and 2 is a BATCH, and the two are separate roster entries over one root, because they are two readers. A MESSAGE mutant resolves against the CONNECTION's announced VOCABULARY, and the leg derives that vocabulary from its OWN unit's announcement, the compile-time constant its backend emits, read through the same AnnounceRead a receiver uses. The vocabulary is a pure function of the build version, so both sides derive the same one and the roster carries no announcement. A form-2 mutant is driven through LoadMessages and SaveMessages, the plural verbs, because a batch is the form's primitive and a mutant of one body is a batch of one. A leg with no message codec answers 0 for that entry, exactly as it does for a root it cannot name.
  • The RETAIN byte says which path this entry is driven through (docs/SPEC-TABLES.md §6.6). 0 is the ordinary run: Load and Save, with retention off, which is what leaves the round-trip requirement the one §4.2 states. 1 is the retention arm: LoadRetain, MeasureRetain and SaveRetain over one TableRetain the leg owns, with both capacities declared large, because a record's byte cost is the port's own and two engines at one tight capacity would drop different records. The arm's roster is the VARIABLE-CLASS FILE ROOTS and nothing else: a fixed-class root's LoadRetain is refused by name and a form-2 SaveRetain refuses by name (§6.6, §3.3), so those entries never carry a 1, and the line says how many seeds sat outside the arm.
  • retained and retain_lost ride EVERY reply, and are zero on every entry the roster did not mark. They are the two counters the retention arm compares beside the six, and retain_lost at the end is the sum of what the load could not keep and what the save could not place, so the leg zeroes one report before LoadRetain and reads it after SaveRetain (§6.6). A leg with no retention at all answers 0 in the roster for those entries and writes two zeroes here.
  • A root the leg cannot name is a 0 in the roster and nothing more: the harness never sends it a mutant, and the line it prints says how many seeds were absent. A port with no variable class registers its fixed roots and is fuzzed over them.

The C++ leg is test/tables/wire_fuzz_main.cpp: a codec table of (unit, root, run) triples, a fixed and a variable template, and the stream. A port's leg is that file's shape in its own language and nothing else — the mutators, the oracle and the comparison never move.

The pinned vectors. testdata/wire/tables/fuzz-vectors/INDEX.txt names mutants the fuzzer has already gone red on, one per line as <name> <unit> <root> <file>. Each rides in every run, exactly as it is and before the random pass, so a red it pins is a SEEK rather than a search. They are seeds like any other but are never mutated and never drawn from by the random pass, which is what keeps the mutant sequence a function of the corpus and the seed alone. Pinning a vector cannot move a red that was already there. A vector earns its place by having been a red, and the fix that closed it owes a negative control naming it.

A failure prints what reproduces it: the run seed, the corpus seed and pass it came from, and the mutant's own bytes as hex, restored with xxd -r -p. A red in a CI log a person cannot re-run is still a red they can replay. A mutant past 4 KB prints its SHA-256 instead and the run seed carries the reproduction. The whole mutant is on disk at --failed either way.

The budget

make conformance runs under the two-minute rule (#320). Measured on arm64 macOS, everything already built, median of three, one sitting — the whole table re-measured together when the C leg registered, because a table whose rows come from different sittings can say the whole costs less than one of its parts. The laptop was NOT quiet for this sitting (three sibling ports building alongside, load average near 12), so every row here is an upper bound and every row is inflated by the same load: read the RATIOS, and read the totals as a ceiling. The quiet-laptop numbers this replaces are in git history:

legwall
all seven, 268 cases per leg22.8 s
java alone0.63 s
go alone0.74 s
c alone0.76 s
rust alone0.88 s
cpp alone1.00 s
dart alone2.86 s
cs alone18.0 s

The cost is per-PROCESS, not per-case, and the numbers say so plainly. The battery grew from 80 cases per leg to 268 — the cook's 111 forgeries, the 66 hostile trees, a sixth cook, two block row dumps and the two FOREIGN surfaces — and the six NATIVE legs still answer all 268 each in under three seconds. The C# leg starts a runtime once per surface plus once per cook, because test/cs-cook's dump takes one root per invocation, and that is where nearly the whole wall is: of the 1,876 cases in this table, the 1,608 the six NATIVE legs answer cost about seven seconds between them — under three seconds each, even under this load — and the last 268 cost eighteen.

cook-write added 40 cases to the C++ leg alone — twenty instances in two byte orders, the four VARIABLE ones among them — and the table above is NOT re-priced for them: they are answered inside build/conformance-cpp, a process that was already starting for the wire surfaces, so what they cost is a wire load, a numbering walk for a pointered root and a memset per case in a leg the table already measures at a second. The row is left as it was measured rather than adjusted by arithmetic, which is what the sitting rule means.

The C leg answers all 268 from one native binary, which is the cheapest shape the contract allows and what puts its row among the fastest. A sixth leg cost the whole run less than the run's own spread across three repeats.

The DART leg is AOT-COMPILED for exactly that reason: dart run would pay a JIT start-up per surface, and the leg answers all twelve it carries out of one binary, thirteen execs of something that starts in milliseconds, which is what puts its row among the native legs rather than beside the C# one.

Six native legs cost about seven seconds together. Adding the two foreign surfaces cost each native leg two more execs of a binary that starts in milliseconds, and cost the C# leg two more runtime starts — which is the whole shape of this table in one edit. A leg that answers every surface in ONE binary is the cheapest shape the contract allows, and cook and cook-forgery answered in the same binary as everything else rather than delegated is what makes it so; the C++ and C# legs cost what they do because each was assembled from a binary that already existed, which the contract exists to allow.

The two MANAGED legs differ by seven times, and the difference is the SHAPE rather than the runtime. Both start a process per surface; the C# leg starts one more per cook, because test/cs-cook's dump takes one root per invocation, and the Java leg starts none, because its generated units — the block unit and the pointered unit — are packages of a single classpath, so both cook surfaces ride inside processes that were already starting. Twelve JVM starts is 2.2 s; twelve runtime starts plus six more is 11.7 s. A managed leg pays for its process starts and nothing else, so the number of them is the whole design decision.

So what the remaining languages cost depends on the SHAPE each leg takes rather than on the corpus, and the two shapes measured here differ by twenty times. A managed leg costs roughly 0.9 s per process start, times the twelve surfaces plus one per cook. Nine legs of the native shape is about 8 s; nine of the managed shape is about 150 s, which is past the two-minute rule on its own. So the rule holds comfortably while ports take the cheap shape, and the leg that does not is the one to shard — per language leg, the way the type wire's nine legs already are. Not needed at this size, and the number to watch is the per-start cost of the managed legs, not the case count.

What is not here yet

Named, with the reason, so a port knows what it is not being asked for:

  • The FIXED-root cooks (Settings, Stamp). test/cookgen writes a root followed by a chain, so a root nothing points from has no fixture here, and the two fixed roots' value crossing stays where it is — in test/tables/cook_main.cpp's fixedvalues mode and its C# twin, which read a cook the C++ side wrote the wire for.
  • The block form's fuzzers (test/tables/block_fuzz_main.cpp and its C# twin) and the cook's. A fuzzer is a search, not a case, and the finds it produces land here as forgery rows — block_offset_overflow is one.

The optional wire-fuzz --builder arm compares mutable file readers with tablewire.Decode. Its roster contains variable-class file roots. The driver reports its load result in the existing loaded byte, the accumulated report, and canonical saved bytes only after a successful read. A failed read emits a save failure (-1); the partial value must be discarded. This arm does not preflight or compare region extents. In particular, an int32 list count-cap refusal stops without inventing the region reader's malformed-data event. --builder cannot be combined with --message or --retain. The existing region and retention arms retain their measurement and bounds checks.