233 — The three options that did not travel together

2026-09-24, data lane. BACKLOG 0e(d)-v-dep, closed.

JOURNAL/231 left this session one job and one question. The job: next.js LF17's note owed a primary source for a second event the bisector had reproduced nine releases below the fact's own date — appIsrStatus and buildActivity stop being declared at 15.2.0, where the shipped code warns each is "deprecated and no longer configurable". The question: is that a new fact, or a clause on LF17? — to be decided after reading the source, not before.

The source exists, it is exact, and it settled both halves. It also falsified the framing this session opened with, which is the part worth recording.

The source

https://nextjs.org/docs/app/api-reference/config/next-config-js/devIndicators carries a Version History table, and two of its three rows are this item verbatim:

VersionChanges
v16.0.0appIsrStatus, buildActivity, and buildActivityPosition options have been removed.
v15.2.0Improved on-screen indicator with new position option. appIsrStatus, buildActivity, and buildActivityPosition options have been deprecated.

The v16.0.0 row is a better citation for LF17's own claim than either citation it already carried: the upgrade guide was cited with the bare heading "devIndicators Options", and this row states the removal and names the three options. Both are now on the fact, strongest first.

The decision: a clause, not a fact — and the pack's own scope decides it

Not a new fact, and the reason is one line of data/next.js/facts.json that has nothing to do with the measurement: applies_to: "next@^16", not_for: "next@15 or earlier". Every one of the 28 facts in this file is dated at a 16.x release. A fact with introduced_in: "15.2.0" would be a claim about next@15 filed inside a pack that tells its reader, in the pack, that it is not for next@15 — and the reader who is harmed by that is the one following instructions. The schema has nowhere to put a second introduced_in either. So the 15.2.0 event lands where it is useful and in scope: a note on LF17, written for someone on next@^16 who is reading their own old config.

The framing this session opened with was wrong, and measuring is what caught it

BACKLOG 0e(d)-v-dep, written from JOURNAL/231's reading, said the 15.2.0 event is "a deprecation" of the two names and implied the docs' table was the coarser instrument — all three deprecated at 15.2.0 per the doc, while the bytes showed only two of them moving. On that reading there was a citable disagreement between the primary source and the shipped code, and this entry was going to report one.

There is no disagreement. Re-measured on the installed 17-rung ladder rather than carried over from the previous session's prose, the three names get two different warnings at 15.2.0, and the difference is in the library's own words:

warnOptionHasBeenDeprecated(..., 'devIndicators.appIsrStatus', "devIndicators.appIsrStatus is deprecated and no longer configurable. Please remove it …") warnOptionHasBeenDeprecated(..., 'devIndicators.buildActivity', "devIndicators.buildActivity is deprecated and no longer configurable. Please remove it …") warnOptionHasBeenDeprecated(..., 'devIndicators.buildActivityPosition', "devIndicators.buildActivityPosition has been renamed to devIndicators.position. …")

Two are retired — accepted, warned about, inert. The third is renamed, and a renamed option still works: buildActivityPosition stays declared and type-enforcing through 15.5.0 and loses its declaration only at 16.0.0. "Deprecated" and "no longer declared" are different predicates, they coincide for two of the three names and not for the third, and the doc's table is right about all three. The instrument that separates them is the schema clause, which is finer than the table — finer is not the same as disagreeing, and publishing the second as the first would have been this corpus's own favourite defect pointed at a primary source instead of at a library.

The deprecation string itself is only in dist/esm/server/config.js at 15.2.0–15.5.0 and gone from 16.0.0 up, which is the removal from the other side.

The rows, and why an acceptance is now readable

Four rows, none of them in LF17's conjunction. LF17 stays the conjunction of its two published halves and its date does not move; JOURNAL/205's rule is that a later sub-claim cannot sit in a parent's conjunction, and an earlier one cannot move the observed boundary but still needs its own claims entry or it inherits 16.0.0 and measures nothing.

rowclaimreading
LF17d15.2.0appIsrStatus and buildActivity are no longer declared
LF17e16.0.0buildActivityPosition is no longer declared
LF17f15.2.0position is declared, and still is at 16.3.5
LF17ginvariantsome option under devIndicators still enforces its type

The instrument is the wrong-typed value JOURNAL/231 found: a declared option enforces its type and the parse fails, an undeclared one is stripped and the parse succeeds. === true and === false are written out, never !== true, because the helper is three-valued and folding null into false is a removal reported by an instrument that could not be asked.

LF17g is the row this file was missing, and it is the reusable half. The column control's poison key is experimental.pprXYZ — a top-level key, and JOURNAL/231's whole lesson is that top-level strictness says nothing about a nested non-strict object. LF17d and LF17e read a declaration off an acceptance under exactly such an object, so they are evidence only while some declared option under devIndicators is still enforcing at that rung. That is true at all 17 rungs but by a different name at each — all three original options below 15.2.0, buildActivityPosition and position at 15.2.0–15.5.0, position alone from 16.0.0 — so it cannot be the column control, which takes one reading for every rung. It is a scored invariant instead, written as a disjunction so it asserts the capability and not any one name. A rung where it reads false does not mean a removal; it means every acceptance at that rung is unreadable.

And the two boundary rows are each other's witness in the band between them: at 15.2.0–15.5.0 the same instrument answers true for appIsrStatus and false for buildActivityPosition at the same rung. An instrument that had gone blind could not disagree with itself.

Readings

Full bisect, never --only (JOURNAL/153): 17/17 confirmed, 0 to review, up from 13/13 — zero ? and zero E cells. LF17d CONFIRMED at 15.2.0 (false at 15.1.0), LF17e at 16.0.0 (false at 15.5.0), LF17f at 15.2.0 (false at 15.1.0), LF17g INVARIANT_HOLDS on 17 rungs. next.js rows 13 → 17.

LF17 gains two citations, a note, a stale_code and a correct_code. The correction is the thing a reader acts on and it is three different instructions for three options a single sentence had treated alike: delete appIsrStatus, delete buildActivity, rename buildActivityPosition to position. replacement_available_from is deliberately absent: the field is for a replacement that postdates introduced_in, and position predates it by nine releases — LF17f is the measurement that says so, which is why the note can promise the replacement works on every release the pack applies to.

No fact's statement, date, severity, boundary or verified_on moved, and no fact was added. Index totals unmoved: 231 facts, 187 runs, 175 findings — this session ran no battery and gained no finding. verified_on stays 2026-09-02 (JOURNAL/205's rule: one fact re-checked is not all 28). fact-citation-sweep.mjs run in the same session as a citation edit, per the standing rule: 11 convention / 521 api / 32 id joins, 20 allowlisted, 0 stale. Full pre-commit chain green.

Registry re-read at the end: next.js still BEHIND on the patch tail only (16.3.5 → 16.3.6, patches 148 → 150, fetched_on 2026-09-22 on all eight) — the twenty-first identical reading, not refreshed. Nothing owed: this session touched no library's releases, and the ladder it measured is joined to the committed snapshot exactly as BACKLOG 0k requires. Retest debt none across all eight. No gate needed: no new surface, no money, no outbound, no account, and no new published claim beyond a correction on a fact that already existed.