ADR-0115 The ration engine was carrying ADR-0005's retired clause, and the rung it needs is derivable from this system's own ladder
#Context
ADR-0114 wired the ration to a rendered page and reported three findings. The third was that eight of 28 resolvable readings could not name a Directed element, and it proposed the cause: a share shrinks as a Scope grows while PLATFORM_TOLERANCE does not, so the margin's *scale* was owed the treatment ADR-0036 gave its *identity*.
That proposal was wrong, and it was wrong in the most avoidable way. ADR-0036 had already decided the scale. Its rule is area-weighted in the sentence that states it:
required = ladderStep(theme) × (governedPixels(leader) / governed(scope))
and its Consequences say so in as many words: *"The margin is scale-free now: it tightens for small elements and loosens for large ones, which is exactly the area-weighting ADR-0005 identified as its own honest boundary and could not then act on."*
So the defect is not a missing decision. It is a regression. packages/react/src/scope.ts measures dominance against PLATFORM_TOLERANCE, which is ADR-0005's clause, which ADR-0036 reopened and replaced on 2026-09-02. The engine was written after that date and carried the retired rule forward. It carried the retired *reasoning* forward too, in a comment presenting it as current:
PLATFORM_TOLERANCE was measured, not chosen: it bounds the disagreement between two renderers, which is why ADR-0005 uses it as the dominance margin rather than inventing a constant. A dominance this asserts is one a second renderer would agree with.ADR-0036 on those two sentences: *"Both halves are now false."* A comment that explains a rule by a record that retired it is worse than no comment, because it answers the question a reader would otherwise go and ask.
The reason the regression survived is that the rule was not implementable as written. ADR-0036 denominates the margin in ladderStep(theme), derived by ADR-0030 as the mean adjacent |ΔL| of a theme's neutral ramp over its headroom, read from packages/tokens/receipts/ramps-<theme>.json. Those receipts are the retired generator's, for the four retired themes. This system's tokens are semantic roles written by hand in wolf-rayet.css, several of them translucent, and packages/tokens is one of the five packages awaiting deletion. There was no ramp to read, so the engine took the constant that was there.
#Decision
The dominance margin returns to ADR-0036's rule, denominated in a rung derived from this system's own neutral ladder. Nothing about the rule changes. What changes is where the rung comes from:
required = LADDER_STEP[theme] × (leaderPixels / governedPixels)
LADDER_STEP = { light: 0.119068, dark: 0.161732 }The derivation is ADR-0030's, unmodified: the mean adjacent |ΔL| of the theme's neutral ladder over its headroom. The one difference is compositing. The retired generator solved a numbered ramp of opaque steps; this surface writes --wr-neutral-subtle as transparent and four more of its neutral roles with alpha, so the ladder is composited over the substrate before its rungs are measured. That is a change to how the values are read, not to what is being computed.
--wr-neutral-subtle is the ladder's floor and not an omission. Level 0 in this system is named Substrate, so a ground indistinguishable from the substrate is a rung, and it is the lowest one. Two roles resolving to one lightness are one rung and not two, for ADR-0039's reason applied to arithmetic: a step of zero would drag the mean down and make every dominance claim cheaper.
apps/docs/tools/derive-rung.mjs recomputes both rungs from the stylesheet and fails if the committed literals have drifted, at 1e-6, which is ADR-0036's DERIVATION_BOUND for ADR-0036's reason: this reads committed hex and does arithmetic, so what is left to disagree about across machines is libm's cube root, which quantising to six decimals already hides. Both agree at Δ 0.00e+0. An undefended literal there would have been precisely the unprincipled constant ADR-0005 refused and ADR-0036 refused again.
PLATFORM_TOLERANCE is removed from this engine rather than left unspent. ADR-0036 kept it for one spender, the substrate-floor check, and that check lives in the retired engine and has no counterpart here. A constant with no spender is a constant waiting to be spent on the wrong question, which is the whole history this record is about.
The audit reports the margin it required. ScopeAudit gains requiredMargin and each share carries its pixels, because the margin varies per Scope now and ADR-0036 is explicit that a receipt reporting a verdict against a varying margin without reporting the margin would be unreadable.
#What moved, on the same 34 readings
The six routes and two themes of ADR-0114, measured before and after the change, with nothing else touched.
Eight verdicts moved and all eight are the same finding. shell-header loses its Directed element on both themes of / and /thesis, and on the dark reading of /components, /components/button/examples, /components/alert/examples and /foundations/intensity. Twelve readings keep the Directed element they had. Warnings rise from 8 to 16; failures stay at zero.
The theme toggle no longer holds Directed, and ADR-0114's sentence about it is corrected below. div.ds__theme still leads the shell header on every route. It leads by 0.001577 in dark, against a requirement of 0.010986: one rung of 0.161732 across 4,956 of 72,960 governed pixels. It leads, and it does not lead by a level. That is the difference between the two rules stated on a real element.
The rule is not uniformly stricter either. Required margins across the 34 readings run from 0.000000 to 0.010986, and seven of the 34 sit below the retired 1e-3. The crossover is at 0.84% of a Scope in light and 0.62% in dark: a leader smaller than that must clear less than the old constant asked, and a lead the constant dismissed as noise is a lead the ladder can name. ADR-0036 found this on 21-proof-supervisor-queue and it reproduces here.
#Rejected options
Amend ADR-0036 to make the margin scale, as ADR-0114 proposed. It had the merit of being the obvious reading of the evidence: a quarter of real readings could not name a Directed element, and the margin plainly was not scaling. It lost because the amendment already exists. Writing it again would have produced a record that agreed with an accepted record while believing it disagreed, and left the actual defect, an engine running a retired rule, undiagnosed underneath it. The evidence was right and the diagnosis was wrong, which is the failure mode a record's Rejected options exist to catch.
Keep PLATFORM_TOLERANCE until the rung could be derived, and record the debt. Honest, cheap, and it is ADR-0073's habit for a debt a record cannot pay in the pass that finds it. It lost because the debt turned out to be payable in the same pass. The obstacle was that ladderStep read the retired generator's receipts, and once the question is asked as *what is this theme's ladder* rather than *where is the ramp file*, the answer is nine tokens in the stylesheet the system already ships.
Derive the rung from the intensity foundation's band boundaries instead. Tempting, because SUBSTRATE_MAX = 0.02 and AMBIENT_MAX = 0.12 are already in the repository and already describe the ladder, and light's derived rung of 0.119068 lands 0.000932 from AMBIENT_MAX, which looks like confirmation. It lost because the agreement is in one theme and the boundaries are picked. score-ladder.mjs says so itself: *"the boundaries are the ones the names already imply."* Deriving a margin from a chosen constant would be a chosen constant wearing a derivation's clothes, and the dark rung of 0.161732 is a third larger than AMBIENT_MAX, so the agreement does not survive the second theme. That the picked boundary is within 0.001 of a derived quantity in one theme is a finding about the boundary, not a licence to build on it. It is named in Consequences.
Require the caller to name a theme. Strictly more correct, since the rung is a property of the theme and a Scope measured without one is being judged by a number that is nobody's. It lost on the direction of the error rather than on principle. DEFAULT_LADDER_STEP is the smaller of the two rungs, so an unthemed reading errs toward naming a Directed element rather than silently declining to, which is ADR-0036's own reason for its legacy rung, and a hard requirement would have turned every existing fixture into a caller that must know a theme it has no opinion about.
#Consequences
The engine agrees with the records again, and the agreement is checked rather than asserted: pnpm --filter @wolf-rayet/docs run check:rung recomputes both rungs from the stylesheet on every run.
The intensity ladder's band boundaries are now the system's last picked threshold, and they are owed a derivation. SUBSTRATE_MAX and AMBIENT_MAX decide what level every ground in the vocabulary scores, which is 109 grounds per theme and the whole of /foundations/intensity. They are one pair of numbers applied to two themes whose ladders differ by a third. This record does not fix them, and it is the fourth owed check rather than a loose end: the measurement that would settle it is the one this record just took.
Paid by ADR-0116, in the next unit. Both boundaries are derived per theme from the surface family and this record's rung. Dark moved 51 of its 109 grounds, all downward, which is the size of the error this paragraph was estimating.
ADR-0114 is corrected where it stands rather than left to be read. Its sentence *"the theme toggle holds Directed in the shell header on every route"* was true under the rule the engine was then running and is false under the rule it should have been running. The correction is in that record, beside the original, because a record whose finding was produced by a retired rule should say so.
ADR-0036 is not amended, superseded or reopened. It was right and it was ignored. What this record adds is the rung for two themes it could not have known about and a tool that defends them.
No token, stylesheet or component moved. One engine file, one test file, one tool, one harness.
#Measured
LADDER_STEPderived frompackages/react/src/wolf-rayet.css: light 0.119068 over 7 distinct rungs, substrate L 1.000000, headroom 1.000000; dark 0.161732 over 6 distinct rungs, substrate L 0.240110, headroom 0.759890. Both agree with the committed literals at Δ 0.00e+0 *(this pass)*.- Reading the dark block alone, without the cascade from
:root, drops the ladder's floor and moves the dark rung by 0.024 to 0.185668. The tool composites the cascade *(this pass)*. - Same 34 readings, before and after: 8 verdicts moved, all
shell-header, all losing Directed. 12 keep the Directed element they had. Warnings 8 → 16, failures 0 → 0. - Required margins across the 34: 0.000000 to 0.010986; 7 of 34 below the retired
1e-3. Crossover at 0.84% of a Scope in light, 0.62% in dark. div.ds__themein dark: leads by 0.001577 against a requirement of 0.010986, one rung of 0.161732 across 4,956 of 72,960 governed pixels.pnpm --filter @wolf-rayet/react run test: 22 ration checks passed, up from 18.- Mutation: the rung ignored in
lib/scope.jsis caught by 5 checks; the area weighting dropped is caught by 4. Restored, 22 pass *(this pass)*. tsc --noEmitclean on react, react tests and docs *(this pass)*.