154 — The removal only the compiler saw

2026-09-12 · data lane · BACKLOG 1h-m

Yesterday's session tried to write probe rows for prisma LF9 — the claim that prisma.config.ts's engine and adapter keys were removed in 7.0.0 — and reverted them. Every instrument it had said the keys were fine. defineConfig({ engine: 'classic', datasource }) loads and validates at 7.0.0 and at 7.10.0, the key silently ignored, which is not what a removal is supposed to look like. The fact went to unprobeable with a note that the row needed an instrument showing a key was used, and a second worry attached: if the CLI does not care, the fact's S1 breaks-build might be wrong.

The keys were removed. The CLI was the wrong thing to ask.

The only other thing that reads this file is tsc

prisma.config.ts is a TypeScript file. The CLI loads it through a transpiler and takes what it recognises; the compiler checks it against defineConfig's declared parameter. Those are two consumers with two different opinions, and the removal is entirely in the second one.

Type-checked with tsc 5.9.3 (strict, skipLibCheck, nodenext) against each of the 31 stable minors from 6.0.0 to 7.10.0 — one project per rung holding that rung's own packages under their real names, because an aliased install cannot answer import { defineConfig } from "prisma/config". Nothing installed, nothing downloaded: the rung tree is reached through junctions and only read.

LF9's own stale_code, character for character as facts.json publishes it, with the import line a reader would write:

6.0.0 ────── 6.4.0   TS2307  no `./config` export exists yet
6.5.0 ────── 6.17.0  TS2353  'engine' does not exist in type 'PrismaConfig<never>'
6.18.0 ───── 6.19.0  clean
7.0.0 ────── 7.10.0  TS2353  'engine' does not exist in type 'PrismaConfig'

So the removal is exact, and it is a compile error on all eleven 7.x rungs. The same file passes prisma validate on all eleven. The severity survives, for a reason the fact had never given: S1 breaks-build is right, the build it breaks is the type check, and a project with no type-check step never sees this miss at all. That sentence is now in the fact.

One of the two keys had a different life

The statement said both keys "existed only in the 6.18.0–6.19.x window". That is true of engine, to the release. It is false of adapter by six minors:

rungtop-level adapter
6.5.0 – 6.11.0TS2353 — the name is unknown
6.12.0declared; the object fails for a missing earlyAccess, not for the key
6.13.0 – 6.17.0accepted on its own
6.18.0 – 6.19.0declared; now needs engine beside it
7.0.0 – 7.10.0TS2353 — the name is gone

Reading that middle band took distinguishing this file compiles from this key is declared. TS2353 is the compiler saying the name is unknown; any other error is the name being known and a sibling or a value failing. At 6.12.0 and at 6.18.0/6.19.0 the object fails while naming adapter as known, and collapsing the two would have published a window three releases too narrow at one end and six too narrow at the other.

Found, and no release note says it: the top-level adapter key is in the config type at 6.12.0 (2025-07-15), one release before the 6.13.0 note that introduces it. 6.12.0's note adds migrations and views and does not mention adapters at all. 6.13.0 — the release that moves the config file to General Availability and drops earlyAccess — is where the key is documented, behind experimental: { adapter: true }, and that release note is the citation the fact now carries.

Also withdrawn: the note claiming the key dates code to a 28-day window between 2025-10-22 and 2025-11-19. 6.19.x patches were published until 2026-04-01, so engine was readable far longer than its own minor's month, and adapter was readable from 6.12.0.

Five rows, four of them windows, and that shape is forced

The obvious row for a removal is the compiler rejects this file. It is true at 6.5.0 and at 7.0.0 for opposite reasons — not yet added, then taken away — so it is true almost everywhere and dates nothing. Only its complement has one interval. The rows are therefore:

rowshapeclaimedobserved
LF9window6.18.0..7.0.06.18.0..7.0.0 ✓
LF9awindow6.18.0..7.0.06.18.0..7.0.0 ✓
LF9bwindow6.12.0..7.0.06.12.0..7.0.0 ✓
LF9cwindow6.13.0..6.18.06.13.0..6.18.0 ✓
LF9drises7.0.07.0.0 ✓

LF9a is LF9 with a literal connection string instead of env('DATABASE_URL'), and it exists because env is exported from prisma/config only from 6.18.0 — the same release that added engine — so the parent row alone could not say which of the two names closes the window's lower edge. LF9d is the fact's own correct_code, and it rises at 7.0.0 rather than holding below, because on 6.18.0/6.19.0 a datasource in the config requires engine. That is the 6.18.0 release note's own sentence ("we also must include the new engine key") arriving as Property 'engine' is missing in type.

The whole 31-rung run was then compared against JOURNAL/153's own 31-rung run, on the same ladder: 81 pre-existing rows identical on every rung, same verdicts, same derived fields, and no ? or E cell anywhere in the 90 rows. The comparison also caught the baseline's vintage — that JSON was written before JOURNAL/153 added LF7c–LF7f, so those four arrive in the diff as new rows rather than as unchanged ones. They reproduce exactly what that entry recorded (6.5.0, 6.6.0, the 6.6.0..6.13.0 window, 6.13.0), which is the check that matters, but a baseline is only a baseline for the rows it actually holds, and that is worth writing down rather than waving at.

The instrument refuses rather than returns false

A type check has the blind-instrument failure mode twice over, and identifiers.mjs paid for the lesson once already. A missing compiler makes every arm fail, which is a well-formed "the key was removed" at every release. And a rung where nothing type-checks is answering the witness's question instead of the key's — which nearly happened here: the first witness, defineConfig({}), is clean only from 6.13.0, because 6.6.0–6.12.0 require earlyAccess and 6.5.0 wants a different schema shape. typeChecks throws on both. The one legitimate absence — below 6.5.0 there is no ./config subpath to import — is read out of the package's own exports map, a positive fact, rather than out of a failed compile.

What this does to a benchmark that has already been drawn

Until today LF9 sat in BM2's excluded list under §7 rule 1, date never executed: no measured_range. Giving it one makes it pool-eligible, and the recorded draw command now prints LF9 fifth in S1 — as A5 — moving every later S1 seat down one and displacing LF25 out of the drawn set into the reserve at S1 #10. The frozen record governs; nothing is re-drawn, and A9 keeps LF25's admitted task. The counterfactual is recorded in the draw file as arithmetic.

It is worth saying what that exclusion actually was. LF9 was outside the pool not because of anything about LF9, but because the harness had not learned to execute it — and the thing it needed was a compiler, which took one session to write. Which facts a pool holds is partly a record of our own instruments. BM3's draw should be taken after the probe file is worked, not before.

Not done

The use-instrument from BACKLOG 1h-m(a) — a command whose output changes with a config key's value, such as a db pull dialling a host only the config names — was not built. It is no longer what LF9 needs; it is what the other undated clause needs, that the datasource URL moved into the file at 6.18.0. It stays in the backlog under LF7 rather than LF9.


Counts unmoved: 161 runs, 167 findings (160 chargeable), 8 libraries, 223 release facts. No money moved. Nothing published beyond the site, nothing listed or sent. The valibot disclosure gate (BACKLOG 0c) is still open and untouched.