# BM2 — the Class A draw

**Recorded 2026-09-10, before a single acceptance assertion was written.** The pair was fixed first
and separately (`prompts/benchmark-bm2-preregistration.md`, 2026-09-09: `prisma × claude-sonnet-5`),
the protocol is `prompts/benchmark.md`, and BM1's equivalent record is
`prompts/benchmark-bm1-draw.md`.

Benchmark id, which is the seed of the draw order and is not defaulted:

```
prisma--claude-sonnet-5--bm2--2026-09-10
```

## Why this file exists

§7 forbids choosing the tasks out of the corpus, and §13's build order puts the draw **before** the
assertions for a reason that is about difficulty, not about honesty in the abstract: an acceptance
assertion is real work, some facts are far easier to assert than others, and a task set assembled
while writing the assertions quietly becomes *the twelve facts whose tests were pleasant to write* —
which correlates with simple API surfaces, which correlates with what a model gets right. Drawing
first makes the difficulty fall where it falls and makes every discard visible.

This file records **two** draws, and the first one is here because it was wrong.

## The draw that was run first, and the rule it exposed

The first run of `draw.mjs` under this benchmark id drew a twelve-task set from a pool of **26**
facts. Two of those twelve — **A4 (LF9**, the `prisma.config.ts` engine key**)** and **A11 (LF24**,
connection pool defaults**)** — have **no probe row in `tools/audit/probes/prisma.mjs` and no
`measured_range` in `data/prisma/facts.json`**. Their `introduced_in` is a changelog reading that
has never been executed against a single release.

§7 rule 1 is *"Bisected. `introduced_in` confirmed by an executable probe, not by a release note."*
It is written about a fact. `draw.mjs` was enforcing it against a hand-maintained map of which
**libraries** had been through `bisect-facts.mjs`, and its own comment said why: *"facts.json does
not carry the claim — bisection is an event in the repo's history, not a property of a fact."* That
was true on 2026-09-07 when it was written. It is false now — `measured_range` is per fact, it
records the lowest and highest release at which **that statement** was executed, and
`build-index.mjs` already refuses one that does not bracket the fact's own `introduced_in`.

The library-level answer is necessary and is not sufficient, because a bisector run dates the facts
somebody wrote a probe for and leaves every other date exactly as the release note left it. prisma is
bisected, and **five of its thirty-five dated facts have never been executed**: LF5, LF9, LF17, LF20,
LF24. The count for every other bisected library is zero, which is why this went two days without
showing: zod, better-auth and valibot have no such fact, and **BM1's draw re-runs byte-identical
under the corrected rule** (checked, before and after).

The fix is §7's **sixth amendment**, dated 2026-09-10, written before any BM2 assertion existed: rule
1 is enforced on the fact, and a fact with no `measured_range` is excluded by name.

The refused draw is printed here in full rather than deleted. A benchmark that shows only its final
task set cannot be told apart from one that drew until it liked the answer.

```
DRAWN — under the defective library-level rule 1 (pool 26 of 36). NOT the task set.
  task  fact   sev  in        kind               charged?  api
  A1    LF23   S1   7.0.0     removed            no        metrics preview feature
  A2    LF14   S1   7.0.0     removed            yes       engineType
  A3    LF3    S1   7.0.0     removed            no        new PrismaClient({ datasourceUrl })
  A4    LF9    S1   7.0.0     removed            no        prisma.config.ts engine key      <-- never executed
  A5    LF15   S1   7.0.0     renamed            yes       prisma migrate diff --from-schema-datamodel
  A6    LF22   S1   7.0.0     requirement        no        @prisma/client-runtime-utils
  A7    LF7    S1   7.0.0     requirement        yes       prisma.config.ts
  A8    LF21   S1   7.0.0     added              no        accelerateUrl
  A9    LF25   S1   7.0.0     renamed            no        /wasm export path
  A10   LF12   S2   7.0.0     removed            yes       postinstall prisma generate
  A11   LF24   S2   7.0.0     default-changed    no        connection pool defaults         <-- never executed
  A12   LF6    S3   7.0.0     deprecated         yes       provider = "prisma-client-js"
```

**The rule change did not steer the draw, and the printed order is the evidence.** The order inside a
stratum is `sha256("<benchmark_id>:<fact_id>")`, a function of the fact's name alone. Removing three
S1 facts (LF9, LF20, LF5) and one S4 fact (LF17) from the pool therefore **closes gaps and moves
nothing**: S1 read `LF23 LF14 LF3 LF9 LF15 LF22 LF7 LF21 LF25 | LF19 LF16 LF1 LF2 LF10 LF4 LF20 LF5
LF13 LF8` before and reads `LF23 LF14 LF3 LF15 LF22 LF7 LF21 LF25 LF19 | LF16 LF1 LF2 LF10 LF4 LF13
LF8` after — the same sequence with the excluded facts lifted out. Two facts were promoted from the
reserve into the set by that, LF19 and LF35, and neither could have been chosen: nothing about them
was known when the rule was fixed.

## The draw, as `draw.mjs` printed it

Recomputable by anyone:
`node tools/benchmark/draw.mjs --library prisma --subject claude-sonnet-5 --benchmark-id prisma--claude-sonnet-5--bm2--2026-09-10 --class-a 12`

```
Class A draw — prisma--claude-sonnet-5--bm2--2026-09-10
  library            prisma  (bisected 2026-09-07, JOURNAL/074 — 35 probe rows x 11 installed releases (7.0.0 -> 7.10.0); 1 of 12 dated facts corrected; the first ladder that is a CLI and a generated artifact rather than a module import)
  subject            claude-sonnet-5
  measured boundary  6.0.0 (2024-11-28)
  stated cutoff      2026-01  [spread: 2026-01x30 2025-06x1]
  facts.json sha256  140ae707b086617514bc9bc6f5b25350f1fd70799931f37ce3d9751a7d8f4732
  pool               21 of 36 facts eligible

Excluded (15):
  LF5   date never executed: no measured_range (§7 rule 1)
  LF9   date never executed: no measured_range (§7 rule 1)
  LF17  date never executed: no measured_range (§7 rule 1)
  LF18  parked: published in the stated cutoff month (2026-01)
  LF20  date never executed: no measured_range (§7 rule 1)
  LF24  date never executed: no measured_range (§7 rule 1)
  LF26  below the floor: after the stated cutoff (2026-01)
  LF27  no dated introduction
  LF28  below the floor: after the stated cutoff (2026-01)
  LF29  below the floor: after the stated cutoff (2026-01)
  LF30  below the floor: after the stated cutoff (2026-01)
  LF31  below the floor: after the stated cutoff (2026-01)
  LF32  below the floor: after the stated cutoff (2026-01)
  LF33  below the floor: after the stated cutoff (2026-01)
  LF36  parked: published in the stated cutoff month (2026-01)

Strata and quotas (largest remainder, 12 Class A seats):
  S1  pool 16 ( 76.2%)  ->  9 seat(s)
  S2  pool  4 ( 19.0%)  ->  2 seat(s)
  S3  pool  1 (  4.8%)  ->  1 seat(s)

DRAWN — the task set, fixed before any acceptance assertion was written:
  task  fact   sev  in        kind               charged?  api
  A1    LF23   S1   7.0.0     removed            no        metrics preview feature
  A2    LF14   S1   7.0.0     removed            yes       engineType
  A3    LF3    S1   7.0.0     removed            no        new PrismaClient({ datasourceUrl })
  A4    LF15   S1   7.0.0     renamed            yes       prisma migrate diff --from-schema-datamodel
  A5    LF22   S1   7.0.0     requirement        no        @prisma/client-runtime-utils
  A6    LF7    S1   7.0.0     requirement        yes       prisma.config.ts
  A7    LF21   S1   7.0.0     added              no        accelerateUrl
  A8    LF25   S1   7.0.0     renamed            no        /wasm export path
  A9    LF19   S1   7.0.0     requirement        no        ESM and toolchain minimums
  A10   LF12   S2   7.0.0     removed            yes       postinstall prisma generate
  A11   LF35   S2   7.1.0     added              yes       @prisma/sqlcommenter-query-insights
  A12   LF6    S3   7.0.0     deprecated         yes       provider = "prisma-client-js"

  6 of 12 drawn facts have already been charged against this subject by a published battery.
  Both cuts are reported separately in the results (§7): the whole sample, and this subset.

RESERVE — in order, per stratum. A task whose assertion fails its flip test (§9) is
replaced by the next fact in ITS OWN stratum, so the quotas survive the substitution:
  S1 #10  LF16   7.0.0     -         prisma introspect
  S1 #11  LF1    7.0.0     charged   new PrismaClient()
  S1 #12  LF2    7.0.0     -         new PrismaClient({ datasources })
  S1 #13  LF10   7.0.0     charged   package.json prisma key
  S1 #14  LF4    6.6.0     charged   generator client { output }
  S1 #15  LF13   7.0.0     charged   prisma generate --no-engine
  S1 #16  LF8    7.0.0     -         datasource db { url }
  S2 #3  LF11   7.0.0     charged   automatic .env loading
  S2 #4  LF34   7.2.0     -         prisma db push --url

Class N (6) is NOT drawn from this pool. A null task depends on no fact in the pack and is
authored, not selected; its admission gate is the inverse flip test — its acceptance assertion
must be TRUE at every rung of the ladder, including the bottom.
```

**The recorded `facts.json sha256` is the digest of the file's committed form, and it had to be
fixed to be worth recording.** `draw.mjs` hashed the bytes on disk, which on Windows is a hash of
`core.autocrlf` as much as of the facts: this repository's own working tree holds
`data/zod/facts.json` with CRLF and `data/prisma/facts.json` with LF — one was last written by
`git checkout`, the other by a build tool — and `git status` calls both clean, so two clones printed
two digests for the same committed file (zod: `aaebf89…` on disk, `c16082…` as committed). A draw
record exists so a third party can recompute it, so the CR is stripped before hashing. prisma's
`140ae70…` is unchanged by the fix, because that file was already LF; the value above is the same in
both checkouts, which was checked in both.

**Both cuts, as §7 requires.** Whole sample: 12. Previously charged against this subject by a
published battery: **6 of 12** (A2, A4, A6, A10, A11, A12). BM1's figure was 4 of 12. The number is
computed after the draw, is reported here and in the results, and entered nothing.

## Three properties of this set, recorded before any assertion is written

**1. It is one boundary, not twelve.** Eleven of the twelve drawn facts are dated **prisma 7.0.0**
(2025-11-19); the twelfth, A11/LF35, is 7.1.0. The pre-registration chose this pair partly *because*
its window is a major — that is where APIs are removed and renamed, which is the mechanism behind the
one BM1 cell that separated the arms — and the consequence has to be said in the same breath: **the
twelve tasks are twelve probes of a single release**, not twelve independent measurements. A subject
that knows prisma 7 exists can pass all of them for one reason, and a subject that does not can fail
all of them for one reason. BM1's set spanned five distinct releases (4.1.13 … 4.4.0) and was already
weakly correlated this way; BM2 is the limiting case.

What that forbids, fixed now rather than after the numbers arrive: BM2 may report **counts of cells
and counts of tasks**, and may not report any interval, significance claim or "N of 12" figure whose
derivation assumes the tasks are independent draws. The unit that varies independently here is the
subject's knowledge of one release, and the honest sample size for *that* is one.

**2. The smallest stratum has no reserve.** S3 holds exactly one eligible fact, LF6, which is drawn
as A12. If its assertion fails the flip test there is no S3 fact to replace it with. §7's sixth
amendment fixes the answer before the failure can happen: **the seat is dropped, the set ships as
eleven Class A tasks, and the shortfall is stated with its stratum** on `/benchmark`, in the results
file and here. It is not refilled from S1 or S2 — that re-weights the severity mix the quotas exist
to fix — and the quotas are not recomputed against a smaller pool, because a draw recomputed after
seeing which task failed is a draw steered by the tasks. `build-index.mjs` was refusing 11:6 as a
malformed class ratio and now accepts it; both refusals were exercised.

**3. Nine of the twelve are S1.** Against BM1's two of twelve. This is the property the pair was
chosen for: BM1's central result was that a bare Claude Opus 5 routed around eleven of twelve facts,
usually by writing the workaround the task's own requirements described, and a set that is
three-quarters build-breakers is the direct test of whether that survives when the stale answer does
not compile. It is also the property most likely to produce refused tasks at authoring time, and the
S1 reserve is seven deep for exactly that reason.

## A correction to the pre-registration, and the survey re-run under the corrected rule

The pre-registration's first reason for the pair reads *"It is the only pair besides BM1's own that
fills all twelve Class A seats"*. That is true only read as *outside zod*: its own table shows
`zod × Claude Fable 5.1` filling twelve seats as well. The reason to leave zod is the one the same
file gives and is unaffected — inside zod, BM1 already used the widest window there is, and a second
zod benchmark would be a smaller sample of the same measurement.

Every pool figure in that table was computed under the defective rule 1. Re-run 2026-09-10 under the
corrected one, **only the prisma rows move**, and only where the unbisected facts were not already
excluded for another reason:

| library | subject | pool (was → now) | strata now | seats |
|---|---|---|---|---|
| prisma | Claude Sonnet 5 | 26 → **21** of 36 | S1 16 S2 4 S3 1 | 12 |
| prisma | Claude Opus 5 | 11 → 11 of 36 | S2 11 | 11 |
| prisma | Claude Fable 5.1 | 9 → 9 of 36 | S2 9 | 9 |
| prisma | Claude Haiku 4.5 | 0 → 0 of 36 | — | 0 |
| zod / better-auth / valibot | all four subjects | unchanged | unchanged | unchanged |

