Skip to contentWolf-Rayet

Decision records

ADR-0066 A bar that counts what is not there, and the second layer the roster got wrong

Accepted2026-09-05Phase 4, reopened

#Context

ADR-0061 audited section B's five remaining rows and let pagination stand on one dimension: its subject is a set the reader cannot see. Every Arbiter built ranks things on the screen; this one's content is a count of items it is not showing, and its nearest relative is region's governed count rather than anything else in the tier.

That audit accepted the roster's layer without re-deriving it. ADR-0058 is why that was a mistake worth catching: tile was filed as an Arbiter and was a Scope, and the record that admitted it did so in one sentence.

#Decision: it is an Emitter, and the nesting table is the argument

§3's Arbiter *"resolves competing requests among its children."* A pagination bar has no children to resolve. The only candidates are its controls, and it ranks none of them — a "next" button is not more important than a "previous" one, it is the one that applies. Where a set of controls genuinely needs ranking, button-group is the Arbiter that does it (ADR-0054), and it sits beside this component rather than inside it.

§3's Emitter *"can hold an allocation. Cannot grant one."* It holds one, about one fact: where the reader is in a set, and how large that set is.

And the refusal is not a house style. Core's nesting table reads emitter: never, so AcceptedBy<'emitter'> has no members and this component accepts nothing at all. Carbon draws previous and next inside the pagination container; here they cannot be inside it, and the composition that is legal — the bar and the buttons as three separate declarations — is the one the type system leaves.

That makes the reporting-and-acting split a structure rather than a preference. ADR-0050 stated it for acknowledgement (*"the control that performs an acknowledgement is a Button"*), ADR-0062 restated it for a process. This is the first component where the layer model enforces it without anyone deciding to.

The row moves from section B to section A, layer Arbiter → Emitter, levels "1 to 3" → "1 to 2", and is built. The roster total does not change: 52 components, 32 built.

#The ceiling is argued, not inherited

Most Emitters carry four rungs. This one stops at Marked.

§2's Directed is *"clearly the local focus"*, and a bar that counts a list is never the local focus — the list is. A screen where the counter has become the thing a reader lands on first is the screen this component exists to *describe* rather than to become.

The Demanded rung needs no separate argument once that holds, but the case that looks like an exception is worth naming: a total that has gone out of date under the reader. That is genuinely urgent, and it is not this component's claim. It is staleness's, and ADR-0055 is why the distinction is kept rather than absorbed — two components saying one thing with two allocations is a screen that can disagree with itself about how loud the same fact is.

#The variants are a claim and a missing claim

counted and uncounted: a total the product knows, and one it does not.

Cursor-paged and streaming sources cannot cheaply answer *how many altogether*, and a component that rendered both cases the same would make "240 alarms" and "at least 240 alarms" one string. That is ADR-0048's thesis about a claim and a withdrawn claim, arriving at a number instead of a mark, and ADR-0055's about two causes with one rendering.

The correlation is in the props union rather than validated: counted requires a total, uncounted refuses one. A bar cannot claim to know a size it does not have, or hide one it does — the two ways it could lie about what it knows.

Neither variant is adverse. A total the product does not know is less informative, not worse, so both keep the whole ladder and ADR-0044's floor does not apply.

#And they are told apart by language, which needed an exemption

Both variants resolve to the same mark at both rungs, which is exactly what ADR-0039's Rule B refuses — two states separated by hue alone. $stateEncodingExemption names the channel that actually carries them: §2 gives language as one of the three, and this is a component whose whole difference lives in it. One renders a number; the other renders the word the system authors for an unknown total.

The exemption is the third in the repository and the first that is not about a mark. meter's three are about variants at one level; this one says the difference is real and is not in light at all.

#What the generator refused, again

tokens:verify rejected the first build over a codepoint — U+221E, the infinity sign — which appears nowhere in the component and only in a comment explaining that it may not be used. The shipped-subset check reads the repository's content and does not care why a character is present.

This is precisely what ADR-0053 hit: the scene's first draft used a degree sign outside ADR-0035's subset, and then the record explaining the finding was refused for showing the same codepoint. Two passes, thirteen records apart, both caught by the same check for the same reason. The prose now describes the symbols rather than printing them.

#Rejected options

Build it as the Arbiter the roster says. It would have compiled — an Arbiter accepts Emitters, and buttons are Emitters, so the controls could have gone inside. Rejected because the layer question has one answer and this is not it: a container that ranks nothing is not resolving competing requests, and putting the controls inside would have made the reporting-and-acting split a convention this component happened to break.

Carry Carbon's "pagination nav" variant — the row of numbered page buttons. Carbon publishes both, and the nav variant is a real thing. Rejected because it is a set of navigation entries with exactly one current, which is what ADR-0061 decided breadcrumb was: NavigationItems in the plain markup that component's own contract names, at whatever rung the context deserves. Building it here would add a second spelling of a composition that already exists — and it would be an Arbiter, in a component whose other variant is an Emitter, which is the four-answers problem ADR-0058 refused for tile.

Let the component compute its own page numbers from total and a page size. Convenient, and it puts arithmetic in a component whose job is to report what it was told. The product knows what it fetched; a bar that recomputed it could disagree with the query that produced it, which is a second derivation of a fact (ADR-0053) at the smallest possible scale.

Render an unknown total as a symbol. Refused twice over: by ADR-0035's shipped subset, which does not carry the glyphs, and by the reason the subset exists — a symbol meaning "we did not count" is a symbol a reader has to be taught, and §6's language column is the channel that needs no teaching.

#Consequences

Roster 52, built 31 → 32. Section B has two rows left, tree-view and file-uploader, and tree-view still carries ADR-0061's open conflict with §5.

Two of section B's layer assignments have now been wrong — tile and this one. That is the symptom the section's justifying sentence not stretching was pointing at, and it is worth stating: a section whose argument covers ten of fourteen rows is a section where four rows were filed by grouping rather than by the layer question.

The first component that accepts nothing, and the discipline table records accepts: [] rather than an omission.

themed:check earned its keep on its first use after being written. The scene was added to the themed set and the check confirmed the join in the same run — 173 fixtures from 56 scenes.

linux-x64 is short by one unthemed scene and three themed ones, twelve Scope values in total.

#Measured

  • pagination: 19 component tier tokens, 32 APCA floor checks all met, worst |Lc| 16.23 against an interior-light Ambient floor of 15.
  • Scene 58: 1 demand of cap 1, the bar at Marked beside it; three Scopes, worst emission 0.058529 against a field-night ceiling of 0.128641.
  • Themed set 170 → 173 fixtures, 56 scenes, joined both ways by themed:check.
  • tokens:verify refused the first build over U+221E in a comment — the same refusal ADR-0053 took over a degree sign.
  • Roster 52, built 31 → 32. pnpm battery — the verdict this pass is measured by.