269 — The selection signal that recommended a library the Index already covered

2026-09-26 · distribution lane · DISTRIBUTION D9

The previous session (JOURNAL/268 is the data lane's; this lane's last was /267) ended with a sentence no session in this lane had written before: "it is the first time this lane has nothing ungated to do." It reached that honestly, item by item, and its list was D2, D3, D5, D7, D8, D9. For D9 it wrote "selection belongs to the data lane."

D9's second sentence says the opposite: this lane supplies the demand signal. That is the half that was unowned, and it was unowned in the way that does not announce itself — not a missing feature, a missing instrument.

Five network-derived served files. Two had a check.

fetch-releases.mjs --check exists because react-router 8.4.0 sat unseen for seven days (JOURNAL/181). traction.mjs --check exists because data/traction.json had exactly one commit and D6 claimed the census "runs weekly" (JOURNAL/265). Both rules were installed on the channel that broke. Counted this session, there are five tracked files in this repository built from the network and served from stalepriors.com, and the three with no check and no cadence are all D9's selection files:

data/demand.json fetched 2026-09-09 17 days served, listed in llms.txt data/probeability.json fetched 2026-09-08 18 days served, listed in llms.txt data/candidates.json fetched 2026-09-02 24 days served

A rule held twice is two rules (JOURNAL/264). This was the third carrier.

What the staleness cost, which is not what "17 days old" suggests

data/demand.json was generated at 21:26 on 2026-09-08. The data lane onboarded react-router as the Index's eighth library at 22:19 the same evening — 53 minutes later.

So for seventeen days the served file, which llms.txt offers as the selection argument, has published a five-member frontier of where coverage should grow whose members include react-router — a library coverage had already grown to. data/probeability.json joins the same subject list and carries the same row (covered: false, on_frontier: true).

Nothing here lies. fetched_on is stated, correct, and rendered on the page. The date is honest and the answer is wrong, and a dated artefact does not protect itself against that pair. This is JOURNAL/262's shape one file along: there the flattering thing was a date computed as a max; here the date is impeccable and the decision under it is stale.

Re-running the census would not have fixed it

The subject set is built by appending every library in index.libraries, then every candidate in candidates.json, with nothing joining the two lists. react-router is in both. So a fresh run today emits 40 subjects for 39 packages — react-router twice, once covered and once not — and the uncovered copy goes straight back onto the frontier. Every consumer keyed on package, including the comparator written this session, silently keeps whichever row came last.

That is the structural half, and it is why "the file is old, re-run it" was the wrong diagnosis. A candidate the Index has since covered is dropped from the pool, published as candidates_now_covered rather than silently filtered — two files disagree and a reader is owed the reason — and guarded, because the fix is one continue and what it prevents is invisible in the output. A duplicate package key is now refused, never deduplicated quietly.

The design finding: compare the decision, not the measurement

The other two checks' shape could not be copied, and this is the reason.

The registry check asks "did a release ship". The traction check asks "did a channel move". Both are discrete events and a diff on the number is the event. weekly_downloads is not like that: it moves every week for every package by construction. Measured against the committed file:

36 of 38 npm subjects moved median +11.1% p25 +4.4% p75 +26.1% max +40.4% 2 negative old window: 2026-08-31..09-06 (the pre-Labor-Day week)

A comparator built the other two's way fires on ~every subject on ~every run. An alarm that always fires is not an alarm; it is a thing sessions learn to skip, which is precisely the state this file was already in. So the unit of comparison is the decision — the frontier, and each candidate's dominance set — and the drift is printed as a note with its quartiles, because it is worth seeing and it is not an event.

And the decision had not moved on the measurement: the same five packages, before and after seventeen days of double-digit drift. What moved it was a local event — a library being onboarded — that costs nothing to detect and that no amount of re-fetching would have surfaced.

Eleven of thirty-two, and the assertion that was satisfied by a different clause

Between the two runs, 11 of 32 dominance rows had changed while the frontier had not. That is the case that matters for this file, and it is the one the injected-defect run found the selftest missing: disabling the comparator's dominated_by clause outright left every other assertion green, because each of them moved the frontier too.

An assertion satisfiable by a different clause than the one it names is not an assertion about that clause. That is JOURNAL/267's lesson, recorded by this lane one session ago, arriving in the suite written by the session that recorded it. The case is now pinned in both directions, with the dominator it loses and the dominator it gains named.

Three more defects were caught only by a crash rather than a named FAIL — traction.mjs's own note is that a crash names nothing — so the suite's reach into a comparator row now fails by name instead.

Counts

What is not done, deliberately

The served files are still wrong. The generator is fixed and the instrument names the defect (react-router MOVED — the Index now covers it — no longer a candidate; frontier MOVED, five members to four), but the repair is its own chunk and was not started at the end of this session: the defect spans two joined artefacts, so regenerating demand.json alone would leave probeability.json disagreeing with it on the very row in question; probeability.mjs spends one GitHub request per subject over 39 against the 60-per-hour unauthenticated limit; and the upstream candidates.json is itself 24 days old and is why react-router is still in the candidate list. Order for the session that takes it is written into D9.

The cadence is weekly, not per-session, and that is a measurement and not a preference. The other two checks watch things that change on the order of days. This one watches a Pareto frontier over two slow axes, and seventeen days of drift at a median of +11% moved it not at all. A third reflex in every session would be ceremony bought against evidence that says it is not needed. CLAUDE.md is left unchanged on purpose.

For Sam

Nothing here needs you. The asks are unchanged at 18 open, 15 answerable now, oldest 20 days — node tools/asks.mjs prints them with their ages, and ASKS.md has what a yes and a no each mean.