Skip to contentWolf-Rayet

Decision records

ADR-0046 Chrome that outlives a route may not demand

Accepted2026-09-05Phase 4, reopened

#Context

shell-header is the twenty-second component and the third Scope, and it is the first component in this system that persists across routes. Every Scope built so far — modal, data-table — lives inside one route and disappears with it. A shell header does not: it is the surface an operator sees before the route loads and after it changes, and it is the same element throughout.

§3 says a View "is a route". ADR-0010 gives that View a demand cap of 1, ratified from the spike's own gameability probe P3, and it is explicit about the static case: *"a scene declaring more concurrent Demanded elements than the View cap is a build failure, naming every offending Scope, the View, and the rule."* The engine enforces exactly that — viewDemands.length <= viewCap — and the cap is the two-tier ration §2 calls "the rule the whole system exists to enforce".

Put those two facts together and the shell asks a question nothing built so far could ask. Which View's cap does a persistent surface count against?

There is no comfortable answer available by default:

  • If shell chrome may reach Demanded and counts against the View it is currently rendered in, then a header carrying one live badge permanently occupies the route's only demand slot. The operator's actual work — the queue, the table, the form they are looking at — can then never demand, because the chrome got there first and never leaves. That inverts the system's purpose precisely: the route is what the operator is working in, and the chrome is what frames it.
  • If shell chrome is given a View of its own so it has its own slot, then a header demand and a route demand are two live demands on one screen, which is the exact screen probe P3 constructed and ADR-0010 was ratified to refuse. Splitting demands into sibling containers to double the ration is the gaming the cap exists to stop; a container being persistent does not make it a different screen.
  • If the question is left open, the answer changes at a route transition — the same rendered header counts against one cap, then another, then none — and a rule whose subject changes underneath it is not a rule.

The roster is about to make this decision four times over. shell-header, shell-left-panel, shell-right-panel and menu are all Scopes on ADR-0021's section D, all persistent, and deciding this per component is deciding it four times with four chances to disagree.

One further piece of context, because the record should not restate a table that disagrees with disk. ADR-0021's roster gives every Scope the level column *"none — allocates"*. That is not what got built: modal declares levels 3 and 4 under ADR-0037, and data-table declares level 1. A Scope in this system allocates a budget and holds chrome of its own — a ground, a border, a title — and that chrome sits somewhere on the ladder. The question below is what rung the shell's own chrome may occupy, not whether it has one.

#Decision

A Scope that persists across routes is chrome, and chrome may not hold a demand. The shell Scopes declare level 1 and no other rung.

shell-header, and by the same argument shell-left-panel, shell-right-panel and menu when they land, declare a single legal level — Ambient. They may not reach Marked, Directed or Demanded. The View's cap is therefore untouched by the shell in every route and at every transition: the question "which View does this demand belong to" never arises, because a persistent surface never has one.

What signals is what the shell hosts, not the shell. A header carries navigation-items, which are Arbiters reaching Directed, and those items belong to the route they point at rather than to the chrome doing the pointing. A badge saying a route needs attention is the item's declaration, made about somewhere else. This is ADR-0042's shape one layer up: a toast reports an event rather than being a condition, so it may not carry Demanded and gains origin to name where the condition lives; shell chrome reports that a *route* wants attention, may not carry a demand either, and names the route by being navigation.

Ambient, not Directed. The ceiling and the floor are the same rung, and the floor is the load-bearing half. §2 defines Directed as "clearly the local focus", and a surface that is on screen continuously cannot be the local focus — chrome that is always the focus is never the focus, because the reader stops seeing it, which is the sea-of-green failure ADR-0044 measured one channel over. The most persistent surface on the screen is the one that can least afford to be loud, so it takes the quietest rung the ladder has and stays there.

This is a property of persistence, not of the layer. modal is a Scope and reaches Demanded under ADR-0037; data-table is a Scope at Ambient. Neither outlives its route. The rule below is stated on the property that actually distinguishes the shell, so a future Scope inherits it by being persistent rather than by being named:

A component that remains rendered across a change of route declares level 1 and no other, and may not hold a demand.

Enforced in the type, and by construction in the tier. ShellHeaderLevel is AmbientLevel, so a shell header at any other rung is a compile failure — ADR-0042's mechanism, and the same reason: the refusal is of a declaration a component may not make, not of a frame the engine may not accept. The component tier follows automatically, because a mark table with one level emits one token.

#Rejected options

Let the shell demand, and count it in the current View. The straightforward reading of ADR-0010, and it needs no new rule at all — the cap already covers every Scope on the screen, and a header is on the screen. It lost on what it does to the route. A persistent badge is persistent, so the slot it takes is taken forever, and every route the operator visits afterwards is one that cannot raise a demand. The cap would be spent on the frame rather than on the work, which is the opposite of the allocation the system exists to make. It also fails a second way: at a route transition the same rendered element changes which cap it counts against without re-rendering, so the check's subject moves while its object stands still.

