121 — The instrument that would have errored every cell

2026-09-10 · distribution lane · DISTRIBUTION D1, BM2 build-order step 1

The two runner gaps JOURNAL/119 demonstrated are closed, and BM2's arms are no longer blocked on the instrument. Both were about the same thing from two directions: tools/benchmark/run.mjs, which grades the arms, and tools/benchmark/flip-test.mjs, which admits the tasks, were reading the same install two different ways. The gate had been brought to §9's fifth amendment on 2026-09-09 (JOURNAL/109) and the runner had not.

Nothing published moved. No benchmark document was touched, no arm ran, no subject was spawned.

Gap 1 — the runner handed assertions no subject at all

The gate calls an assertion as { subject, library, produced, version }, where subject is what tools/audit/probes/<lib>.mjs builds for that rung and library is the same object under the name BM1's twelve assertions were written against. The runner called it as { library: await env.loadLibrary(), produced, version }no subject key, and loadLibrary was a zod-shaped import(node_modules/<lib>/index.js). Every prisma assertion destructures subject. Every cell of every arm of BM2 would have been an error cell.

What was done, and it is a deletion rather than an addition. subjectsFor — one subject per rung, built by the probe file, plus the two ways an install can be broken — moved out of flip-test.mjs into tools/lib/rung.mjs, the module that already exists so that the bisector and the gate cannot disagree about what a subject is. The runner imports the same function. There is now one definition of "the subject at release X" and three callers.

The refusal sentence deliberately did not move. A gate's ends "a boundary measured on a ladder with a rung missing is the release where the LADDER changed, not where the fact did"; the runner's ends with the release its arms would have been graded on and "nothing was graded". What a subject is, is shared, because two instruments disagreeing about that is a wrong number. How an instrument explains its own refusal is that instrument's, because the two refuse for different consequences.

Where the release is, is no longer a path spelled out in the runner. It read <modules>/node_modules/<lib> — a fourth install layout known to no other tool. That shape is now a named entry in rung.mjs's own table, flat-real, and the runner resolves the graded release through resolveRung with the three ladder layouts first and flat-real last. The consequence is practical and immediate: a runner pointed at the ladder the gate admitted the tasks on finds the graded rung inside it, which is how the demonstration below ran against prisma 7.10.0 without installing anything. BM1's install answers to flat-real and its cells do not move.

And the environment is now checked before the first cell, not after the arms. A subject that will not build, and a control the probe file says is true on every release and is not, are both the install's fault; an arm graded through either measures the install (JOURNAL/108, /109). The runner refuses the whole run, names the release and says nothing was graded.

Gap 2 — the reply was always imported as a module, and A1's answer is not one

loadProduced wrote the reply to a .mjs and imported it, and gradeOnce turns a failed import into a graded failure with the syntax error as retry feedback. That is right for BM1: a reply that will not import is a subject that wrote broken JavaScript. It is wrong for BM2's A1, whose fact is about the schema language, whose prompt asks for a schema.prisma, and whose answer imports as SyntaxError: Unexpected identifier 'db'. Round 0 would have failed in every arm for a reason that is ours. Symmetric across arms, so never a bias between them — and still four cells of a published document measuring the grader.

§9 NINTH AMENDMENT, written before any BM2 arm ran: a task declares what its answer is. produced: { form: "text", as: "schema" } in the task, absent meaning module — BM1's entire set, unchanged. Under text the runner hands the assertion { <as>: <the reply's bytes> }, which is the shape the gate's committed artifact already has, and the gate refuses a text task whose artifacts do not export <as> as a string. So the equality of the two shapes is checked rather than assumed, which is the whole point: one assertion grades the operator's artifact and the subject's reply, and until now nothing required them to be the same kind of object.

A2 stays a module task and that is not an oversight. Its answer is a list of strings and a module exporting argv is the unambiguous way to receive one. Wrapping a file in a module changes what the task asks for; receiving a list as a list does not. That is the line the amendment draws, and it is written into the protocol rather than left in a task comment.

The demonstration, end to end, on the real install

Not argued. The runner was pointed at the twenty-three-rung prisma ladder and at a scratch document holding BM2's two admitted tasks, with the committed artifacts placed as if a subject had replied with them. It is not a benchmark run — no subject was spawned, the document lives in a temp directory, nothing was published — and it is the only thing that can say the two gaps are closed.

graded on prisma@7.10.0 — per-rung-alias under …/sp-prisma-bisect,
  subject from tools/audit/probes/prisma.mjs

  reference artifacts   A1 pass=true   A2 pass=true
  stale artifacts       A1 pass=false  A2 pass=false

The stale replies fail with the toolchain's own words — A1 with The preview feature "metrics" is not known, A2 with Unknown command "introspect". That separation at the graded release is exactly what BM2 will measure, and the instrument now produces it.

What the demonstration found on its way past

A1's retry feedback was a banner, not the error. Its assertion returned the first non-empty line of prisma validate, which is Prisma schema loaded from <file>. Measured against A1's own committed stale artifact at 7.10.0: the real error is four lines further down and the first line carries nothing at all. A retry round told only the banner is a round the subject cannot use — in every arm, so never a bias, but rounds_to_pass is one of the numbers BM2 publishes and it would have been measured against an empty feedback channel. An assertion's detail is retry feedback before it is a grader's note, so it now quotes the toolchain. Recorded in §9 and in the file, for the ten seats still to be authored.

Every check was made to fail before it was trusted

JOURNAL/118's lesson is that a rule can survive its own adoption only in the file that declares it, so each new check was driven against the defect it names by mutating the committed code:

mutationwhat failed
the assertion argument put back to { library, produced, version }the assertion must receive the environment's own subject
produced.form ignoredsix checks, including the four the assertion receives
the environment refusal removedthree, naming the release and the control
the ninth amendment's shape check disabledtwo, on a number-valued and an absent export

Nothing that was byte-identical stopped being byte-identical

Every claim of "unchanged" here is a diff against output captured before the first edit, on installs that were already on disk:

Selftests: the gate 42 → 46 checks, the runner 42 (it now counts them). MCP 54/54, identifiers 35, five generated surfaces green, citation sweep 459 api joins, 8 allowlisted, 8 matched, 0 stale. Corpus counts unmoved at 161 runs / 167 findings / 8 libraries, which is correct for a session that ran no battery and no arm.

What is left of BM2

Ten drawn Class A assertions plus A7's substitute, the six Class N tasks, BM2's own predictions, then the arms. The arms are no longer blocked. No gate is needed from Sam for any of it.