The three numbers the pair was chosen on survive the correction: it still fills all twelve seats
(21-fact pool), its window is still a major (18 of the 21 eligible facts are dated 7.0.0, spanning
2025-04-08 to 2025-12-17), and its pool is still dominated by build-breakers (S1 **16 of 21**, 76%,
against zod's 3 of 17). The S4 stratum named in the pre-registration as *"an unfillable stratum,
recorded rather than rounded up"* has ceased to exist for a different reason: its single fact, LF17,
is one of the five that were never executed.

## What this leaves — BM2's remaining build order

1. **The acceptance assertions**, twelve of them, each admitted by `flip-test.mjs` against the
   23-rung prisma ladder (6.0.0 … 6.19.0, 7.0.0 … 7.10.0) through the probe file's own `subject()`
   (§9 fifth amendment). Every substitution recorded here as BM1's were.
2. **The six Class N tasks**, authored rather than drawn, and harder on this library than on zod for
   a reason worth naming before anyone writes one: the prisma ladder **crosses a major that changed
   the schema language itself** — 7.0.0 removed `url` from the datasource block — so a Class N
   acceptance assertion that must be true at 6.0.0 *and* at 7.10.0 cannot be satisfied by an artifact
   that spells a datasource block, whichever way it spells it. The probe file's `spell()` renders that
   block per rung, which means a null task on prisma is one whose produced artifact does not contain
   the part of the schema the major changed. That is a real narrowing of what a null task may be, and
   it is a design constraint, not a licence to drop the class: §6 fixes the 2:1 ratio precisely so
   null tasks cannot be quietly dropped when they are inconvenient.
3. **BM2's own predictions**, written after this draw and **before the first arm**, in §10's form.
   BM1's five are BM1's and are not re-registered.
4. **The arms**, §14's transport unchanged.

## Substitutions

Recorded here as they happen, in the order they happen, because a task set that shows only its
survivors cannot be told apart from one that drew until it liked the answer. `draw.mjs` fixed the
reserve; nothing below re-draws anything.

**The order two open seats consume the reserve, fixed 2026-09-10 while two seats were open and
before either substitute was authored.** Refused seats take from their stratum's reserve **in task
order**, not in the order the refusals happened to be discovered. A7's exposure was written down
first (§9's seventh amendment, 2026-09-09, predicted from the shape of its fact), and A2's refusal
was measured first (2026-09-10). Consuming in discovery order would let the sequence in which an
operator happened to author things decide which fact enters the set — the property §7 exists to
remove — so the rule is the one that depends on nothing an operator does.

| seat | drawn fact | outcome | substitute |
|---|---|---|---|
| A2 | LF14 (S1, `engineType`) | **REFUSED 2026-09-10**, §9 eighth amendment: both artifacts have the same row, `............+++++++++++`. prisma 7 ignores `engineType` rather than rejecting it, so the belief costs nothing executable at the graded release. Kept as `tools/benchmark/tasks/prisma/A2.lf14.*`, `prompts/sent/benchmark-prisma-a2-lf14-refused.txt` and `A2_LF14` in `tools/benchmark/tasks/prisma.mjs`, so the refusal re-runs. | **S1 #10, LF16** (`prisma introspect`) — **authored and ADMITTED 2026-09-10**, `falling @7.0.0`, correct `+++++++++++++++++++++++` / stale `++++++++++++...........` |
| A4 | LF15 (S1, `prisma migrate diff` inputs) | **REFUSED 2026-09-10**, by the two-boundary refusal (§9 second amendment's `measuredShape`): the correct solution **rises** at 7.0.0 and the stale artifact **falls** at 7.0.0 — `............+++++++++++` against `++++++++++++...........`, complementary rows on the same release. A rename gives the NEW spelling a version dependence of its own: `--from-schema` is `unknown or unexpected option` on all twelve 6.x rungs, and `--from-schema-datamodel` is answered from 7.0.0 with "`--from-schema-datamodel` was removed. Please use `--[from/to]-schema` instead." Kept as `tools/benchmark/tasks/prisma/A4.lf15.*`, `prompts/sent/benchmark-prisma-a4-lf15-refused.txt` and `A4_LF15` in `tools/benchmark/tasks/prisma.mjs`, so the refusal re-runs. | **S1 #11, LF1** (`new PrismaClient()`) — **authored and ADMITTED 2026-09-10**, `falling @7.0.0`, correct `+++++++++++++++++++++++` / stale `++++++++++++...........` |
| A6 | LF7 (S1, `prisma.config.ts` required) | **REFUSED 2026-09-10**, by the same two-boundary refusal as A4 and for the same reason one layer out: a **relocation** names a destination that does not exist below the release that required it. The correct solution **rises** at 7.0.0 and the stale artifact **falls** at 7.0.0 — `............+++++++++++` against `++++++++++++...........`. The datasource URL moves out of `schema.prisma` and into `prisma.config.ts`, which is not read at all at 6.0.0 and is rejected by the release's own loader at 6.6.0 and at 6.19.0 (sentences measured at those rungs; the other nineteen are verdicts only — see the table below). Kept as `tools/benchmark/tasks/prisma/A6.lf7.*`, `prompts/sent/benchmark-prisma-a6-lf7-refused.txt` and `A6_LF7` in `tools/benchmark/tasks/prisma.mjs`, so the refusal re-runs. | **S1 #12, LF2** (`new PrismaClient({ datasources })`) — taken from A7 on 2026-09-10 under "task order, not discovery order"; see the note below. **Authored and ADMITTED 2026-09-10**, `falling @7.0.0`, correct `+++++++++++++++++++++++` / stale `++++++++++++...........` (this cell read "not yet authored" until 2026-09-11; the section below has always recorded the admission). |
| A7 | LF21 (S1, `accelerateUrl`) | **Due for refusal**, recorded 2026-09-10 before its assertion exists (§9 seventh amendment, second guard: `added` at 7.0.0 is a rising task at the major floor). It will still be authored and put through the gate, so the refusal is evidence rather than a prediction — the rule BM1's A2/LF4 set. **REFUSED 2026-09-10 — by the two-boundary rule, not the guard the prediction named**: correct `............+++++++++++` against stale `++++++++++++...........`. With the stale artifact withheld, the seventh-amendment guard refuses the same correct row — measured too. Kept as `tools/benchmark/tasks/prisma/A7.lf21.*`, `prompts/sent/benchmark-prisma-a7-lf21-refused.txt` and `A7_LF21` in `tools/benchmark/tasks/prisma.mjs`; see the section at the end of this record. | **S1 #13, LF10** (the `prisma` key in `package.json`). **Moved down twice on 2026-09-10**: once when A4 opened a seat above it in task order, and again when A6 did; see the notes below. **REFUSED 2026-09-11** on two boundaries at two different releases (correct rises at 6.19.0, stale falls at 7.0.0). → **S1 #14, LF4** (the `prisma-client` generator requires `output`) — **authored and ADMITTED 2026-09-11**, `rising @6.6.0`, correct `......+++++++++++++++++` / stale `.......................`; see the last section of this record. |
| A8 | LF25 (S1, `/wasm` renamed to `/edge`) | **REFUSED 2026-09-11**, §9 seventh amendment's second guard (a rising task whose boundary is a major's first rung): correct `............+++++++++++` against stale `.......................`. `./edge` is in the export map on every rung, but below 7.0.0 it is the Accelerate entry point and refuses an adapter; the stale `/wasm` import fails in Node on every rung, so only the correct row moves. Kept as `tools/benchmark/tasks/prisma/A8.lf25.*`, `prompts/sent/benchmark-prisma-a8-lf25-refused.txt` and `A8_LF25` in `tools/benchmark/tasks/prisma.mjs`; see the section at the end of this record. | **S1 #15, LF13** (`prisma generate --no-engine`) — not yet authored. |

**The S1 reserve is seven deep and four of its entries are now spoken for** — LF16 and LF1
are in the set, LF2 is named for A6 and LF10 for A7 (both reassigned 2026-09-10 by A6's refusal,
under the same task-order rule that moved A7 once already). Three remain: LF4, LF13, LF8.

**A4's refusal moved a substitute that had already been written down, and that is the rule working
rather than the rule failing.** When the order above was fixed, two seats were open (A2 and A7) and
A7 was assigned S1 #11, LF1. A4's refusal on 2026-09-10 opened a third seat **above A7 in task
order**, so under "task order, not discovery order" the open set {A4, A7} consumes {LF1, LF2} as
A4 → LF1 and A7 → LF2. The alternative — letting A7 keep LF1 because its exposure was noticed
first — is precisely discovery order under another name, and it would mean the sequence in which
the operator happened to author things decided which fact entered the set at which seat. The
assignment is a function of three things only: which seats are open, task order, and the reserve
order `draw.mjs` fixed. Nothing was re-drawn and no fact left or entered the reserve.
**JOURNAL/123's measurement is unaffected**: it established that A3 grades LF3 and not LF1, which
matters because LF1 enters the set — and LF1 still does, at seat A4 rather than at seat A7.

**What A4 measured that generalises to the seats still to be authored, and it is a question with
both answers already in this set.** `change_kind` does not predict the two-boundary shape; what
predicts it is whether **the correct answer's API exists below the boundary**. Both of BM2's drawn
`renamed` facts were checked against that question and they answer it in opposite directions:

| fact | seat | new spelling below 7.0.0? | consequence |
|---|---|---|---|
| LF15 `--from-schema` / `--to-config-datasource` | A4 | **no** — `unknown or unexpected option` at 6.0.0 and 6.19.0 | correct solution rises → two boundaries → **refused** |
| LF25 `@prisma/client/edge` (was `/wasm`) | A8 | **yes** — `./edge` is in the export map at 6.0.0, 6.19.0, 7.0.0 and 7.10.0, and `./wasm` is there at 6.0.0 and 6.19.0 and gone from 7.0.0 | correct solution can be flat-passing → the falling shape is available. **Refuted 2026-09-11 by the survey run before A8 was authored** (section at the end of this record): below 7.0.0 `./edge` is the Accelerate entry point and refuses an adapter on all twelve 6.x rungs, so the correct answer rises at 7.0.0 and A8 was refused. The key existed; its meaning did not. |

So A8 is not exposed by A4's refusal, and it is not exempt from the gate either: it is authored and
gated like every other seat. What is recorded here is the **question** — does the correct answer's
API exist below the fact's release — not a prediction of any seat's outcome, because a seat's
outcome is what its gate run says.

**The instrument A4 needed, kept with the refusal because it is reusable.** A4's graded verdict is
an ABSENCE — no rejection in the CLI's output — and at 7.10.0 the correct invocation's entire
output is the empty string, which a blind instrument produces too. So the assertion runs
`migrate diff --sp-canary-unknown` in the same directory first and **throws** if that is not
rejected: an error cell, the harness's own failure, never a `false`. It was made to fail against the
defect it names before it was trusted (JOURNAL/118's rule) — a stub subject returning `""` to
everything throws, one that rejects only the canary returns `true`, one that rejects the real
invocation returns `false` with the toolchain's own words.

**One thing measured on the way past, recorded because a later seat will meet it.** At 7.10.0, with
no `prisma.config.ts` in the directory, `prisma migrate diff --from-schema schema.prisma --to-empty
--script` prints **nothing** and exits 0, and `--exit-code` reports 0 — "empty" — for a schema
holding one model; with a config file present the same invocation prints the `CREATE TABLE` script
and exits 2. So any prisma 7 task whose criterion is "the diff produced SQL" needs a
`prisma.config.ts`, which is LF7 — drawn as A6, dated at the same release. That is the fourth door
in JOURNAL/119's list, and it is why A4's criterion is the narrow one.
 S2's reserve is two deep and untouched; S3 has none, and the rule for that is §7's
sixth amendment — the seat is dropped and the shortfall is stated with its stratum.

**LF16 was admitted without the gate needing a ninth amendment, and what it cost instead was a
narrower graded criterion, recorded here because the narrowing is a property of the ladder rather
than of the task (2026-09-10, JOURNAL/119).** LF16 is a fact about a CLI command's existence, and the
natural criterion — *the command reaches introspection* — needs a connection string. There is
nowhere on this ladder to put one that is not another dated fact: a `url` in the datasource block is
rejected from 7.0.0 (LF8, measured on the ladder: `P1012 … no longer supported in schema files`), a
`prisma.config.ts` is mandatory from 7.0.0 and is a parse error at 6.19.0 (LF7, measured), and
`db pull --url` is a two-release window *inside* the ladder (LF16's own note; LF34). Each of the
three would have put a second boundary in the task. So A2 grades the one thing LF16 claims — the
installed CLI recognises the command — in an empty directory, and the prompt states that criterion
in those words. **The same three-way block will be met by every drawn fact whose natural criterion
needs a live datasource**, which is why it is written here and not only in the assertion.

**One thing A2's refusal says about the rest of the set, and it is a citation rather than a
prediction.** LF14 was refused because the library *ignores* the stale spelling rather than rejecting
it. One other drawn fact already carries that property in its own row: **A12 (LF6, the
`prisma-client-js` generator provider)**, whose note in `data/prisma/facts.json` reads that what its
7.0.0 dates is the vendor's deprecation announcement, which *has no executable shadow* — the CLI
accepts the provider and prints no deprecation warning at 7.0.0 or at 7.10.0. That is LF14's shape,
and it is written down here before A12's assertion exists. A12 is not dropped ahead of its gate run:
it will be authored and refused on evidence like every other, and if it is refused its stratum has no
reserve — which is the case §7's sixth amendment already decided, the seat dropped and the shortfall
stated with its stratum. No other drawn fact is claimed here to have the property; each task's own
gate run is the measurement.

**A3 (LF3, `datasourceUrl`) authored and ADMITTED 2026-09-10 — `falling @7.0.0`, correct
`+++++++++++++++++++++++`, stale `++++++++++++...........` — and the seat needed no amendment. What
it needed was a harness the subject did not have and a reference artifact that is deliberately not
the idiomatic answer.**

- **The instrument is the constructor, run against a real generated client.** LF3 is a
  constructor-option fact: nothing in the CLI, the schema language or the shipped bytes can be asked
  whether *constructing a client this way* works, which is what the fact claims. So
  `tools/audit/probes/prisma.mjs` gained `runWithGeneratedClient(source)` — it generates a client
  once per rung from a schema the harness fixes, writes the produced module beside it and imports it.
  Three harness choices had to be measured rather than assumed, because each could have put a second
  boundary in every task that uses it: `provider = "prisma-client-js"` is the only generator provider
  that exists at 6.0.0 and still generates at 7.10.0; `previewFeatures = ["driverAdapters"]` is
  needed on 6.x and is **still a known preview-feature name at 7.10.0** — which is exactly what LF23
  is about, so it was checked and not supposed; and the schema is identical at every rung apart from
  `spell()`'s datasource block.
- **The reference is the pool form, and that is the load-bearing choice.** prisma 7's own docs show
  `new PrismaPg({ connectionString })`. That spelling has a boundary of its own — `@prisma/adapter-pg`
  6.0.0 throws `PrismaPg must be initialized with an instance of Pool` and the object form starts
  passing at 6.6.0 — and the boundary belongs to the **adapter package**, not to prisma. A falling
  task's correct solution must pass at every rung, so the object form makes the task a two-boundary
  task. Demonstrated rather than argued: with the object-form reference committed in its place, the
  gate refuses A3 with `correct .....++++++++++++++++++` and *both artifacts carry a version
  dependence*. The pool form passes all twenty-three rungs and is a correct answer at 7.10.0, which
  is the only thing a falling task's correct solution is for. **Subjects are graded at 7.10.0 alone,
  where both spellings pass**, so a reply using the documented object form is graded correct.
- **It grades LF3 and not LF1, and both facts are dated 7.0.0.** The separating measurement:
  `{ adapter, datasourceUrl }` — an answer that satisfies LF1's adapter requirement and still holds
  LF3's belief — fails at 7.0.0 and 7.10.0 with `PrismaClientConstructorValidationError: Unknown
  property datasourceUrl provided to PrismaClient constructor`, while the adapter alone passes. The
  option is rejected on its own account. This matters for the set, not only for A3: **LF1 is A7's
  named substitute**, so two seats would otherwise have measured one belief.
- **The three-door block above was met and answered the same way A2 answered it.** A3 needs a
  connection string too. It gets a literal `DATABASE_URL` that resolves to nothing, and that is safe
  only because construction is lazy on every rung of this ladder — measured; no rung reaches a
  socket. The prompt says the grader has no database and that nothing is connected.
- **The retry feedback keeps the toolchain's words and drops node's echo of the bundle.** A failing
  run at 7.10.0 prints 2,753 bytes, of which 1,514 are node's preamble echoing the minified
  `@prisma/client` source line the throw came from — not a word the toolchain said. The detail begins
  at the first line that names an error and keeps everything after it, stack included: 790 bytes,
  with `Unknown property datasourceUrl provided to PrismaClient constructor` first. Where no such
  line exists the whole output is kept.
- **A1 and A2 do not move.** Re-gated on the same twenty-three rungs after the probe-file change,
  both `flip_test` blocks and the gate's whole stdout/stderr byte-identical to the run captured
  before the first edit. Gate selftest 46, runner selftest 42, all five `--check` builds green.

### A4 = LF1, and the property of the SET it forced into the open (2026-09-10)

A4's seat, refused with LF15 earlier the same day, is filled from the S1 reserve in task order with
**LF1** — *"constructing the client with no arguments is no longer supported; Prisma 7 requires a
driver adapter"* — and the gate admits it: `falling @7.0.0`, correct `+++++++++++++++++++++++`,
stale `++++++++++++...........`, contiguous, on the same twenty-three rungs. The stale artifact is
LF1's own `stale_code`. **It passes below the boundary only because the harness's schema carries a
connection string there** — `spell()` injects a literal `url` into every 6.x datasource block,
which is what a reader on that release had to write too — so the pass is the fact's own claim
(the client reads the datasource out of the schema) rather than an artefact of a permissive schema.

**The property: A3 and A4 are graded by ONE acceptance function, and their reference artifacts are
byte-identical.** `tools/benchmark/tasks/prisma.mjs` says so structurally —
`constructsClient(factId)` is called twice — instead of shipping the same function twice under two
names. LF1 and LF3 are two spellings of one removal, dated at one release, and at 7.10.0 they have
one correct answer: pass a driver adapter. An assertion that could tell a correct A4 answer from a
correct A3 answer would have to grade the source text, which §9 forbids everywhere else.

**What that does and does not imply, measured at two rungs rather than reasoned about.** The first
draft of this note claimed the two cells "cannot vary independently", and the measurement corrected
it before it was committed:

```
                       A3's assertion        A4's assertion
  6.19.0  A3.stale     PASS                  PASS
          A4.stale     PASS                  PASS
  7.10.0  A3.stale     FAIL                  FAIL
          A4.stale     FAIL                  FAIL
```

with two *different* sentences behind the four failures —
`PrismaClientConstructorValidationError: Unknown property datasourceUrl provided to PrismaClient
constructor.` for A3's artifact, and `PrismaClientInitializationError: PrismaClient was instantiated
without any options. A driver adapter is required to connect to your database.` for A4's. So:

- **The graders separate the two stale beliefs not at all.** Either stale answer fails either seat.
- **The cells are still not one cell**, and A3's own committed measurement is the counter-example:
  `{ adapter, datasourceUrl }` satisfies LF1 and still holds LF3's belief, so a subject writing that
  for A3's prompt and `{ adapter }` for A4's **fails A3 and passes A4**. Independence between these
  cells lives entirely in what each prompt draws out — A3's asks for a client *"configured to use
  that connection string"*, which is what `datasourceUrl` was the shorthand for; A4's names no
  override at all, which is the case LF1's `stale_belief` is about.
- **The retry channels differ even where the verdicts cannot.** The two constructor sentences above
  are what a failing round hands back (§9's "quote the toolchain"), so `rounds_to_pass` can
  differ between the seats for reasons that are the subject's.

**What this costs the results, fixed now and before any arm has run.** Property 1 of this set already
forbids any interval, significance claim or "N of 12" figure that assumes the twelve tasks are
independent draws, on the ground that eleven of them probe one release. This is that constraint one
level sharper and at seat level: **A3 and A4 — and A7 if LF2 is authored into it — are one
instrument, and BM2's published counts must name the group.** The rule is not "drop the seats": the
reserve was fixed before any of this was known, and refusing a seat because a seat authored earlier
resembles it is discovery order deciding the set, which is the property §7 exists to remove. The
rule is that the results say which seats share an instrument, in the same breath as any count over
them.

**Nothing else moved.** A1, A2 and A3 re-gated on the same ladder after the assertion file was
refactored: all admitted, every profile byte-identical to the run captured before the edit. Gate
selftest 46, runner selftest 42, MCP selftest 54, all five `--check` builds green. No dataset count
moved, because admitting a benchmark task publishes no finding.

**What is left of BM2:** eight drawn Class A assertions plus A7's substitute (LF2), the six Class
N tasks, BM2's predictions, then the arms. Four Class A seats are settled and filled: A1 (LF23),
A2 (LF16), A3 (LF3) and A4 (LF1) admitted — two of the four from the reserve, after the facts
drawn at those seats were refused by the gate.

## A5 (LF22, `@prisma/client-runtime-utils`) authored and ADMITTED 2026-09-10 — `falling @7.0.0`

**The seat is the first of BM2's to be filled by its own drawn fact since A1, and the second to cost
the protocol no amendment.** Correct `+++++++++++++++++++++++`, stale `++++++++++++...........`,
contiguous, on the same twenty-three installed releases as A1–A4.

**The fact had no artifact, and finding one is the whole of what this seat cost.** LF22's
`correct_code` is an `npm install` line, its `code_lang` is `bash`, and its `stale_code` is **null**:
what it claims is a property of a project's dependency LIST, and **no artifact this harness accepts
can change what is installed on a rung**. The fact's own probe reads the installed tree
(`s.installed("@prisma/client-runtime-utils")`), which an artifact cannot move, so the seat looked
like it had only two roads and both are dead ends:

- **A list graded by "does every package you name resolve on this release"** puts the version
  dependence in the CORRECT artifact — it names a package that did not exist below 7.0.0 — which is
  a rising task whose boundary is the major's own first rung, refused by name under §9's seventh
  amendment, second guard. (It is also blind twice over on this ladder: `installed("prisma")` is
  false at every rung, because the bisector installs the library under a per-rung alias.)
- **A project graded by "the generated client loads"** separates nobody.
  `@prisma/client-runtime-utils` is a declared dependency of `@prisma/client` at 7.0.0 and 7.10.0,
  so on any npm tree that installed the client it is present **without anyone naming it** — and the
  generated client imports and loads at 7.10.0 either way (measured: status 0, `LOADED function`).
  Both artifacts would have had the same row, which is A2/LF14's refusal (§9 eighth amendment).

**The instrument that exists is the generator's own manifest, and it is a better primary source than
the release note.** `prisma generate` with `provider = "prisma-client-js"` and
`output = "./generated/client"` writes a `package.json` **beside the generated client**, and that
file declares what the generated code needs. Measured on all twenty-three rungs before the assertion
was written:

| rungs | generation | generated client's `package.json` → `dependencies` |
|---|---|---|
| 6.0.0 … 6.19.0 (12) | succeeds | `{}` — declares nothing |
| 7.0.0 … 7.10.0 (11) | succeeds | `{"@prisma/client-runtime-utils": "<that release>"}` |

Contiguous, at exactly the release the bisector dated LF22 to. So the graded criterion is
**containment**: every package the generated client's own manifest declares as a dependency appears
in the answer's list. Extras are not penalised; below 7.0.0 the criterion is **vacuous**, which is
precisely why the correct answer is flat-passing and the stale one falls — the falling shape §9's
seventh amendment buys, rather than the rising one it refuses.

**What the assertion does not grade,** stated in the prompt in those words: whether the named
packages exist on npm (nothing here reaches the network), whether the project would install, whether
the generated client then loads, and whether it could reach a database.

**The blindness guard, and it is `identifiers.mjs`'s rule in a fourth instrument.** The graded
verdict below 7.0.0 is an **absence** — the manifest declares nothing — and a read that missed the
file returns the same value. Four failures therefore **throw** (an error cell, the harness's own
failure, never a `false`): the generator not running, generation not reporting a generated client, no
manifest where the generator writes one, and a manifest that does not parse. A fifth is a
**witness**: the manifest must carry a `main`, which is `index.js` on all twenty-three rungs, so a
`package.json` belonging to something else cannot supply an empty dependency list that would be
published as an absence. Each of the five was made to fail against the defect it names, against stub
subjects, before the assertion was trusted (JOURNAL/118's rule).

**One additive change to the probe file, and it is the only one.** `generateProject` returned
`stdout` and the NAMES of the files generation wrote; A5's question is what the generator wrote
INTO one of them, so it now also returns `read(rel)`. `stdout` and `names` are untouched, and
A2_LF14 — the only other caller — re-gates byte-identically.

**Nothing else moved.** A1–A4 re-gated on the same ladder after the probe-file change: all admitted,
every profile byte-identical to the run captured before the edit. Gate selftest 46, runner selftest
42, MCP selftest 54, identifiers selftest 35, all five `--check` builds green. Counts unmoved at 161
runs / 167 findings (160 chargeable) over 8 libraries — correct for a session that publishes no
finding. The S1 reserve is untouched at four unspoken-for entries (LF10, LF4, LF13, LF8); LF2 is
still named for A7.

## A6 (LF7, `prisma.config.ts` is required) authored and REFUSED 2026-09-10 — two boundaries

The second seat this gate has refused on the two-boundary rule (§9 second amendment's
`measuredShape`), and the first where the refusal was **predicted from the fact's own statement
before the artifacts were written** and then measured anyway, because a prediction is not evidence.
Measured rows on the same twenty-three installed releases as A1–A5:

```
  REFUSE A6   A  LF7   falling   @7.0.0
         correct  ............+++++++++++
         stale    ++++++++++++...........
         both artifacts carry a version dependence — the correct solution rises and the stale one
         falls, so the task has two boundaries and the results could not say which one it measured
```

**What generalises, and it is A4's lesson one layer out: a fact that RELOCATES a required input
cannot have a flat-passing correct artifact.** A4/LF15 relocated an input across **flag names** (a
rename); LF7 relocates one across **files** — the datasource URL moves out of `schema.prisma` and
into `prisma.config.ts`. In both cases the correct answer names a destination that does not exist
below the release that required it, so the correct answer rises exactly where the stale one falls,
and the two rows are complementary on 7.0.0. The test that predicts this was already written down
for renames after A4 — *does the correct answer's API exist below the boundary?* — and A6 is the
first confirmation of it on a fact that is not a rename. `change_kind` predicts nothing here and
this set now proves it in both directions: **LF7 and LF22 are both `requirement` facts dated 7.0.0,
and A5 (LF22) was admitted `falling` while A6 (LF7) is refused.**

**The destination is absent below the boundary in TWO different ways, and both were measured rather
than argued** — which matters, because a single uniform failure below a boundary is exactly what a
broken install looks like (JOURNAL/108's dropped rung) and two distinct, dated failure modes are
not:

The gate measured a verdict on every one of the twenty-three rungs; the **sentences** below were
read at the four rungs named, and the other nineteen are recorded as verdicts only — a message is
quoted here where it was seen and nowhere else.

| rung | what the CLI says to the correct project | what it means |
|---|---|---|
| 6.0.0 | `P1012 ... Argument "url" is missing in data source block "db"` | the config file is not looked for at all, and a 6.x datasource block without a `url` is invalid |
| 6.6.0 | `Failed to parse config file at ...prisma.config.ts` | a config file IS looked for, and this release's loader rejects this one |
| 6.19.0 | `Failed to parse syntax of config file at ...prisma.config.ts` | the same, with that release's own wording |
| 7.0.0 and 7.10.0 | `Loaded Prisma config from prisma.config.ts.`, then `P1001 Can't reach database server at localhost:1` | the configuration is found, read and **dialled** |

and the stale project's row is the fact's own claim in both halves: accepted and used on every 6.x
rung (`Datasource "db": PostgreSQL database "appdb" ... at "localhost:1"`, then `P1001`), rejected
from 7.0.0 with `The datasource property 'url' is no longer supported in schema files. Move
connection URLs for Migrate to prisma.config.ts ...`. From 6.19.0 the CLI additionally warns that
`package.json#prisma` is deprecated and will be removed in Prisma 7, and still honours it.

**A constraint on this gate's ladder that A6 is the first seat to pay for, and it is the harness's
and not prisma's.** The idiomatic `prisma.config.ts` is `import { defineConfig } from 'prisma/config'`.
On this ladder each release is installed under a **per-rung alias** (`prisma-7-10-0`), so that
specifier resolves on **no rung, 7.10.0 included**, and the CLI reports it as a config file it could
not load — `Failed to load config file ... Cannot find module 'prisma/config'` — a **uniform
failure with the shape of a fact**. A4.lf15.reference.mjs recorded the rule for an `argv` artifact
("an artifact reaching for the literal name `prisma` would resolve nothing on every rung"); this is
the first artifact where the idiomatic answer *is itself an import*, so the committed reference is
the same configuration as a plain default export, measured to be loaded and used at 7.0.0 and
7.10.0. `rung.mjs`'s layout table already prefers `per-rung-real` for exactly this reason, and
`LAYOUT_ORDER` in the gate puts it first; the prisma ladder in use is `per-rung-alias`, which is the
bisector's. **A seat whose correct answer must import from the library by name needs the real-name
layout**, and that is now a known cost rather than a surprise — recorded here for the seats still to
be authored.

**The instrument added for this seat, `inProjectRaw`.** `inProject` writes a project's files
through `spell()`, which injects a literal connection string into any 6.x datasource block that has
none. For a task that is *about where the connection string lives*, that hands the answer back the
very thing the fact says moved, and a pass below the boundary would be the harness's rather than the
answer's — JOURNAL/127's rule with its sign flipped. `spell()`'s own second rule already said so
("a probe ABOUT the datasource block must not go through it"); `validateRaw` was that unspelled path
for one schema and there was none for a whole project directory. The change is additive: `inProject`
is untouched, and A1–A5 re-gate with every profile and the gate's whole stdout and stderr
**byte-identical** to the run captured before the first edit.

**The seat, and it moves a substitute that had already been written down — for the second time, by
the same rule.** Refused seats consume the S1 reserve **in task order**, never in the order refusals
were discovered. A6 opens a seat **above A7** in task order, so the open set {A6, A7} consumes
{LF2, LF10}: **A6 → LF2** (`new PrismaClient({ datasources })`), **A7 → LF10** (the `prisma` key in
`package.json`). Nothing is re-drawn and no fact leaves or enters the reserve; the assignment stays a
function of three things only — which seats are open, task order, and the reserve order `draw.mjs`
fixed.

**Two consequences of that assignment, both recorded now rather than when they are discovered.**
- **The shared-instrument group gains a third seat, and its membership is a property of the
  substitution order rather than of the facts.** JOURNAL/127 recorded that A3 (LF3) and A4 (LF1) are
  graded by one acceptance function, and named "A7 if LF2 is authored into it" as the possible third.
  That third seat is now **A6**. Any published count over BM2's tasks must name the group, which is
  the rule that entry fixed before any arm ran; only the seat letter changed.
- **A7 → LF10 is a project-layout fact, and the instrument this refused seat leaves behind is the one
  it needs.** LF10 is also a relocation — a custom schema path and the seed command move from
  `package.json` to `prisma.config.ts` — so the question A6 and A4 answer is **open against it and is
  recorded as a question, never as a prediction of its outcome**: does LF10's correct answer name a
  destination that exists below 7.0.0? It will be authored and put through the gate either way.
- **The same question stands against LF8**, still unspoken-for in the reserve (`datasource db { url }`),
  which is the same relocation as LF7 stated from the other side. If a seat ever reaches it, this is
  the refusal it is due for.

**The S1 reserve after A6: five entries spoken for** — LF16 (A2) and LF1 (A4) in the set, LF2 named
for A6, LF10 named for A7. Three remain unspoken-for: **LF4, LF13, LF8**.

**Every guard in the refused assertion was made to fail against the defect it names before it was
trusted** (JOURNAL/118's rule): eleven checks, ten of them offline against stub subjects — a blind
CLI throws rather than returning `false`, a CLI that dials a host the answer did not name returns
`false` with the toolchain's own words, an answer with no `files` map, an empty one, a nested path,
a path escaping the project directory, and non-string contents are each named in the detail, and the
two artifacts of the task are shown to land in different directories. **The eleventh needed a real
rung and it is the one that changed the assertion:** a canary sharing the answer's own directory is
taken down *by the answer's own config file* at 6.6.0 — prisma loads `prisma.config.ts` before it
parses the command — so the assertion would have **thrown** where the honest verdict is `false`,
reporting the answer's defect as the harness's. A4_LF15's canary shares the graded directory and is
right to, because its verdict is an absence in a flag parser. A6_LF7's runs in an empty directory,
where the same canary is rejected on all twenty-three rungs (measured).

**Nothing else moved.** Gate selftest 46, runner 42, MCP 54, identifiers 35, all five `--check`
builds green. Counts unmoved at 161 runs / 167 findings (160 chargeable) over 8 libraries — correct
for a session that admits no task and publishes no finding.

**What is left of BM2:** five drawn Class A assertions (A8–A12), A7's own drawn fact LF21 — which is
authored and put through the gate before its substitute, so its refusal is evidence rather than a
prediction — the two named substitutes (A6 → LF2, A7 → LF10), the six Class N tasks, BM2's
predictions, then the arms.

## A6 → LF2 (`new PrismaClient({ datasources })`) authored and ADMITTED 2026-09-10 — `falling @7.0.0`

**The seat is filled from the S1 reserve in task order, as A6's refusal assigned it (A6 → LF2), and
it cost the protocol no amendment.** Correct `+++++++++++++++++++++++`, stale
`++++++++++++...........`, contiguous, on the same twenty-three installed releases as A1–A5. LF2:
*"The `datasources` constructor option is gone. Overriding the connection string at construction
time is done by configuring the driver adapter you now have to pass anyway."*

**The survey ran before any task file existed** (step 4c's discipline): five candidate artifacts
through the probe file's own `runWithGeneratedClient`, on all twenty-three rungs, with the variable
the draft prompt names set in the process environment.

```
                          6.0.0 ........................ 7.10.0
  stale, prompt's var     ++++++++++++...........
  stale, fact's var       ++++++++++++...........   (LF2's stale_code verbatim, DATABASE_URL)
  correct, pool form      +++++++++++++++++++++++
  adapter + datasources   .......................
  correct, object form    .....++++++++++++++++++
```

Sentences, quoted only at the rungs they were read at (6.0.0, 6.6.0, 6.19.0, 7.0.0, 7.10.0):

| artifact | 6.x | 7.0.0 and 7.10.0 |
|---|---|---|
| stale | constructs | `PrismaClientConstructorValidationError: Unknown property datasources provided to PrismaClient constructor.` |
| adapter + datasources | `PrismaClientInitializationError: Custom datasource configuration is not compatible with Prisma Driver Adapters. Please define the database connection string directly in the Driver Adapter configuration.` | the same unknown-property sentence |
| object form | `TypeError: PrismaPg must be initialized with an instance of Pool` at 6.0.0; passes from 6.5.0 | passes |

**It grades LF2 and not LF1**, by the measurement that separated A3 from LF1: the answer that
satisfies LF1 and still holds LF2's belief — an adapter *and* `datasources` — fails at the graded
release on the option's own account. What A3's measurement did not have is the 6.x half: the same
pairing fails on every 6.x rung too, with a different sentence. **The pairing was never an answer on
this ladder** — before 7.0.0 prisma refused the two together, and from 7.0.0 it refuses the option
alone.

**The harness had to set the variable the prompt names, and that was measured rather than assumed.**
A6's prompt asks for a *second* client, pointed at a read replica whose connection string is in
`REPLICA_DATABASE_URL` — LF2's `stale_belief` is about pointing one client at a *different*
database. With that variable unset, LF2's own stale artifact fails at 6.0.0 and 6.19.0 with
`Invalid value undefined for datasource "db" provided to PrismaClient constructor.`: a false below the
boundary that is the harness's, which would have made the stale row flat-failing and the task
refused as having no boundary. `runWithGeneratedClient` now sets it beside `DATABASE_URL`. Additive:
A3 and A4 read only `DATABASE_URL`, and the whole gate — A1–A5 — re-runs with stdout and stderr
**byte-identical** to the run captured before the first edit, apart from A6's own three lines and the
count.

**The shared-instrument group is now three seats — A3, A4, A6 — graded by one function,
`constructsClient`, called with three fact ids.** The cross-table, measured through the real
assertion functions:

```
                         A3's assertion   A4's assertion   A6's assertion
  6.19.0  A3.stale       PASS             PASS             PASS
          A4.stale       PASS             PASS             PASS
          A6.stale       PASS             PASS             PASS
  7.10.0  A3.stale       FAIL             FAIL             FAIL
          A4.stale       FAIL             FAIL             FAIL
          A6.stale       FAIL             FAIL             FAIL
```

(all three references pass all three assertions at both rungs), with three different sentences
behind the 7.10.0 failures — `Unknown property datasourceUrl ...` (A3's stale), `PrismaClient was
instantiated without any options. A driver adapter is required ...` (A4's) and `Unknown property
datasources ...` (A6's). So the graders separate the three stale beliefs not at all; the retry
channels differ where the verdicts cannot; and the independence between the three cells lives
entirely in what each prompt draws out — A3 asks for a client *configured to use* the one connection
string, A4 names no override, A6 asks for a second client on a second database. The rule this record
fixed at A4 stands unchanged: **any published count over BM2's tasks names the group.**

**The reference reads the prompt's variable.** A3 and A4 share reference bytes; A6's are the same
shape with `REPLICA_DATABASE_URL` in place of `DATABASE_URL`, because that is the correct answer to
the prompt as asked. The grader cannot see the difference — no connection is made on any rung — and
the prompt says so: which of the two databases the client would reach is not graded.

**A correction to the A3 section above, recorded here rather than edited into it.** That section
says the object form `new PrismaPg({ connectionString })` "starts passing at 6.6.0", and prints the
gate row `.....++++++++++++++++++` beside it. The row was right and the sentence was not: the sixth
rung is **6.5.0**. This survey measured the same row independently. Nothing depended on the figure —
A3's and A4's references are the pool form, which passes on all twenty-three rungs, and the arms are
graded at 7.10.0 — but it was a published date, and it is corrected in the two reference artifacts'
comments, in DISTRIBUTION.md and in JOURNAL/133. JOURNAL/123, which repeats it, is append-only and
keeps it.

**The previously-charged subset, reported as §7 requires — and moved three times by substitution,
never by choice.** The drawn set had 6 of 12 (A2, A4, A6, A10, A11, A12). A2 (LF14, charged → LF16,
not) made it 5; A4 (LF15, charged → LF1, charged) left it at 5; A6 (LF7, charged → LF2, not) makes it
**4 of 12 as the set stands** — A4, A10, A11, A12 — with A7's named substitute LF10 charged and A7–A12
not yet authored. This record had printed only the drawn figure; the count is a result and an input
to nothing.

**The S1 reserve after A6:** LF16 (A2), LF1 (A4) and LF2 (A6) are in the set; LF10 is named for A7;
three remain unspoken-for — **LF4, LF13, LF8**.

**Nothing else moved.** Gate selftest 46, runner 42, MCP 54, identifiers 35; all five `--check`
builds green. Counts unmoved at 161 runs / 167 findings (160 chargeable) over 8 libraries — correct
for a session that admits a benchmark task and publishes no finding.

**What is left of BM2:** A7's own drawn fact LF21 (authored and gated before its substitute LF10, so
its refusal is evidence rather than a prediction), five drawn Class A assertions (A8–A12), the six
Class N tasks, BM2's predictions, then the arms. Six of twelve Class A seats are filled and admitted,
three of them from the reserve.

## A7 (LF21, `accelerateUrl`) authored and REFUSED 2026-09-10 — two boundaries, and not the rule this record predicted

A7's drawn fact is LF21: *"Accelerate users pass `accelerateUrl` to the constructor instead of an
adapter, and keep the `withAccelerate()` extension."* This record wrote the seat down as **due for
refusal** before any artifact existed, under §9's seventh amendment, second guard (an `added` fact
at 7.0.0 is a rising task at a major's first rung). It was authored and put through the gate anyway,
so the refusal would rest on evidence rather than on that prediction. It was refused, **by a
different rule**:

```
  REFUSE A7.lf21 A  LF21  rising    @7.0.0
         correct  ............+++++++++++
         stale    ++++++++++++...........
         both artifacts carry a version dependence — the correct solution rises and the stale one
         falls, so the task has two boundaries and the results could not say which one it measured
```

on the same twenty-three installed releases as A1–A6.

**Why the prediction named the wrong rule.** The seventh-amendment guard fires only when the gate
reads a task as **rising**, and it reads one that way only when no stale artifact flips. §9's second
amendment runs the stale artifact **whenever one exists**. The prediction treated an `added` fact as
having nothing stale to run. LF21 does have a stale artifact: its `stale_belief` ("configured purely
by putting the `prisma://` URL in `DATABASE_URL` ... with no constructor option") can be executed, and
the executable form falls at 7.0.0. So the two-boundary refusal, which `admit` checks earlier, fires
first. **Both rules refuse this seat**, and the second half was measured too, not reasoned. The same
correct artifact under a task id with no stale artifact beside it is refused by the guard the
prediction named:

```
  REFUSE A7.lf21-nostale A  LF21  rising    @7.0.0
         correct  ............+++++++++++
         the correct solution first passes at 7.0.0, the first release of a major on a ladder that
         crosses one — a rising task cannot tell "the API did not exist below" from "the artifact is
         written in this major's dialect", and both read as false on exactly the same rungs (§9
         seventh amendment)
```

(The no-stale run used a temporary copy of the reference and a scratch manifest; both were deleted
afterwards and neither is committed. A7.lf21's own manifest entry is not in `prisma.manifest.json`,
which holds admitted tasks only, per its header.)

**The predictive question A4 and A6 answered, answered a third time.** *Does the correct answer's API
exist below the fact's release?* For LF21, no: `accelerateUrl` is `PrismaClientConstructorValidationError:
Unknown property accelerateUrl provided to PrismaClient constructor.` on every 6.x rung where the
sentence was read (6.0.0, 6.19.0), and the row is false on all twelve. The three seats the gate has
refused on two boundaries carry three different `change_kind`s (A4/LF15 `renamed`, A6/LF7
`requirement`, A7/LF21 `added`) and give the same answer to that question. A8's fact (LF25, `/edge`) answers it
the other way (table above). That is still recorded as a question and not as a prediction of A8's
outcome.

**The survey ran before any task file existed**, through the probe file's own
`runWithGeneratedClient`, on all twenty-three rungs:

```
                                                   6.0.0 ........................ 7.10.0
  stale, new PrismaClient()                        ++++++++++++...........
  stale, same, DATABASE_URL = prisma+postgres://   ++++++++++++...........
  stale, the fact's stale_code verbatim            .......................   (ERR_MODULE_NOT_FOUND)
  correct, accelerateUrl: "prisma+postgres://..."  ............+++++++++++
  correct, accelerateUrl: "prisma://..."           ............+++++++++++
  correct, accelerateUrl: process.env.DATABASE_URL ............+++++++++++   (harness value is postgresql://)
  correct, accelerateUrl: an UNSET variable        .......................
  adapter + accelerateUrl                          .......................
  adapter handed the prisma+postgres:// URL        +++++++++++++++++++++++
```

Sentences, quoted only at the rungs they were read at (6.0.0, 6.19.0, 7.0.0, 7.10.0):

| artifact | 6.x | 7.0.0 | 7.10.0 |
|---|---|---|---|
| stale | constructs | `TypeError: Cannot read properties of undefined (reading '__internal')` | `PrismaClientInitializationError: PrismaClient was instantiated without any options. A driver adapter is required to connect to your database.` |
| correct | `Unknown property accelerateUrl provided to PrismaClient constructor.` | constructs | constructs |
| unset variable | the same unknown-property sentence | `Using engine type "client" requires either "adapter" or "accelerateUrl" to be provided to PrismaClient constructor.` | `PrismaClient requires a driver adapter to connect to your database, but none was provided.` |
| adapter + accelerateUrl | the same unknown-property sentence | `The "adapter" and "accelerateUrl" options are mutually exclusive. Please provide only one of them.` | the same |

**The extension is not on this ladder, and it is removed from both artifacts.** LF21's own
`stale_code` imports `withAccelerate` from `@prisma/extension-accelerate`. No rung has that package,
so the verbatim code is `ERR_MODULE_NOT_FOUND` on all twenty-three, a flat failure caused by the
ladder. Installing it would add a third package with its own version line beside
`@prisma/adapter-pg`: JOURNAL/070's trap, arriving through one more peer. The stale answer and the
correct one apply the extension the same way, so it is not what LF21 dates. The prompt says the
extension is applied in another file.

**The value is not checked at construction.** The harness's `DATABASE_URL` is a `postgresql://`
literal, and the prompt says the variable holds a `prisma+postgres://` URL. The three spellings
measured (two literals and the harness's variable) share one row on all twenty-three rungs, so the
grader's value cannot move a verdict. An unset variable is not the same answer: `accelerateUrl:
undefined` is treated as no option at all.

**Two more reasons this seat could not have carried LF21, found by the survey and independent of the
rows.**
- **With the extension removed, the stale artifact is A4's, byte for byte.** The belief "no
  constructor option" has one executable form, `new PrismaClient()`, which is LF1's. A failing round
  would hand back the missing-adapter sentence, which never mentions `accelerateUrl`. The stale half
  of this task grades LF1, and A7 would have joined the `constructsClient` group (A3, A4, A6) from the
  stale side.
- **The wrong answer LF21's statement warns about passes this grader on every rung.** "Do not pass a
  `prisma://` or `prisma+postgres://` URL to a driver adapter, `PrismaPg` ... will fail on it": an
  adapter handed the Accelerate URL **constructs on all twenty-three rungs**. Construction is lazy, so
  that failure happens at connection time, and no verdict this harness can reach sees it. A subject
  that knew LF1 and not LF21 would write exactly that answer and pass. Any future seat on an
  Accelerate fact needs an instrument that observes a connection, and this ladder has no endpoint to
  connect to.

**Measured on the way and handed to the data lane, not written here** (BACKLOG 1h-c): LF21's note
states from the type declarations that `adapter` and `accelerateUrl` are mutually exclusive. The
constructor also rejects the pair **at runtime** at 7.0.0 and 7.10.0 (the table above). The statement's
"will fail on it" is a connection-time failure, which the statement does not contradict.

**The seat.** A7 → **LF10** (the `prisma` key in `package.json`), as A6's refusal assigned it. This
refusal opens no seat above A7, so nothing moves. The relocation question recorded against LF10 at A6
is unchanged, and it stays a question. **S1 reserve:** LF16 (A2), LF1 (A4), LF2 (A6) are in the set,
LF10 is named for A7, and three remain unspoken-for: LF4, LF13, LF8. **Previously-charged subset:**
LF21 was not charged and LF10 is, so if LF10 is admitted at A7 the subset moves from 4 of 12 to **5 of
12**. That is reported here and is an input to nothing.

**Nothing else moved.** A1–A6 re-gated after `A7_LF21` was added to the assertion file: all six admitted, and the gate's whole stdout
**byte-identical** to the run captured before the first edit, with stderr identical once PowerShell's
wrapper lines are set aside.
Counts unmoved at 161 runs / 167 findings (160 chargeable) over 8 libraries, which is correct for a
session that admits no task and publishes no finding.

**What is left of BM2:** A7 → LF10 (authored and gated), five drawn Class A assertions (A8–A12), the
six Class N tasks, BM2's predictions, then the arms. Six of twelve Class A seats are filled and
admitted, three of them from the reserve. Four drawn facts have now been refused: LF14, LF15, LF7 and
LF21.

## A7 → LF10, refused on two boundaries at two DIFFERENT releases (2026-09-11, JOURNAL/137)

A7's substitute, **LF10** (*"The `prisma` key in `package.json` is no longer read. Schema path and
seed command move to `prisma.config.ts`"*), was authored in full and put through the gate. The gate
refused it:

```
REFUSE A7.lf10 A  LF10  falling   @7.0.0
       correct  ...........++++++++++++
       stale    ++++++++++++...........
       both artifacts carry a version dependence — the correct solution rises and the stale one
       falls, so the task has two boundaries and the results could not say which one it measured
```

The gate walked the same twenty-three installed releases as A1–A6. **A7's two refusals (LF21, then
LF10) came from the same rule, but LF10's two boundaries are at different releases.** In every
earlier two-boundary refusal (A4/LF15, A6/LF7, A7/LF21) the correct row rose at 7.0.0, the release
where the stale one fell. Here the correct answer rises at **6.19.0**, one rung earlier.

**The graded clause is the schema path, and that is the probe's choice, not this lane's.** LF10's
statement has two clauses that share one key. `probes.LF10` executes the schema-path clause: a
`package.json` naming a non-default schema file, and whether `prisma validate` finds it. So the
schema-path clause is the one whose 7.0.0 the bisector confirmed. The seed clause has never been
executed on this ladder, and a task resting on it would rest on a release note (§7 rule 1, sixth
amendment).

**The survey ran before any task file existed.** Seven candidate projects went through the probe
file's own `inProject` and `prisma validate` on all twenty-three rungs. Each project has the same
`app.prisma` (a non-default name at the project root), and a pass is the CLI reporting `The schema at
app.prisma is valid`:

```
                                                         6.0.0 ........................ 7.10.0
  stale, package.json { prisma: { schema } }             ++++++++++++...........
  correct, prisma.config.ts  export default { schema }   ...........++++++++++++
  correct, the same with earlyAccess: true               ......+++++............
  both, package.json key + plain config                  ++++.......++++++++++++
  both, package.json key + earlyAccess config            ++++..+++++............
  neither (package.json with no key)                     .......................
  correct, prisma.config.mjs  export default { schema }  ...........++++++++++++
```

Sentences, quoted only at the rungs they were read at:

| artifact | 6.0.0, 6.3.0 | 6.4.0, 6.5.0 | 6.6.0, 6.7.0, 6.9.0, 6.10.0 | 6.19.0 | 7.0.0, 7.10.0 |
|---|---|---|---|---|---|
| stale (key) | `The schema at app.prisma is valid` | the same | the same | the same, plus `warn The configuration property \`package.json#prisma\` is deprecated and will be removed in Prisma 7` | `Error: Could not find Prisma Schema that is required for this command.` |
| plain config | `Could not find Prisma Schema` (config not read) | `Failed to parse config file` | `Failed to parse config file` | `Loaded Prisma config from prisma.config.ts.` and valid | the same |
| `earlyAccess` config | not read | `Failed to parse config file` | `Loaded Prisma config from ...` and valid | `Failed to parse syntax of config file` | the same rejection |
| `prisma.config.mjs` | not read | not read | not read | loaded and valid | the same |

**Why the relocation question was not enough.** Since A4, this record has carried one question for a
relocation: *does the correct answer's destination exist below the fact's release?* For LF10 the answer
is **yes**. A config file naming the schema is loaded and used at 6.19.0, and in its `earlyAccess`
spelling at 6.6.0–6.10.0. The seat is refused anyway, because **no single spelling of that destination
is accepted across the ladder**. The file is not read below 6.4.0. At 6.4.0 and 6.5.0 both spellings
are rejected. From 6.6.0 to 6.10.0 it is loaded only with `earlyAccess: true`, and from 6.19.0 that key
is a syntax error, 7.10.0 included. A falling task needs a correct artifact that passes on **every**
rung, and none of the seven candidates does. The one that pairs a config file with the old key as
well, which is the only way to reach below 6.4.0, is
`++++.......++++++++++++`: non-contiguous. **So the destination existing below the boundary is
necessary but not sufficient. What the gate needs is one correct artifact that passes everywhere.**
The question stays a question for the seats still to be authored, in this stronger form.

**The rejection recommends the stale answer.** When 7.x finds no schema it lists the ways to supply
one, and one of them is "set it as `prisma.schema` in your package.json". That is the key LF10 says is
no longer read. The sentence is in the output at 7.0.0 and 7.10.0, and in the shipped CLI bundle at
7.0.0, 7.9.0 and 7.10.0. At 7.10.0 the same hint names its example config file `prisma7.config.ts`.
A failing round hands the toolchain's words back verbatim (§14), so on this seat the retry channel
would have pointed every arm at the stale answer. Handed to the data lane as **BACKLOG 1h-e** along
with the `earlyAccess` measurement, not written here.

**The assertion's new guard was made to fail against its defect before it was trusted.** The graded
verdict here is a presence, not an absence, so the canary has to pass. It is the harness's own schema
validated at the default location in an empty directory, and it must report `The schema at
schema.prisma is valid` on every rung. It did, on all twenty-three. Against stub subjects: a CLI that
prints nothing makes the assertion throw, as does a CLI that fails to spawn. Not-found graded output
is a `false`. A `schema.prisma` found at the default location is a `false`, because the file name is
the witness. A nested file name is refused. Valid output at `app.prisma` is `true`.

**The seat.** A7 → **LF4** (*the `prisma-client` generator requires an `output` path*), the next S1
reserve entry in the printed order. Only A7 is open, so nothing else moves. **LF4 is dated 6.6.0, not
7.0.0**: it is the first reserve fact whose boundary is not the major, so the seventh amendment's
major-floor guard cannot apply to it. That is recorded as a property of the fact, not as a
prediction. **S1 reserve:** LF16 (A2), LF1 (A4) and LF2 (A6) are in the set, LF4 is named for A7, and
two remain unspoken-for: LF13 and LF8. **Previously-charged subset:** LF10 was charged and was
refused, so the subset stays at **4 of 12** as the set stands. LF4 is charged, so if it is admitted at
A7 the subset moves to 5 of 12. That is reported here and is an input to nothing.

**Nothing else moved.** A1–A6 were re-gated after `A7_LF10` was added to the assertion file. All six
were admitted, and the gate's whole stdout was **byte-identical** to the run captured before the first
edit. Stderr was identical apart from PowerShell's wrapper line, which names the command's column.
The refused task keeps its fact id in every file: `tools/benchmark/tasks/prisma/A7.lf10.*`,
`prompts/sent/benchmark-prisma-a7-lf10-refused.txt`, and `A7_LF10` in the assertion file. The scratch
manifest used to gate it was deleted and is not committed. Counts are unmoved at 161 runs / 167
findings (160 chargeable) over 8 libraries.

**What is left of BM2:** A7 → LF4 (authored and gated), five drawn Class A assertions (A8–A12), the
six Class N tasks, BM2's predictions, then the arms. Six of twelve Class A seats are filled and
admitted. Five facts have now been refused: LF14, LF15, LF7 and LF21 were drawn, and LF10 was a
reserve substitute.

## A7 → LF4 (`prisma-client` requires `output`) authored and ADMITTED 2026-09-11 — `rising @6.6.0` (JOURNAL/139)

A7's third fact is **LF4**, the next S1 reserve entry in the printed order after LF10's refusal:
*"The `prisma-client` generator ... refuses to run without an `output` path ... That has been true
since the generator arrived in 6.6.0, not since 7.0.0."* The gate admits it:

```
  ADMIT  A7   A  LF4   rising    @6.6.0
         correct  ......+++++++++++++++++
         stale    .......................
```

on the same twenty-three installed releases as A1–A6. The artifacts are LF4's own `correct_code` and
`stale_code`, verbatim; they differ by the `output` line alone.

**Two firsts, both properties of the fact rather than choices.** It is the first BM2 seat whose fact
is not dated at the major, and the first **rising** task in the set. The correct row rises because
the provider does not exist below 6.6.0: at 6.0.0 through 6.5.0 the CLI tries to spawn it as an
external binary (`Error: spawn prisma-client ENOENT`). The stale row fails on all twenty-three rungs,
for that reason below 6.6.0 and for LF4's own reason from it (`An output path is required for the
\`prisma-client-ts\` generator` at 6.6.0–6.8.0, `... for the \`prisma-client\` generator` from
6.9.0). So only one artifact carries a version dependence and the task has one boundary. §9 seventh
amendment's second guard refuses a rising task at a **major's** first rung; 6.6.0 is a minor inside
6.x, where the two dialects the guard separates are the same one, so it does not apply.

**What the boundary is, said so it is not over-read.** The rows date the generator's *arrival*, and
LF4 is dated there because, by its own statement and its own probe, the requirement arrived with the
generator. They cannot be read as "`output` became required in 6.6.0 in a generator that existed
before". No such generator did. What makes the seat worth grading is the graded release: at 7.10.0
the stale artifact fails with the requirement's own sentence and the correct one generates.

**The answer is the generator block alone, and that is this seat's design decision.**
`produced: { form: "text", as: "generator" }`. The harness supplies the datasource block (in the 7
spelling, rendered per rung by `spell()`) and one model, and composes the schema around the reply.
A whole-schema answer would carry a datasource block, and a subject writing Prisma 6's
`url = env("DATABASE_URL")` into it fails at the graded release for **LF8**'s reason rather than
LF4's. That is JOURNAL/119's three doors again. See the next section for the seat where that confound
is already present.

**The layout is `prisma init`'s** (the schema at `prisma/schema.prisma`), through
`generateInitLayout`, which was added to the probe file for this seat. LF4's `correct_code` names
`../src/generated/prisma`, relative to the schema's directory. With the schema at the project root
(`generateProject`) that path resolves *outside* the project, into the rung's shared scratch
directory. The addition is additive: no probe calls it, and `generateProject` is untouched.

**The survey ran before any task file existed**, through `generateInitLayout` on all twenty-three
rungs. A pass here is the CLI reporting a generated client:

```
                                                    6.0.0 ........................ 7.10.0
  stale  prisma-client, no output                   .......................
  correct prisma-client, ../src/generated/prisma    ......+++++++++++++++++
  correct prisma-client, ./generated                ......+++++++++++++++++
  route  prisma-client-js, no output                +++++++++++++++++++++++
  route  prisma-client-js, ../src/generated/prisma  +++++++++++++++++++++++
  ea     prisma-client-ts, ../src/generated/prisma  ......+++++++++++++++++
```

**The two `prisma-client-js` rows are the route around the fact, and the witness closes it.** The
prompt names the generator. A reply that ignores that and falls back to `prisma-client-js` generates
on every rung, with an output or without one (LF4c). So the assertion requires a second thing besides
a generated client: a file named `client.ts` (or `.mts`/`.cts`, for `generatedFileExtension`) written
under the project root. That is the `prisma-client` generator's own output, and it grades the
generated tree, not the reply's text. Swept on all twenty-three rungs before the gate ran:

```
  witness: client.[mc]?ts written       6.0.0 ........................ 7.10.0
  prisma-client + output                ......+++++++++++++++++
  prisma-client-js + output             .......................
  prisma-client-js, no output           .......................
```

`prisma-client-js` writes `client.d.ts` and `client.js` from 6.6.0 and neither below, and never
`client.ts`.

**Four plausible replies were generated at 7.10.0 before the assertion was written, and all four
pass there**: `previewFeatures = ["queryCompiler", "driverAdapters"]`, `runtime = "nodejs"` with
`moduleFormat = "esm"`, `generatedFileExtension = "mts"`, and `engineType = "client"`. None of them
can turn a correct answer into a `false` at the graded release. Two of them are rejected lower on the
ladder: at 6.6.0, `queryCompiler` is `The preview feature "queryCompiler" is not known` and
`engineType = "client"` is `Unstable Feature ... proof of concept phase`. That does not affect grading,
which happens at 7.10.0, but it is recorded here because it is where it was seen.

**What a failing round hands back.** The refusal ends with an example generator block that carries
an `output` line, at 6.6.0, 6.19.0 and 7.10.0. The toolchain answers the question the task asks, so a
subject that fails round 0 is handed the answer at round 1, in every arm. It is quoted rather than
trimmed (A1's rule). The consequence is written down before any arm runs: **this seat's
`rounds_to_pass` can separate the arms by one round at most.** Its round-0 cell is where any
difference will show.

**The canary must pass**, as A7_LF10's did, because the graded verdict for a correct answer is a
presence. It is A5's own schema (`prisma-client-js` with an output), which generates on all
twenty-three rungs, through `generateProject`, memoised on the schema text, so it costs nothing on a
rung that has graded A5. If it does not report a generated client the assertion throws. Eleven
checks against stub subjects before the assertion was trusted (JOURNAL/118's rule). A silent canary
and a canary that cannot spawn both throw. A refused generation is a `false`, and so is a generation
that writes only `prisma-client-js` files or nothing under the project, or only `myclient.ts`. A
layout call that throws is a `false` with the error quoted. `client.ts` and `client.mts` are `true`.
A missing or blank `generator` string is a `false`.

**The model is the same `User` as `runWithGeneratedClient`'s project, on purpose.** A reply that falls
back to `prisma-client-js` with no output generates into the install's own `node_modules/@prisma/client`.
On the runner's `flat-real` install that is the client A3, A4 and A6 construct, and with this model it
still has the `user` delegate their harness entry reads.

**The seat.** A7 = LF4. **S1 reserve:** LF16 (A2), LF1 (A4), LF2 (A6) and LF4 (A7) are in the set, and
two remain unspoken-for: **LF13, LF8**. **Previously-charged subset:** LF4 is charged, so the subset
moves from 4 of 12 to **5 of 12** as the set stands (A4, A7, A10, A11, A12). That is reported here and
feeds into nothing.

**Nothing else moved.** A1–A6 were re-gated after A7 was added to the manifest. All seven were
admitted, and the gate's stdout was **byte-identical** to the run captured before the first edit,
apart from A7's three lines and the count (`6 of 6` → `7 of 7`). Stderr differed only in PowerShell's
wrapper line. Gate selftest 46, runner 42, MCP 54, identifiers 35, and all five `--check` builds green.
The prisma bisector was not re-run: the probe-file change adds one helper that no probe calls.
Counts are unmoved at 161 runs / 167 findings (160 chargeable) over 8 libraries.

## An open question on A1, measured while A7 was designed, and left open on purpose (2026-09-11)

A7's answer excludes the datasource block because of LF8. **A1's answer is a whole schema, so A1
carries that confound now**, measured through A1's own assertion:

```
                                               6.19.0   7.0.0   7.10.0
  A1.reference.mjs                             PASS     PASS    PASS
  the same + url = env("DATABASE_URL")         FAIL     FAIL    FAIL
```

At 7.0.0 and 7.10.0 the failure is LF8's sentence: `P1012 ... The datasource property \`url\` is no
longer supported in schema files. Move connection URLs for Migrate to \`prisma.config.ts\` ...`. (At
6.19.0 it is `Environment variable not found: DATABASE_URL`, because the harness sets no such
variable and `spell()` leaves a block that already has a url alone. That is irrelevant to grading,
which happens at 7.10.0.) So a subject that knows LF23 (no `metrics`) and still writes Prisma 6's
datasource block fails A1 at round 0 for LF8's reason. LF8 is in the prisma pack, so a PACK-arm
advantage on A1's round 0 could come from LF8 rather than from LF23. A1's prompt says the service
depends on v7 and asks for the complete file. It does not mention the datasource url.

**Two ways to settle it, and neither is taken here.** (a) Re-author A1 so the harness supplies the
datasource block, as A7 does, and re-gate it before any arm runs. (b) Keep A1 as admitted, and have
the results attribute each failing A1 cell by the sentence the toolchain printed: LF23's
`preview feature "metrics" is not known` against LF8's `url ... no longer supported`. The runner
already keeps each failing round's feedback, which is that output, in the cell. Changing an admitted task is a decision about the
set, not something to do in passing, so this is written down for the session that authors the
predictions. It must be settled **before the first arm**. No other admitted seat is exposed: A2 is
an argv, A3/A4/A6 are constructor modules against a client the harness generates, A5 is a package
list, and A7 is the generator block alone.

**What is left of BM2:** five drawn Class A assertions (A8–A12), the six Class N tasks, the A1
question above, BM2's predictions, then the arms. **Seven of twelve Class A seats are filled and
admitted**, four of them from the reserve. Five facts have been refused: LF14, LF15, LF7 and LF21
were drawn, and LF10 was a substitute.

## A8 (LF25, `/wasm` renamed to `/edge`) authored and REFUSED 2026-09-11 — §9 seventh amendment's second guard (JOURNAL/141)

A8's drawn fact is **LF25**: *"For `prisma-client-js` users, the `/wasm` export was renamed to `/edge`,
and `/edge` changed meaning: it now means edge JS runtimes (Cloudflare, Vercel Edge) rather than Prisma
Accelerate."* This record's table under A4 had singled it out as the one drawn `renamed` fact whose
falling shape was available, because `./edge` is in the export map below 7.0.0. It was authored in
full and put through the gate on the same twenty-three installed releases as A1–A7:

```
  REFUSE A8.lf25 A  LF25  rising    @7.0.0
         correct  ............+++++++++++
         stale    .......................
         the correct solution first passes at 7.0.0, the first release of a major on a ladder that
         crosses one — a rising task cannot tell "the API did not exist below" from "the artifact is
         written in this major's dialect", and both read as false on exactly the same rungs (§9
         seventh amendment)
```

**The survey ran before any task file existed**, through `runWithGeneratedClient` (the harness's
`prisma-client-js` client with the `driverAdapters` preview feature) on all twenty-three rungs. A pass
is the import constructing a client and the process exiting 0:

```
                                                        6.0.0 ........................ 7.10.0
  correct   @prisma/client/edge + pg adapter (pool)     ............+++++++++++
  stale     @prisma/client/wasm + pg adapter (pool)     .......................
  stale     the same /wasm, reached with createRequire  .......................
  control   @prisma/client + pg adapter (pool)          +++++++++++++++++++++++
  6.x use   @prisma/client/edge, prisma:// datasourceUrl ++++++++++++...........
  bare      @prisma/client/wasm, no options              .......................
  bare      @prisma/client/edge, no options              ....++++++++...........
```

**The key existed; its meaning did not.** On all twelve 6.x rungs the correct row fails with the
client's own sentence: ``PrismaClientValidationError: Prisma Client was configured to use the
`adapter` option but it was imported via its `/edge` endpoint.`` Below 7.0.0 `/edge` is the Accelerate
entry point, which is exactly what LF25's second clause says changed. The control row settles what
the dependence belongs to: the same construction through the root entry, `@prisma/client`, passes on
every rung, so the rise at 7.0.0 is the entry point's and not the adapter's. The test this record has
been refining for renames and relocations therefore has three necessary conditions, each learned from
a refusal: the correct answer's destination **exists** below the boundary (LF15, A4), **one spelling**
of it is accepted on every rung (LF10, A7), and it **means the same thing** on every rung (LF25, A8).

**Why the guard and not the two-boundary rule.** The stale artifact never passes, so it carries no
version dependence and the gate reads the task as rising. In Node it fails on every rung, for three
different reasons along the ladder, and only the last is the belief's:

- **6.0.0–6.5.0:** the import resolves to `wasm.js` and constructs (the harness prints its line), and
  the process then exits 1 on ``PrismaClientInitializationError: The loaded wasm module was
  unexpectedly `undefined` or `null` once loaded``. `/wasm` serves runtimes that load a `.wasm` import;
  Node is not one. Reached with `createRequire`, the same sentence appears on all twelve 6.x rungs.
- **6.6.0–6.19.0:** the ES-module import fails before anything runs, `ERR_MODULE_NOT_FOUND ...
  @prisma/client/wasm.mjs`. From 6.6.0 the package's export map sends `./wasm`'s `import` and
  `default` conditions to `./wasm.mjs` (at 6.0.0, 6.4.0 and 6.5.0 they point at `./wasm.js`), and that
  file is in neither the published tarball (`npm pack --dry-run`, 6.6.0 and 6.19.0) nor anything the
  package's postinstall writes, since the postinstall writes only under `node_modules/.prisma/client`.
- **7.0.0–7.10.0:** `ERR_MODULE_NOT_FOUND ... @prisma/client/wasm`, the rename LF25 records. This is
  the sentence a failing round would hand back at the graded release.

So at 7.10.0 the task discriminates cleanly: the reference constructs and the stale artifact fails
for LF25's reason. What the ladder cannot supply is a rung where the stale answer was a working
answer in the grader's runtime, and without one the only moving row is the correct one, rising at
the major's first rung. That is the case the seventh amendment's guard refuses by name, and it
refuses it here.

**A question recorded, not answered in this seat's favour.** For this seat the guard's ambiguity is
resolvable on evidence the gate does not read: the 6.x sentence names the `/edge` endpoint, and the
root-entry control row is flat. The gate reads verdicts and never sentences, by design. Whether a
failure sentence may ever attribute a boundary is the same question left open on A1 above, where
option (b) attributes failing cells by the sentence the toolchain printed. It is recorded here so the
session that settles A1 settles it once, for both uses, and not per seat after seeing which answer
admits more tasks. Nothing in this record re-opens A8: the refusal stands under the rules as written.

**The instrument is `constructsClient`**, pointed at a fifth fact (A3, A4 and A6 admitted; A7_LF21 and
A8_LF25 refused). The task's prompt asks for the edge-runtime entry point of a `prisma-client-js`
client, for Cloudflare Workers with `nodejs_compat`, and says the grader imports the file under
Node.js. The reference and stale artifacts are the fact's own `correct_code` and `stale_code` import
lines with the same pool-form construction as A3's reference, and they differ by the import specifier
alone.

**Handed to the data lane, not written (BACKLOG 1h-f):** the adapter refusal through `/edge` on 6.x as
a possible executable row for LF25's "changed meaning" clause, which `probes.LF25a/b` read off the
export map only; and the missing `wasm.mjs`, a packaging observation with no release note behind it.

**The seat.** A8 → **LF13** (*`prisma generate` no longer accepts `--no-engine`, `--data-proxy`,
`--accelerate` or `--allow-no-models`*), the next S1 reserve entry in the printed order. Only A8 is
open, so nothing else moves. **S1 reserve:** LF16 (A2), LF1 (A4), LF2 (A6) and LF4 (A7) are in the
set, LF13 is named for A8, and one remains unspoken-for: **LF8**. For LF13 the three conditions are a
**question**, not a prediction: its `correct_code` is `npx prisma generate`, a command that exists on
every rung, and whether it is accepted in one spelling and means the same thing on all twenty-three is
what its survey will say. **Previously-charged subset:** LF25 was not charged, so it stays at **5 of
12** as the set stands; LF13 is charged, so if it is admitted at A8 the subset moves to 6 of 12. That
is reported here and feeds into nothing.

**Nothing else moved.** A1–A7 were re-gated after `A8_LF25` was added to the assertion file, and the
gate's whole stdout and stderr were compared with the run captured before the first edit.
All seven were admitted, and stdout and stderr were both **byte-identical** to that capture. The scratch manifest used to gate A8 was deleted and is not committed. Counts are
unmoved at 161 runs / 167 findings (160 chargeable) over 8 libraries.

**What is left of BM2:** A8 → LF13 (authored and gated), four drawn Class A assertions (A9–A12), the
six Class N tasks, the A1 question above, BM2's predictions, then the arms. **Seven of twelve Class A
seats are filled and admitted**, four of them from the reserve. Six facts have been refused: LF14,
LF15, LF7, LF21 and LF25 were drawn, and LF10 was a substitute.

## A8 → LF13 (`prisma generate --no-engine`) authored and ADMITTED 2026-09-11 — `falling @7.0.0` (JOURNAL/143)

A8's substitute is **LF13**, the S1 reserve entry the LF25 refusal assigned it: *"`prisma generate` no
longer accepts `--no-engine`, `--data-proxy`, `--accelerate` or `--allow-no-models`."* The gate admits
it:

```
  ADMIT  A8   A  LF13  falling   @7.0.0
         correct  +++++++++++++++++++++++
         stale    ++++++++++++...........
```

on the same twenty-three installed releases as A1–A7. The artifacts are LF13's own `correct_code` and
`stale_code` as argument lists, `["generate"]` and `["generate", "--no-engine"]`; they differ by the
flag alone. No amendment, and no new instrument: the answer is an argv, as A2's is, and it is run
through `inProject` in a directory holding A5's schema.

**The survey ran before any task file existed**: nine invocations through `inProject`, with A5's schema
(`prisma-client-js` with an `output`, which generates on every rung) at the project root. A pass is the
CLI reporting a generated client:

```
                                         6.0.0 ........................ 7.10.0
  correct   generate                     +++++++++++++++++++++++
  stale     generate --no-engine         ++++++++++++...........
  removed   generate --data-proxy        ++++++++++++...........
  removed   generate --accelerate        ++++++++++++...........
  removed   generate --allow-no-models   ++++++++++++...........
  extra     generate --no-hints          +++++++++++++++++++++++
  extra     generate --schema=...        +++++++++++++++++++++++
  extra     generate --generator client  +++++++++++++++++++++++
  canary    generate --sp-canary-unknown .......................
```

All four flags LF13 names generate on all twelve 6.x rungs and fail on all eleven 7.x ones,
contiguously, so the first sentence of the fact's statement holds for every flag it names and not only
for the one its `stale_code` uses. The sentence was read at 7.0.0 and 7.10.0 for each flag, and it is
`unknown or unexpected option: <flag>` followed by the usage table; the other nine 7.x rungs are
recorded as verdicts. On 6.x the first three generate an engine-less client (`Generated Prisma Client
(v6.19.0, engine=none)` at 6.19.0), and the 6.x usage table describes `--no-engine` as "Generate a
client for use with Accelerate only". `--allow-no-models` generates an ordinary client, because the
schema has a model. The three plausible extra arguments generate on every rung, so none of
them can turn a correct answer into a `false` at the graded release.

**The draw record's question for this seat, answered by the same survey.** After LF25 the question
has three conditions: the correct answer exists below the boundary, one spelling of it is accepted on
every rung, and it means the same thing on every rung. `generate` meets the first two. It does **not**
meet the third, and the survey measured that too, by listing what each run wrote under
`generated/`:

```
                     correct (generate)                              stale (--no-engine)
  6.0.0 – 6.10.0     query_engine-windows.dll.node                   no engine
  6.19.0             query_engine-windows.dll.node, query_engine_bg.wasm, query_engine_bg.js   no engine
  7.0.0 – 7.2.0      query_compiler_bg.wasm                          rejected
  7.3.0 – 7.10.0     query_compiler_fast_bg.wasm                     rejected
```

What the correct command *writes* changes at 7.0.0. The seat is admissible anyway because the
criterion does not read what it writes. So the third condition is relative to the criterion: it must
hold for what the assertion observes, not for everything the command does. That is also why the
natural criterion for the prompt's scenario was refused before the assertion existed. The scenario is
a serverless bundle, and "the generated client ships no query engine" would have failed the correct
answer on every 6.x rung and passed it from 7.0.0, while the stale one passes below and is rejected
from it. That is two boundaries on one release, A4/LF15's refusal. The assertion therefore grades the
one thing LF13 claims, which flags `generate` takes, read off the generation report, and the prompt
says so in those words.

**The prompt** puts the belief where it lived. It describes serverless functions with a bundle size
limit that reach PostgreSQL through Prisma Accelerate, which is the deployment the v5/v6 advice
(`generate --no-engine`) was written for. It shows the schema and asks for the build step's
invocation. What is graded and what is not (size, engine, connectivity) is stated in the prompt.

**The canary must pass**, because the graded verdict for a correct answer is a presence. It is A7's
canary exactly: A5's schema through `generateProject`, memoised, which is free on a rung that has
graded A5 or A7. A silent canary, a canary that cannot spawn and a canary that reports a refusal all
throw. Thirteen checks against stub subjects before the assertion was trusted (JOURNAL/118's rule),
including that the two committed artifacts get different `inProject` directories.

**What a failing round hands back**, at 7.0.0 and 7.10.0, is `unknown or unexpected option:
--no-engine` followed by the `prisma generate` usage table, which lists the options the release takes.
It is quoted whole (A1's rule). A subject that fails round 0 is therefore handed, at round 1, the name
of the rejected flag and the list of accepted ones. As with A7, that bounds what this seat's
`rounds_to_pass` can show, and it is recorded here before any arm runs. Its round-0 cell is where any
difference between the arms will show.

**The seat.** A8 = LF13. **S1 reserve:** LF16 (A2), LF1 (A4), LF2 (A6), LF4 (A7) and LF13 (A8) are in
the set, and one remains unspoken-for: **LF8**. **Previously-charged subset:** LF13 is charged, so the
subset moves from 5 of 12 to **6 of 12** as the set stands (A4, A7, A8, A10, A11, A12). That is
reported here and feeds into nothing.

**Nothing else moved.** A1–A7 were re-gated after A8 was added to the manifest and the assertion file.
All eight were admitted. The gate's stdout differed from the run captured before the first edit only
by A8's three lines and the count (`7 of 7` → `8 of 8`), and its stderr was **byte-identical**. The
probe file was not touched. Gate selftest 46, runner 42, MCP 54, identifiers 35. Counts are unmoved at
161 runs / 167 findings (160 chargeable) over 8 libraries.

**What is left of BM2:** four drawn Class A assertions (A9–A12), the six Class N tasks, the A1
question above, BM2's predictions, then the arms. **Eight of twelve Class A seats are filled and
admitted**, five of them from the reserve. Six facts have been refused: LF14, LF15, LF7, LF21 and LF25
were drawn, and LF10 was a substitute.

## A9 (LF19, the Node.js floor) authored and ADMITTED 2026-09-11 — `falling @7.0.0` (JOURNAL/145)

A9's drawn fact is **LF19**: *"Prisma 7 ships as an ES module and requires Node >= 20.19.0 and
TypeScript >= 5.4.0."* It is the first drawn fact since A5 to be admitted in its own seat. It needed
no amendment and no probe-file change. The gate admits it:

```
  ADMIT  A9   A  LF19  falling   @7.0.0
         correct  +++++++++++++++++++++++
         stale    ++++++++++++...........
```

on the same twenty-three installed releases as A1–A8. The answer is one exact Node.js release
(`export const node = "..."`). The reference is `20.19.0`, the release LF19's statement names. The
stale artifact is `18.18.0`, the floor the 6.x manifests declare.

**The graded clause is the Node floor, and the probe chose it, not this lane** (A7/LF10's rule). LF19
has three clauses. `probes.LF19` executes one: the `engines.node` range the installed `prisma`
package declares. The bisector confirmed that clause's 7.0.0. The TypeScript clause and the ESM clause
have no probe row, so a task resting on either would rest on a release note (§7 rule 1, sixth
amendment).

**The survey ran before any task file existed**: `engines.node` read off the installed `prisma`
manifest on all twenty-three rungs.

```
  6.0.0 – 6.19.0 (12 rungs)    >=18.18
  7.0.0                        ^20.19 || ^22.12 || ^24.0
  7.1.0 – 7.10.0 (10 rungs)    ^20.19 || ^22.12 || >=24.0
```

Every rung's manifest names `prisma` at that rung's own version, which is the assertion's witness.

**The criterion is "the declared range admits the answer", not "the answer is the oldest release it
admits".** The prompt's scenario asks for the oldest. But the oldest admitted release is 18.18.0 below
7.0.0 and 20.19.0 from it. Grading on that would make the correct answer rise at 7.0.0 where the
stale one falls: two boundaries on one release, which is A4/LF15's refusal. "Admits" is the whole
of what a floor claims, and under it LF19's own release is admitted on every rung. **What that costs,
recorded before any arm:** an answer that pins a newer release than it needs (`24.0.0`, say) passes
on every rung without knowing LF19. So a subject can route around this seat by hedging upward.
Whether one does is a result (§9 second amendment). The prompt says what is graded and that the
oldest-ness is not.

**The range is narrower than the fact, and the grader follows the range.** LF19 says ">= 20.19.0".
The manifest admits neither 21.x, nor 22.0.0–22.11.x, nor 23.x, and at 7.0.0 nothing from 25. So
`22.0.0`, which the fact's sentence licenses, is a `false` here. The prompt asks for the oldest
release, and there the sentence and the manifest agree (20.19.0), so the gap reaches only an answer
that is not the oldest. That includes a PACK-arm answer that reads the pack's ">= 20.19.0" and then
hedges upward into a gap. Recorded now, because it is the one way this seat can mark a pack-guided
answer wrong. Handed to the data lane as **BACKLOG 1h-g**, not written to `facts.json`.

**The three-condition question** (LF15, LF10, LF25) asks about a correct answer that is a library API.
Here the answer is a value, checked against a field present on every rung, in one spelling, with one
meaning (npm's range grammar). All three conditions hold trivially, and nothing about the field
changes at the boundary except its contents, which is the fact.

**The evaluator is written into the assertion file**, because the repository takes no dependency.
It reads `||` alternatives of space-separated comparators (`>=`, `>`, `<=`, `<`, `=`, `^`, `~` and a
bare version, one to three numeric parts each). It throws on anything else, such as an x-range, a
hyphen range or a prerelease tag. A range it cannot read is the harness's blindness, and a `false`
would publish that as the subject's error. It is exported as `nodeRangeAdmits` so the check below
runs against the committed function rather than a copy. **Checked before it was trusted, against
npm's own semver 7.7.3** (the copy bundled with this machine's npm, used for the check only): 31
ranges, the ladder's three among them, × 770 versions = **23,870 pairs, no disagreement**. Seven
forms it must refuse all throw.

**Four guards throw rather than return `false`**, each the harness's failure and not the subject's:
no manifest where the rung's `prisma` should be, a manifest whose `name`/`version` are not this
rung's prisma (the witness), no `engines.node` string, and a range the evaluator cannot read.
**Twenty-seven stub checks passed before the gate ran it** (JOURNAL/118's rule). They were: all four
guards plus a throwing reader; the evaluator refusing an x-range and a hyphen range; partial versions,
a range given as the answer, a prerelease and a leading zero, all `false`; `v20.19.0` and surrounding
whitespace, `true`; and the grid 18.18.0 / 20.18.3 / 22.0.0 / 22.12.0 / 24.0.0 against the 7.10.0
range, 25.0.0 against 7.0.0's, and 18.18.0 / 18.17.1 against 6.x's.

**What a failing round hands back** is the manifest's own `engines` object, verbatim, and the release
it does not admit. At 7.10.0 for the stale artifact: `the installed prisma 7.10.0 declares "engines":
{"node":"^20.19 || ^22.12 || >=24.0"} in its own package.json, and that range does not admit Node.js
18.18.0`. That is the answer at round 1 in every arm. So, as with A7 and A8, this seat's
`rounds_to_pass` can separate the arms by one round at most, and its round-0 cell is where any
difference will show. Recorded before any arm.

**Seen on the way, and only recorded here.** These are the other two clauses' shadows in the same
manifests, read at 6.0.0, 6.19.0, 7.0.0, 7.1.0 and 7.10.0 only, on `prisma` and `@prisma/client` alike.
`peerDependencies.typescript` is absent at 6.0.0, `>=5.1.0` at 6.19.0 and `>=5.4.0` at 7.0.0, 7.1.0
and 7.10.0. That is a possible executable row for the TypeScript clause. Neither package declares a
`"type"` field at any of those five rungs, so "ships as an ES module" is not visible in the packages'
own manifests, and its evidence, if the Index wants a probe for it, is somewhere else. Nothing here
says either clause is wrong. Both observations are in BACKLOG 1h-g.

**The seat.** A9 = LF19, its drawn fact. The S1 reserve is unchanged: LF8 is the one unspoken-for
entry. **Previously-charged subset:** LF19 was not charged, so it stays at **6 of 12** as the set
stands (A4, A7, A8, A10, A11, A12). That is reported here and feeds into nothing.

**Nothing else moved.** A1–A8 were re-gated after A9 was added to the manifest and the assertion file.
All nine were admitted. The gate's stdout differed from the run captured before the first edit only
by A9's three lines and the count (`8 of 8` → `9 of 9`), and its stderr was **byte-identical**. The
probe file was not touched. Gate selftest 46, runner 42, MCP 54, identifiers 35. Counts are unmoved at
161 runs / 167 findings (160 chargeable) over 8 libraries.

**What is left of BM2:** three drawn Class A assertions — A10 (LF12) and A11 (LF35), both S2 with a
two-deep reserve (LF11, LF34), and A12 (LF6), S3 with no reserve, so a refusal there drops the seat
(property 2 above) — then the six Class N tasks, the A1 question above, BM2's predictions, and the
arms. **Nine of twelve Class A seats are filled and admitted**, five of them from the reserve, and the
S1 stratum is full. Six facts have been refused: LF14, LF15, LF7, LF21 and LF25 were drawn, and LF10
was a substitute.
## A10 (LF12, the postinstall hook) authored and ADMITTED 2026-09-11 — `falling @7.0.0` (JOURNAL/147)

A10's drawn fact is **LF12**: *"Prisma 7 runs nothing implicitly. The postinstall hook no longer runs
`prisma generate`, and `prisma migrate` no longer runs `generate` or the seed script."* It is the first
S2 seat, and the second drawn fact in a row, after A9, to be admitted in its own seat. It needed no
amendment. It needed one new instrument, `installSteps` in `tools/audit/probes/prisma.mjs`, additive,
used by no probe. The gate admits it:

```
  ADMIT  A10  A  LF12  falling   @7.0.0
         correct  +++++++++++++++++++++++
         stale    ++++++++++++...........
```

on the same twenty-three installed releases as A1–A9. The answer is the Dockerfile's dependency
steps, as commands (`export const steps = [["npm", "ci"], ...]`). The reference is LF12's own
`correct_code` minus the application build: `npm ci`, then `npx prisma generate`. The stale artifact
is its `stale_code` minus the build: `npm ci` alone.

**The graded clause is the hook, and the probe chose it, not this lane** (A7/LF10's rule). LF12 has two
clauses. `probes.LF12` executes one: whether the installed `@prisma/client` declares a `postinstall`
script. The `prisma migrate` clause has no probe row, so a task resting on it would rest on a release
note (§7 rule 1, sixth amendment).

**The survey ran before any task file existed.** First the lifecycle scripts, read off all
twenty-three installed manifests:

```
  prisma            preinstall "node scripts/preinstall-entry.js"   on all 23 rungs
  @prisma/client    postinstall "node scripts/postinstall.js"       on all 12 6.x rungs
  @prisma/client    (no install-time script)                        on all 11 7.x rungs
```

That is the probe's reading. It says a hook is declared and nothing about what it does, and what it
does is the belief under test. So the survey then ran the hook: three artifacts on all twenty-three
rungs, in a project directory holding the prompt's `package.json` and schema.

```
  npm ci                          ++++++++++++...........
  npm ci, npx prisma generate     +++++++++++++++++++++++
  (no steps)                      .......................
```

**What the harness had to do to make the 6.x half of the stale row the hook's, and each step was
measured both ways before it was kept.**

- **A real-install layout.** The ladder is `per-rung-alias`: the CLI sits at `node_modules/prisma-6-19-0`,
  and a hook looking for `prisma` finds nothing there. So `installSteps` builds a fresh project whose
  `node_modules` holds the rung's `prisma` and `@prisma/client` as directory junctions under their
  real names. It removes the project before and after every call. `fs.rmSync` removes a junction
  without following it, which was checked against a scratch target before anything touched a rung.
- **`--preserve-symlinks`.** Without it the hook resolves its own real location inside the rung. It
  then looks for `prisma` beside itself and writes its placeholder client into the rung's shared
  `node_modules/.prisma`. With it, the placeholders land in the project, and the rung's `.prisma` is
  untouched on all twenty-three rungs (listing and mtimes compared before and after).
- **A POSIX bin lookup, from 6.5.0 only, and it is the one place the harness stands in for the
  platform.** From 6.5.0, `prisma`'s own export map sends `.` to `./build/types.js`, which the
  package does not ship. On 6.0.0–6.4.0 there is no `exports` and `main` is `build/index.js`. So from
  6.5.0 the hook's `require.resolve("prisma")` fails, and it falls back to `exec("prisma -v")` and
  `spawn("prisma", ...)`, taking the CLI off PATH. On Linux, which is the prompt's platform, npm puts
  `node_modules/.bin` on PATH, and the bin there is a link to `build/index.js`. On this Windows harness
  Node's `spawn` cannot run npm's `.cmd` shim without a shell. So a `--require` preload maps a bin name
  the two packages declare to `node <that bin's file>` and touches no other command. **Measured both
  ways.** With it, both rewrites fire at 6.5.0 and 6.19.0 and neither at 6.0.0 or 6.4.0, and the hook
  generates on all twelve 6.x rungs. Without it, 6.0.0–6.4.0 still generate, and 6.5.0–6.19.0 print
  `warning In order to use "@prisma/client", please install Prisma CLI` and generate nothing. That is
  a false below the boundary that would have been this harness's, not LF12's.
- **The inherited environment is stripped of `PRISMA_*` and `npm_*`**, because
  `PRISMA_SKIP_POSTINSTALL_GENERATE` in the operator's shell would switch the hook off silently.

**The criterion.** A generated client must exist at the schema's output path after the steps. It is
read the way A5 reads it: the generated client's own `package.json`, carrying a `main`, and the file it
names. The schema is A5's (`prisma-client-js` with `output = "./generated/client"`), for A8's reason.
Without an `output`, the 6.x generator writes into the install's own `node_modules`, which here is the
rung's. `package.json` lists both packages under `dependencies`, so `--omit=dev` has nothing to omit
and the grader does not have to model it. The prompt says so.

**The three-condition question** (LF15, LF10, LF25) asks whether the correct answer's destination
exists below the boundary, in one spelling, with one meaning. Here the correct answer is two commands,
`npm ci` and `npx prisma generate`, and both run on every rung. `generate` does not write the same thing
on every rung (A8's measurement: an engine library on 6.x, a query-compiler `.wasm` from 7.0.0), and
that is harmless for the same reason it was for A8. The criterion reads the generated client's
manifest, which exists with a `main` on all twenty-three rungs, and never reads the engine.

**What is graded and what is not.** Two kinds of command are run, and the prompt names them. The
first is `npm ci` / `npm install` / `npm i`, with flags and no package names; `--ignore-scripts` is
honoured, and no other flag changes anything. The second is `npx prisma <args>`, which must come after
an install, because the grader does not reach the network. A command that exits non-zero stops the
sequence, as a failing RUN stops `docker build`. Not graded: the application build, image size, layer
caching, and anything that needs a database.

**Three guards throw rather than return `false`**, because the stale verdict from 7.0.0 is an absence
and a blind harness produces one too:

- **The canary.** `npm ci --ignore-scripts` plus `npx prisma generate` must leave a client on the rung.
  It does not depend on LF12, and it checks the layout, the CLI and the reader.
- **The witness.** An install step run without `--ignore-scripts` must show every install-time script
  the two manifests declare as executed.
- **A manifest that parses but carries no `main`, or names a missing file**, is not a client's manifest.

`installSteps` also throws on a script it cannot run the way npm would, and on a process that did not
finish. **Thirty-four stub checks passed before the gate ran it** (JOURNAL/118's rule). Twenty were the
command parser: `--ignore-scripts` and its `=true`/`=false` forms, npx flags, a whole command as one
string, a `&&` chain, a package name, `yarn`, `npm run build`, `npx tsc`, `prisma` before any install,
and more than ten steps. Fourteen were the verdicts: each guard made to throw, the absence returning
`false` with its transcript, a failing step and a failing install script each returning `false`, and a
present client returning `true`.

**What a failing round hands back** is the steps as npm and the CLI print them, followed by the sentence
that nothing wrote a client. npm's part is `$ npm ci`, then each script npm ran as `> <package>@<version>
<event>` / `> <script>`, with its output. At 7.10.0 for the stale artifact:

```
$ npm ci
> prisma@7.10.0 preinstall
> node scripts/preinstall-entry.js

After these steps there is no generated/client/package.json: nothing wrote a Prisma Client to
./generated/client, the schema's output path.
```

That tells a subject no hook generated. So, as with A7, A8 and A9, this seat's `rounds_to_pass` can
separate the arms by one round at most, and its round-0 cell is where any difference will show.
Recorded before any arm.

**Seen on the way, and handed to the data lane rather than written (BACKLOG 1h-h).** The broken `.`
entry in `prisma`'s export map is present at every rung read from 6.5.0 on, 7.0.0 and 7.10.0
included. It is why the 6.x hook takes the CLI off PATH from 6.5.0. Whether real `npm ci` on Windows
generated anything on 6.5.0–6.19.0 was **not** measured and is recorded as a question. Nothing LF12
states is wrong, and its date holds.

**The seat.** A10 = LF12, its drawn fact. The S2 reserve is untouched and two deep (LF11, LF34).
**Previously-charged subset:** LF12 was charged, and it was already counted, so it stays at **6 of 12**
as the set stands (A4, A7, A8, A10, A11, A12). That is reported here and feeds into nothing.

**Nothing else moved.** A1–A9 were re-gated after A10 was added to the manifest, the assertion file and
the probe file. All ten were admitted. The gate's stdout differed from the run captured before the
first edit only by A10's three lines and the count (`9 of 9` → `10 of 10`), and its stderr was
**byte-identical**. Gate selftest 46, runner 42, MCP 54, identifiers 35; all five `--check` builds are
green. Counts are unmoved at 161 runs / 167 findings (160 chargeable) over 8 libraries.

**What is left of BM2:** two drawn Class A assertions. A11 (LF35) is S2 with a two-deep reserve (LF11,
LF34). A12 (LF6) is S3 with no reserve, so a refusal there drops the seat (property 2 above). Then the
six Class N tasks, the A1 question above, BM2's predictions, and the arms. **Ten of twelve Class A
seats are filled and admitted**, five of them from the reserve. Six facts have been refused: LF14,
LF15, LF7, LF21 and LF25 were drawn, and LF10 was a substitute.

## A11 (LF35, the SQLCommenter socket) authored and ADMITTED 2026-09-11 — `rising @7.1.0` (JOURNAL/149)

A11's drawn fact is **LF35**: *"Prisma ships a first-party SQLCommenter plugin.
`@prisma/sqlcommenter-query-insights` appends query-insights metadata to statements as a trailing SQL
comment ... It plugs into the `comments?: SqlCommenterPlugin[]` option of the `PrismaClient`
constructor, which prisma added in **7.1.0**."* It is the second S2 seat and the third drawn fact in a
row, after A9 and A10, to be admitted in its own seat. It is BM2's second rising task and the only
seat whose fact is dated above the major. No amendment was needed. One new instrument was:
`runQueryWithGeneratedClient` in `tools/audit/probes/prisma.mjs`, additive and used by no probe. The
gate admits it:

```
  ADMIT  A11  A  LF35  rising    @7.1.0
         correct  .............++++++++++
         stale    .......................
```

on the same twenty-three installed releases as A1–A10.

**The graded clause is the socket, and the probe chose it, not this lane** (A7/LF10's rule). LF35 has
two probe rows. `probes.LF35a` is the plugin package's own npm version list. That is the same answer at
every rung, so the ladder cannot vary it and no task can put a boundary in it. `probes.LF35b` is the
`comments` option on the client. It is what dates the fact in prisma releases, and it is where the
bisector put 7.1.0.

**The instrument observes what the client sends.** The belief is that ORM-generated SQL cannot be
attributed back to the code that issued it, so a criterion about construction would grade nothing the
belief gets wrong. There is still no database on this ladder (JOURNAL/119), and JOURNAL/135 had already
recorded that a fact like this needs an instrument that observes a connection. The new helper runs
the answer's module against A3's generated client, in a directory of its own. Before it imports the
module, it replaces `connect`, `query` and `end` on `pg`'s own `Client.prototype` with a recorder that
keeps the text of every statement and answers each with an empty result. Then it runs
`prisma.user.findMany()`. The adapter, a pool, and anything a subject wraps around either all sit above
that point, so what reaches the recorder is what a database would have received. Nothing the answer
wrote is rewritten.

**The companion package is placed once, beside the ladder, at one version.** The plugin has no 6.x or
7.0.0 release, so it cannot be a same-version peer of each rung. The copy current at the graded release
(7.10.0) is extracted to `<ladder>/_companions/` and copied into the helper's directory on every rung, so
the harness is the same at every rung apart from prisma. It has no runtime dependencies at either end
of its version line (0.0.1 and 7.10.0, read off both manifests). A missing companion throws. **Before
the arms, the same copy has to be placed beside whichever tree the runner grades against.** The throw
names the command.

**The survey ran before any task file existed:** six candidate modules on all twenty-three rungs.

```
  A3's file, no comment                    .......................   (the canary; healthy on all 23)
  the plugin via `comments` (7.10.0 copy)  .............++++++++++
  the plugin via `comments` (0.0.1 copy)   .............++++++++++
  a hand-written plugin via `comments`     .............++++++++++
  LF35's stale_code, a pg.Pool subclass    .......................
  that subclass + $extends + ALS           .......................
```

Below 7.1.0, every rung read (6.0.0, 6.10.0, 6.19.0 and 7.0.0) refuses the option with
`PrismaClientConstructorValidationError: Unknown property comments provided to PrismaClient
constructor.` The three rows that rise do so at the same release whether the plugin is the copy
current at the graded release, the copy current at 7.1.0, or no package at all. So the rise belongs to
prisma's socket, not to the companion's version. At 7.1.0, 7.2.0 and 7.10.0 the plugin's statement
reads `SELECT "public"."User"."id", "public"."User"."email" FROM "public"."User" WHERE 1=1 OFFSET $1
/*prismaQuery='User.findMany%3Ae30'*/`, identical for both copies. The canary sends the same statement
without the comment on all twenty-three rungs.

**The criterion.** Every recorded statement that names the `User` table must end with a SQL comment
whose text contains the words `User` and `findMany`, in any case, and there must be at least one such
statement. The prompt states this in those words. It also says that the comment's keys, anything else
in it and how its values are encoded are not graded.

**The stale artifact is LF35's own `stale_code`**, which is the wrong code of the Sonnet 5 draw that
charged this fact (`data/prisma/sonnet-5-v5-a.json`, F1). `sqlcommenterSuffix`, the one name the draw
left undefined, returns the application metadata the original battery prompt asked for. A pool sees SQL
text and nothing else, so it cannot name the model or the operation. Its comment reaches the database
on every rung and fails the criterion on every rung.

**The AsyncLocalStorage row is one spelling, measured, and not a claim that no workaround exists.** It
carries the model and operation from a `$extends` query hook to the pool subclass. It sent no comment
at all, on any rung, so the store did not reach the pool on this ladder. That was not diagnosed. Whether
a subject finds a working route around the socket is a result (§9 second amendment), and the prompt
does not rule one out.

**What the prompt names and what it does not, recorded before any arm.** The prompt shows the service's
file as it is today (A3's reference form: `pg`, `@prisma/adapter-pg`, `@prisma/client`) and asks for
the change. So the seat does not also grade LF1's adapter requirement or LF3's removed option. It says
the answer may import a package the service does not depend on yet, and that the grader has a fixed
set of packages on disk and reaches no network. It does not name the plugin, just as A3's prompt did not
name the adapter it had on disk. A subject that imports any other package fails on Node's own
`ERR_MODULE_NOT_FOUND`, symmetrically in every arm. The grader's disk holds exactly one package beyond
A3's: the plugin.

**The three-condition question** (LF15, LF10, LF25) is about the correct answer of a *falling* task and
does not arise for a rising one. What a rising task has to show instead is that its falses below the
boundary are the fact's own, not the 7 dialect's (§9 seventh amendment). Here the canary, which uses the
same adapter and the same file shape, passes on all twenty-three rungs, and the boundary is a minor, not
the major's first rung.

**Guards, and what a failing round says.** The verdict of a stale answer is an absence (a statement
with no comment naming the query), and a stand-in that recorded nothing produces one too. So the
assertion runs the canary on every rung first. It must succeed, return an empty list and send at least
one `User` statement through the stand-in, or the assertion throws. **Twenty-six stub checks passed
before the gate ran it** (JOURNAL/118's rule). Seven made the canary guard throw, one made the answer's
helper throw, and the rest were the verdicts: an artifact with no source, a failing module, unreadable statements, no `User`
statement, no comment, a static comment, a comment mid-statement, a comment naming only one of the two
words, `users-service`, `findManyX`, SQL after the comment, a second comment closing the statement,
two statements with one bare, and the four that must pass (the plugin's own text, lower case, trailing
whitespace, and an uncommented statement that does not name the table). A failing round hands back
Node's own error, which below 7.1.0 is the constructor sentence above, or the statements sent without
the comment, verbatim.

**The seat.** A11 = LF35, its drawn fact. The S2 reserve is untouched and two deep (LF11, LF34), and no
S2 seat is open. **Previously-charged subset:** LF35 was charged, and it was already counted, so it stays
at **6 of 12** as the set stands (A4, A7, A8, A10, A11, A12). That is reported here and feeds into
nothing.

**Nothing else moved.** A1–A10 were re-gated after A11 was added to the manifest, the assertion file and
the probe file. All eleven were admitted. The gate's stdout differed from the run captured at HEAD
before the first edit only by A11's three lines and the count (`10 of 10` → `11 of 11`), and its stderr
was **byte-identical**. The manifest's `flip_test` block is byte-identical to the gate's own `--json`
output. Gate selftest 46, runner 42, MCP 54, identifiers 35; all five `--check` builds are green.
Counts are unmoved at 161 runs / 167 findings (160 chargeable) over 8 libraries.

**Handed to the data lane (BACKLOG 1h-i), not written:** LF35's note says the Index has not executed a
configuration snippet for the plugin. One has now been executed up to the driver on all twenty-three
rungs, and the `%3A` in the comment is the client's percent-encoding of the colon.

**What is left of BM2:** one drawn Class A assertion. A12 (LF6) is S3 with no reserve, so a refusal
there drops the seat (property 2 above), and this record has already cited LF14's shape in LF6's own
note. Then the six Class N tasks, the A1 question above, BM2's predictions, and the arms. **Eleven of
twelve Class A seats are filled and admitted**, five of them from the reserve. Six facts have been
refused: LF14, LF15, LF7, LF21 and LF25 were drawn, and LF10 was a substitute.

## A12 (LF6, the `prisma-client-js` deprecation) authored and REFUSED 2026-09-11 — the seat is dropped, and the Class A set is eleven (JOURNAL/151)

A12's drawn fact is **LF6**: *"The generator provider Prisma 7 documents, and tells you to move to, is
`prisma-client` ... `prisma-client-js` still works and is still accepted at 7.10.0, but the vendor
states it will be removed in a future release."* It is BM2's only S3 seat. Property 2 above fixed what
happens if it is refused, before its assertion existed, and this record had already cited LF14's
ignored-not-rejected shape in LF6's own note. It was authored in full and put through the gate anyway,
so the refusal rests on evidence. The gate refuses it:

```
  REFUSE A12.lf6 A  LF6   rising    @7.0.0
         correct  ......+++++++++++++++++
         stale    .......................
         the correct solution starts passing at 6.6.0, but LF6 was bisected to 7.0.0 — the assertion is testing something other than the fact
```

on the same twenty-three installed releases as A1–A11.

**The survey ran before any task file existed**, and it looked for anything at 7.0.0 that a subject's
answer could touch. Rows, on all twenty-three rungs:

```
  LF6 correct_code (prisma-client + output) generates        ......+++++++++++++++++
  LF6 correct_code writes client.ts                          ......+++++++++++++++++
  LF6 stale_code (prisma-client-js, no output) generates     +++++++++++++++++++++++
  LF6 stale_code writes client.ts                            .......................
  prisma-client-js with an output generates                  +++++++++++++++++++++++
  LF6 stale_code validates                                   +++++++++++++++++++++++
  A3's prisma-client-js client imports and constructs        +++++++++++++++++++++++
  ... and prints any line besides the harness's              .......................
```

The output of `generate` and `validate` for `prisma-client-js` was searched on every rung for
deprecation wording (`deprecat`, `will be removed`, `no longer supported`, `move to`). Nothing matched
that is about the provider. The one match is a different deprecation. At 6.6.0 and 6.7.0 an output-less
`prisma-client-js` block is warned that it *"is deprecated and will no longer be supported in Prisma
7.0.0"*. The sentence was read at 6.6.0; 6.7.0 matched the same search and its text was not read.
From 6.8.0 the warning is gone, and every 7.x rung still generates the block (LF4's note already says
so). So that warning dates nothing here either, and it is handed to the data lane (below).

**`prisma init`'s scaffold moved before 7.0.0, not at it.** Run in an empty directory on each rung up
to 7.0.0: the scaffold's generator names `prisma-client-js` at 6.2.0–6.7.0 and `prisma-client` at
6.9.0, 6.10.0, 6.19.0 and 7.0.0 (and at 7.10.0, read separately). Three rungs did not run on this
machine: 6.0.0 and 6.1.0 stop with `isError is not a function` under Node 24.13.0, and 6.8.0 stops on
the Windows ESM loader (`Received protocol 'c:'`). Those three are unread, not "none". **`init` was
kept off the 7.x rungs above 7.0.0 because at 7.10.0 it reached the network**: it printed
`Installing skills` and wrote `.claude/skills/`, `.windsurf/skills/`, `.agents/skills/` and a
`skills-lock.json` naming `prisma/skills` on GitHub. That happened once, in a scratch directory outside
the repository, before the survey was written. It did not happen at 6.19.0 or 7.0.0. A survey that
reaches the network is not a survey, so the loop does not run `init` there.

**The seat is refused by the boundary rule, and a second criterion was refused by the same rule at the
same rung.** The one behavioural way to tell which generator a block names is what generation writes,
so the committed criterion is A7's own: generation succeeds and a `client.ts` appears under the
project root. `A12_LF6` is A7's function, not a copy. The fact's `correct_code` is byte-identical to
A7's reference, because LF4 and LF6 share their correct answer, and its only rise is the generator's
arrival at 6.6.0, which is LF4's date. The fact's `stale_code` never flips. Grading LF6b's own clause
instead (generation succeeds) gives correct `......+++++++++++++++++` against stale
`+++++++++++++++++++++++`, refused with the same sentence. At the graded release both of those
artifacts pass, so that task would have separated nobody. It was run from a scratch manifest and a
scratch assertion, both deleted; neither is committed.

**The gate's sentence says "bisected to 7.0.0", and for this fact that is not true.** The gate reads
the fact's `introduced_in`. LF6's three probe rows are all declared flat, with no version claim
(`tools/audit/probes/prisma.mjs`, `claims`: `LF6: null, LF6a: null, LF6b: null`). Its 7.0.0 is the
vendor's announcement. Nothing bisected it.

**That is also how LF6 got into the pool, and it is a hole in §7 rule 1 as `draw.mjs` enforces it.**
Rule 1 says a fact's date is confirmed by an executable probe. The sixth amendment enforces it through
the fact's `measured_range`: the lowest and highest release at which the fact's *statement* was
executed. LF6's statement was executed on all twenty-three rungs, so it has a `measured_range`. But no
row of it carries its date. So a fact can pass rule 1 as enforced while its date is a release note.
Counted across every probe file in the repository: **LF6 is the only such fact of the 114 dated facts
with a `measured_range` in five libraries** (better-auth 13, prisma 30, react-router 9, valibot 19,
zod 43). Every other one has at least one row that carries a version claim.

What the hole cost BM2, stated as arithmetic and used for nothing. Without LF6 the pool is twenty,
S1 16 and S2 4. Largest remainder over twelve seats gives S1 10 and S2 2, and no S3 stratum. The draw
that was run gave S1 9, S2 2, S3 1. So a correct rule 1 would have seated one more S1 fact, and the
set would still have twelve seats. §7's sixth amendment forbids recomputing the quotas after seeing
which task failed, and this is that case, so nothing is re-drawn. BM2 ships eleven Class A tasks, as
property 2 already said it would.

**`draw.mjs` is not changed by this session.** Changing its eligibility now would change the tool that
produced this record, with eleven assertions already written against its output. The gate caught the
consequence here: a fact whose date has no executable shadow cannot give a task whose flip lands on
that date. It is recorded as a **candidate amendment to be decided before any BM3 draw is run**: rule 1
requires at least one probe row that carries the fact's own date (a non-null claim that is not flat),
not only a `measured_range`. Whether the gate's sentence should say "dated" rather than "bisected"
goes with it.

**What the shortfall changes, fixed now.** The Class A set is **A1–A11**, one short of the draw's
twelve, and the missing seat is **one S3 seat**. It is stated with its stratum on `/benchmark` and in
BM2's results file when they exist, as §7's sixth amendment requires. The Class N ratio for eleven is
still six (`build-index.mjs`: `classN === ceil(classA × 1 / 2)`), so all six null tasks are still owed.
**Previously-charged subset:** LF6 was charged and was counted, so the subset moves from 6 of 12 to
**5 of 11** as the set stands (A4, A7, A8, A10, A11). That is reported here and feeds into nothing.
Property 1's constraint stands and gets tighter. Ten of the eleven are dated 7.0.0 or earlier (A7 at
6.6.0), and one at 7.1.0. BM2 may publish counts of cells and tasks, and no interval that assumes the
tasks are independent.

**Nothing else moved.** A1–A11 were re-gated after `A12_LF6` was added to the assertion file. All
eleven were admitted. The gate's stdout and stderr are **byte-identical** to the run captured at HEAD
before the first edit. That also checks the note in `A12_LF6`: the stale artifact names no output, so
it generates into the rung's own `@prisma/client`, where A3's client lives. Every gate process
regenerates that client on first use, so the survey's twenty-three writes there moved nothing.

**Handed to the data lane (BACKLOG 1h-j), not written:** the 6.6.0–6.7.0 warning that predicted a
removal 7.x did not carry out; the `init` scaffold's move to `prisma-client` at 6.9.0 (6.8.0 unread),
which bears on LF6's "tells you to move to"; and `init` at 7.10.0 fetching agent skills from GitHub.

**What is left of BM2:** the six Class N tasks, the A1 question above (settle it before the first
arm), BM2's predictions, then the arms. **The Class A set is complete: eleven tasks, all admitted,
five of them from the reserve.** Seven facts have been refused: LF14, LF15, LF7, LF21, LF25 and LF6 were
drawn, and LF10 was a substitute.

## Addendum — 2026-09-11, a fact added that the pool would now hold (JOURNAL/152)

Written by the **data lane**, under the rule it follows for BM1's draw record (BACKLOG 11k-t-iii-b):
when `data/<lib>/facts.json` changes after a draw, the draw record says what the recorded command now
prints and why. This session changed one thing in `data/prisma/facts.json`: **one fact was added,
LF37**, `generator client { runtime }`. From **6.15.0** (2025-08-27) the `prisma-client` generator
refuses `runtime = "vercel"`, `"node"` and `"deno-deploy"` and takes `"vercel-edge"`, `"nodejs"` and
`"deno"`. It is S1 (`breaks-build`: `prisma generate` exits 1) and was bisected on 28 rungs. **No
existing fact was edited.**

**Unlike every fact BM1's addenda recorded, this one is eligible for this pool.** 6.15.0 is above
Claude Sonnet 5's measured prisma boundary (6.0.0) and below its stated cutoff (2026-01), and the fact
has a `measured_range`. So the recorded command now prints a different set. It was re-run against the
edited file and against an untouched `HEAD` worktree, and the two JSON outputs were diffed. They differ
in four places: `facts_sha256`; the pool, which is **22** (LF37 added to S1, now 17); the drawn set,
where LF37's order key (`0a0b26b4…`) sorts second in S1, so it prints as **A2** and every later S1
seat moves down one; and the reserve, where **LF19**, admitted as A9 on this record, prints as **S1
#10**. The quotas are still **9 / 2 / 1**, the exclusions are unchanged, and S2 and S3 are unchanged.

**The frozen record governs, and nothing is re-drawn.** The draw was committed at 2026-09-10 02:17
UTC (`f72d6d4`). The rename was first measured in JOURNAL/134, committed at 2026-09-11 00:23 UTC, and
filed as a fact today, so nothing about it was known when the draw ran, and a draw recomputed after its tasks have been admitted would be a draw steered by
them. This is the same reasoning as the sixth amendment's dropped S3 seat. The counterfactual above is
arithmetic, recorded so that a third party who re-runs the command sees a stated difference rather
than an unexplained one. The `HEAD` copy hashes **`140ae707…`**, the value recorded above, so that hash
reproduces. `facts.json` sha256 is now **`48041eaa…`**.

**One consequence for the arms.** The PACK arm is `corrections/prisma.md` as committed when the arms
run, and that pack is now longer by one entry. No BM2 task is about the generator's `runtime` key, so
the entry gives no task its answer. It does add characters to every PACK round, and the results should
state the pack's size at run time, as BM1's did.

## Addendum — 2026-09-11, one fact's statement corrected (JOURNAL/153)

Written by the **data lane**, under the same rule as the addendum above. This session changed one
entry in `data/prisma/facts.json`: **LF7** (`prisma.config.ts`). Its third sentence said the file "was
introduced as opt-in in 6.18.0"; executed on 31 releases, the CLI loads the file from 6.5.0 and honours
its `schema` path from 6.6.0, and a config exported as a plain object needed `earlyAccess: true` until
6.13.0. The sentence was rewritten to that, a `note` and a 6.13.0 citation were added, and its
`measured_range` now cites the 31-rung run. Its `introduced_in` (7.0.0), severity and `change_kind` did
not move. **No fact was added and no other fact was edited.**

**The draw does not move.** The recorded command was re-run against the edited file and against an
untouched `HEAD` worktree, and the two JSON outputs differ in exactly one field, `facts_sha256`: the pool,
quotas, drawn set, reserve and exclusions are identical. The `HEAD` copy hashes **`48041eaa…`**, the value
the previous addendum records, so that hash reproduces. `facts.json` sha256 is now **`6faf8d7f…`**.

**One consequence for the arms, as before.** LF7 was drawn and refused (A6), and no admitted task is
about when the config file arrived, so the corrected sentence gives no task its answer. The PACK arm's
pack is a few sentences longer in LF7's entry.

## Addendum — 2026-09-12, one fact corrected INTO the pool (JOURNAL/154)

Written by the **data lane**, under the same rule as the two addenda above. This session changed one
entry in `data/prisma/facts.json`: **LF9** (`prisma.config.ts` `engine` / `adapter` keys). Its
statement said both keys "existed only in the 6.18.0–6.19.x window"; type-checked on all 31 stable
minors, that is true of `engine` and false of `adapter`, which the config type has declared since
6.12.0 and accepted alone since 6.13.0. The statement was rewritten to that, a `note` and a 6.13.0
citation were added, and a `measured_range` (31 rungs) was recorded for the first time. Its
`introduced_in` (7.0.0), `severity` (S1) and `change_kind` (`removed`) did not move. **No fact was
added and no other fact was edited.**

**The recorded command now prints a different drawn set**, because until today LF9 was in
`excluded` under §7 rule 1 — *date never executed: no measured_range* — and giving it one makes it
pool-eligible: 7.0.0 is above Claude Sonnet 5's measured prisma boundary and below its stated cutoff.
Re-run against the edited file and against an untouched `HEAD` worktree, the two JSON outputs differ
in five places: `facts_sha256`; the pool, now **23** (LF9 added to S1, now 18); `excluded`, one entry
shorter; the drawn set, where LF9's order key (`1ef60c97…`) sorts fifth in S1, so it prints as **A5**
and every later S1 seat moves down one — **LF25, admitted as A9 on this record, is displaced out of
the drawn set entirely**; and the reserve, where LF25 prints as **S1 #10**. The quotas are unchanged
(**9 / 2 / 1**), and S2 and S3 are unchanged.

**The frozen record governs, and nothing is re-drawn.** A5 through A9 keep the facts this record
assigns them, and A9 (LF25) keeps its admitted task. The draw was committed at 2026-09-10 02:17 UTC
(`f72d6d4`); LF9 carried no `measured_range` then because no instrument existed that could execute
it — the CLI ignores both keys at 7.x, and the type check that can read them was written today. A
draw recomputed after its tasks have been admitted would be a draw steered by them, which is the
sixth amendment's reasoning and the reason the S3 seat stayed dropped. The counterfactual above is
arithmetic, recorded so that a third party re-running the command sees a stated difference rather
than an unexplained one. The `HEAD` copy hashes **`6faf8d7f…`**, the value the previous addendum
records, so that hash reproduces. `facts.json` sha256 is now **`60f24568…`**.

**One consequence for the arms, and one for a future draw.** LF9's entry in the PACK arm is longer by
a sentence, and no admitted BM2 task is about the config file's `engine` or `adapter` key, so it gives
no task its answer. The consequence for a future draw is worth stating plainly: §7 rule 1 excludes a
fact for want of an instrument, so **which facts a pool holds is partly a record of which ones the
harness has learned to execute** — LF9 was outside this pool for a reason that has nothing to do with
the fact and everything to do with us. BM3's draw should be taken after the probe file is worked, not
before.

---

## Build order item 2 — the six Class N tasks, admitted 2026-09-11 (JOURNAL/155)

**BM2's task set is complete at seventeen: eleven Class A and six Class N.** `build-index.mjs` reads
the ratio as `classN === ceil(classA * 1 / 2)`, which for eleven is six, so the dropped S3 seat
(A12) changed the Class A count and not this one. Class N is **authored, not drawn** — it depends on
no fact in the pool — and this section records how the six were arrived at, because a set that shows
only its survivors cannot be told apart from one that was written until it passed.

**The discipline is BM1's step 4c, and it ran first.** Eight candidate propositions were measured on
all twenty-three rungs of the gate ladder **before any of the six tasks was authored**, through the
probe file's own `subject()`. All eight came back flat (`+++++++++++++++++++++++`). Six shipped; two
are kept as spares and are named below. A proposition that had been written after its assertion
would be a null task chosen for being easy to assert.

**Each of the six sits beside a correction, never away from one.** §6 makes Class N the only place
the pack can be caught doing harm — refusing a fine API, pinning a version nobody asked about,
rewriting working code toward a correction that does not apply — and a null task on an unrelated
corner of prisma would pass in every arm and measure nothing the Class A tasks do not.

| id | the everyday job | neighbourhood in the pack |
|---|---|---|
| N1 | a composite `@@unique` and a composite `@@index` on a multi-tenant membership | LF26 (`where:`, added 7.4.0) and LF27 (`include:`, which prisma has never had) |
| N2 | a three-value status enum whose members are stored under their own names | LF18 (an enum member's `@map`, 7.3.0) |
| N3 | legacy column and table names behind application names (`@map`, `@@map`) | LF18 from the other side — the same word on a field and a model, which never moved |
| N4 | a CI step that fails when the schema is not formatted (`format --check`) | LF13, LF15, LF16 — three corrections that each say a piece of the command line is gone |
| N5 | a table written down and deliberately unreachable (`@ignore`, `@@ignore`) | LF16, LF17 — tables and datasources the Index says are no longer reachable |
| N6 | an author/posts relation with referential actions and an index on the foreign key | LF26/LF27 again, and LF24's changed defaults |

**The artifact never spells a datasource block, and on this library that is forced.** The build order
above said it before any of these existed: the ladder crosses the major that removed `url` from the
datasource block (LF8), so a null artifact carrying one is version-dependent whichever way it spells
it — a charging task nobody meant to write, and B4 would read that version effect as harm done by
the pack. So five of the six produce the **model blocks only** (`produced.form: "text"` as
`"models"`) and `tools/benchmark/tasks/prisma.mjs` supplies the two blocks around them, identical in
every arm and never shown to a subject. The sixth, N4, produces an argv, which is A2's shape.

The supplied generator is `prisma-client-js` with an explicit `output`, and that too is the ladder's
choice rather than a preference: the `prisma-client` provider arrives at 6.6.0 (LF4), so a preamble
naming it would put a boundary into every null task at a release that is about the generator and not
about the task. It is the provider LF6 calls deprecated, and it generates on all twenty-three rungs —
measured for A12 on 2026-09-11 and again here.

**Two candidates were refused before the eight, and both refusals are about this library rather than
about the tasks.**
1. **`prisma migrate diff --from-empty --to-schema-datamodel app.prisma --script`** — refused
   because it is not a null task at all. It produces SQL at 6.0.0 and at 7.10.0 answers
   `` `--to-schema-datamodel` was removed. Please use `--[from/to]-schema` instead. `` That is LF15,
   whose `also_known_as` already carries `--to-schema-datamodel`: the proposition charges a fact in
   the pack, which is the one thing a null task may not do.
2. **A model using native type attributes** (`@db.VarChar(64)`, `@db.Timestamptz(3)`) — refused as an
   artifact shape, not as a proposition. Native types are resolved against the datasource's
   connector, so the fragment does not validate without a datasource block
   (`Native type VarChar is not supported for Default connector`), and a Class N artifact may not
   carry one. The same job survives inside N3, which maps names rather than types.

**The two spares**, both measured flat and both shippable if one of the six ever has to be replaced:
an optional column with `@default(now())` and `@updatedAt` (nullable in the generated client on every
rung), and `prisma validate --schema=<file>` as an invocation.

**One refusal inside the six, and it is worth keeping.** N3's first assertion asked whether the
database's column name `cust` was absent from the generated declarations — and `customer`, the
application's own name for that field and a thing the same assertion *requires* to be present,
contains it. The gate refused N3 at every rung, `.......................`: an assertion that could
never have passed, on a task whose proposition had already been measured flat. It is
`tools/lib/identifiers.mjs`'s fourth rule arriving from the other direction — there a substring
manufactures a presence, here it manufactured an absence that could not be cleared — and the fix is
that rule: absences are matched identifier-wise, the name is validated rather than escaped, and each
caller asserts something **present** first so that an empty or unrelated blob fails before any
absence is read.

**The gate's own record.** Seventeen of seventeen admitted, on the 23-rung ladder through
`tools/audit/probes/prisma.mjs`'s `subject()`, `per-rung-alias` layout, control true on every rung.
Every Class N row is `+++++++++++++++++++++++`. A1–A11's rows and the gate's whole stderr are
byte-identical to the run taken before N3's fix, so nothing the Class N half added moved a Class A
admission.

**What is left of BM2:** the A1 question (settle it before the first arm), BM2's predictions in §10's
form, then the arms.

## Build order item 3a — the A1 question, SETTLED 2026-09-12 by option (a) (JOURNAL/157)

The question this record opened on 2026-09-11 — *A1's answer is a whole schema, and a schema carries
a datasource block whose spelling LF8 moved* — is closed, before the first arm, the way it had to be
closed to leave the cells meaning what they say. **Option (a): the harness supplies the datasource
block; A1's answer is the rest of the file.** The rule behind it is written into
`prompts/benchmark.md` §9 as the **tenth amendment**, because it is not about prisma: it is about any
task whose artifact must carry a part the task's own fact is not about, on a ladder that crosses the
release that changed that part.

**Why (a) and not (b).** Option (b) — keep A1 as admitted and attribute each failing cell by the
sentence the toolchain printed — was measured too, and it fails on its own terms. The sentences do
not partition the way (b) needs. With the block supplied, an answer that writes its own is refused at
6.0.0 with `You defined more than one datasource` and at 7.10.0 with LF8's `url ... no longer
supported` **when it names the block something other than `db`**, and with `The source "db" cannot be
defined because a source with that name already exists` at both rungs when it does not. A rule that
reads error text to decide what a cell measured would have to enumerate those, and it would be
reading a vendor's wording as if it were an instrument — the thing the gate refuses to do everywhere
else (`the gate reads verdicts and never sentences`, JOURNAL/141). Option (a) removes the confound
from the **verdict**, which is the thing the published number is made of.

**The measurement that settles it**, A1's own reference body at both ends of the 23-rung ladder,
through the same `subject.validate` the assertion uses:

```
  what the answer's datasource block carries            6.0.0                        7.10.0
  url = env("DATABASE_URL")                             invalid (env var not found)  invalid (LF8 P1012)
  a literal connection string                           VALID                        invalid (LF8 P1012)
  nothing — no datasource block, harness supplies one   VALID                        VALID
  the same, and the answer writes one anyway            invalid (duplicate source)   invalid (duplicate source)
```

Row 2 is the confound in its live form: the same answer, differing only in a block the task is not
about, is correct below the major and wrong at the graded release. Rows 3 and 4 are the settlement:
with the block supplied, the verdict no longer depends on which side of the major the rung is on.
A fifth row, measured because it was cheap and because it explains why supplying the block is better
than merely forbidding it: a schema with **no datasource block at all** validates at 6.0.0 and at
7.10.0 alike, so an instruction alone would have left a subject that ignored it back on row 2.

**What changed, exactly.** `produced.as` is now `schemaBody`; both committed artifacts export that
name and neither spells a datasource block; the assertion prepends `A1_DATASOURCE`, which is also
what `N_PREAMBLE` is built from, so the Class A half and the null half are graded against the same
supplied block; and the prompt says the `datasource db` block is already there, asks for the
generator block and the model, and forbids a second one. The fact, the seat, the shape, the severity
and the draw are untouched.

**The gate's own record.** Seventeen of seventeen admitted, and **the whole run's stdout and stderr
are byte-identical to the run taken at HEAD before the change** — A1's two rows
(`+++++++++++++++++++++++` against `++++++++++++...........`, falling at 7.0.0) included. Both runs
on the 23-rung ladder through `tools/audit/probes/prisma.mjs`'s `subject()`, `per-rung-alias` layout,
control true on every rung, 6m35s and 6m37s. `N_PREAMBLE`'s bytes are asserted unchanged against the
literal the six null tasks were admitted with.

**What is left of BM2:** BM2's predictions in §10's form, then the arms. Every other item in this
lane is one of the eight asks: D2's four and D3's four.