Give the shell its own View. Structurally tidy — the shell is not the route, so let it be its own region with its own cap — and it has real precedent in how shells are usually modelled. Rejected because it manufactures a second demand slot on one screen, which is exactly probe P3: two Scopes each locally correct, producing a screen with two demands. ADR-0010 was ratified on that finding. A View is a route by §3, and a region that is not a route calling itself a View to obtain a ration is the definition of gaming the cap.

Ceiling of Directed, floor of Ambient — let the shell escalate but not demand. The middle option, and the one that looks most reasonable: it keeps the View cap safe while letting a header shout when something is wrong. Rejected on §2's own definition rather than on the cap. Directed is "clearly the local focus", and a surface that never leaves cannot take that rung without holding it permanently or flickering between rungs on every route change — the first is a contradiction and the second is motion the reader did not ask for on the most stable element on screen. The thing that should escalate is the navigation item pointing at the route, and it already can.

Decide it per shell component when each one lands. The cheapest path today and the one requiring no record. Rejected because four components will ask the identical question within one section of the roster, and four independent answers is how a system acquires three-quarters of a rule. The property is shared — persistence — so the rule is stated on the property.

#Consequences

The shell gets no demand slot, ever, and that is the point. Nothing in the shell can raise a demand; everything in the shell can point at one. An operator's screen therefore keeps its single demand for the route, which is where the work is.

The type is the enforcement and the must-fail is a compile failure, joining toast's and ADR-0044's rather than adding a scene. The engine gains no check: a header that cannot declare a demand cannot render one, so there is no frame for the engine to catch.

Three components inherit this before they are written. shell-left-panel, shell-right-panel and menu are covered by the rule as stated, and each will cite this record rather than re-argue it. A fourth Scope that is *not* persistent — popover, toggletip, form — is untouched.

ADR-0021's "none — allocates" column is contradicted for the third time and the drift is named here rather than left. modal declares two levels, data-table one, and shell-header one. A Scope allocates a budget and also holds chrome, and chrome sits on the ladder. The roster's level column describes what a Scope *distributes*, not what it *is*; this record says so explicitly so the fourth reader does not have to rediscover it.

No baseline moves for the rule itself. Adding a component adds scenes and their values; the rule adds nothing on top, because a level a component cannot declare emits no token and renders no pixel.

#Measured

All darwin-arm64, this pass.

The scene reads what the record predicted. 44-shell-header-calm puts a shell header and a route region in one View and gives the route the demand. The receipt: View div#view-supervisor: 1 concurrent demand(s) / cap 1, #shell at 0 demands and level 1, #scope-queue holding the one. If chrome that outlives a route could demand, this exact composition would read 2 against a cap of 1 and fail on salience — view. It passes, and passing is the measurement.

The header's own emission, four themes: 0.064013 in field-night against that theme's ceiling of 0.128641, and 0.070634 / 0.087682 / 0.074342 in interior-light, interior-dark and field-day. A persistent surface at the quietest rung, which is what the floor half of this record is for.

Additive on both baselines. One unthemed scene and three themed siblings, zero pre-existing values moved on either platform, and linux-x64 untouched — the shape ADR-0032 leaves for a component build.

The refusal is stronger than the record claimed. ADR-0042 narrowed a level prop; this component has none at all, because with one legal rung there is no choice for a caller to make. The illegal state is not refused, it is unreachable — shell-header-violations.tsx therefore tests the rule where it lives, on the contract's own level type, and records the absent prop with a directive that would go unused if one were ever added.

Two implementations disagreed and the verifier caught it. The component tier asks the stacking context for borderRem; the shipped stacking node records borderIndex and carries the width in a border sub-node. Both are right about their own half — a component consumes a width, a tier holds a selection — and verify-output.js now reconciles them and checks both, that the index exists and that something shipped beside it. Both halves were observed failing before either was trusted. This is the first component to declare raised, so it is the first time the two ever had to agree.

#The rule generalised, and measured doing it

shell-left-panel landed in the pass after this record and is the first component to inherit the rule rather than to occasion it. Nothing in its contract re-argues the demand cap, the View boundary or the floor; it cites this record and declares the same single rung, which is what stating a rule on a property rather than on a name is for.

The scene makes a stronger claim than the header's. 45-shell-left-panel-calm puts two persistent Scopes in one View — a header and a left panel, both barred from demanding — beside a route region holding the View's single demand. Had the rule quietly become a property of shell-header rather than of persistence, the second shell Scope would have been free to demand and this composition would have found out. The receipt reads 1 concurrent demand of cap 1 with the demand in #scope-queue, so the second Scope changed nothing *(darwin-arm64)*.

Its violations file is the type-level half of the same test. It makes the same assertions about the same rule against a different component's level type, and they hold — so the refusal did not attach itself to one contract.

Two of the four shell Scopes now exist and both declare level 1 by citation. shell-right-panel and menu remain, and this record covers them already.