ADR-0078 The same rule for containing, and the second thing nesting breaks
#Context
ADR-0077 found that popover is a raised Scope at §5's second depth and did not build it, because the engine had no notion of containment: it attributes a pixel by a Scope's own rect and removes one only when a Scope grounding on scrim-composite covers it. A Scope inside another would be charged twice — once by itself, once by the Scope it sits in.
That record named the rule this pass writes, and named why it should be its own pass: *"the engine is what every claim in this repository is measured against, so a change to how it attributes pixels gets a pass whose subject is that change, with both baselines re-recorded on purpose."*
#The rule is ADR-0038's with one word changed
A pixel covered by an occluding Scope belongs to that Scope's budget and to no other.
A pixel inside a nested Scope belongs to the innermost Scope that contains it. It leaves the ancestor's governed set and it is not lost — the child is charged for it in full, against the child's own ceiling. Both sentences are one principle: one pixel, one Scope, no double charge.
Containment is walked, not inferred from rects. A descendant that overflowed its parent would otherwise take pixels from a Scope that does not contain it, which is the laundering this rule exists to prevent arriving through the fix for it. The chain is short by construction: §5 allows two.
It is reported, not silently applied. Each Scope's receipt carries a nested count beside occluded, for the same reason and one more: a nested Scope is invisible in a receipt that only totals its parent, and the number saying a parent stopped paying for its child is the number saying the rule ran.
#The pass proved the change moved nothing, then gave it something to move
Nothing nests, so the rule had no subject. Fifty-nine scenes measured identically to six decimals on every Scope after the change, which is the point of separating this pass from the component that needs it — the engine change is provably inert on everything that existed before it.
And a rule asserted against an empty set holds vacuously, which is what ADR-0041 refuses. So the pass adds scene 63, the first thing in this repository with a Scope inside a Scope. Its inner Scope is markup rather than a component, because no component occupies §5's second depth yet: this is a probe for an engine rule, not a specimen of anything.
The receipt is the proof, and it is exact:
#scope-outer governed 806258 nested 36942 #scope-inner governed 36942 nested 0
Every pixel the parent stopped being charged for is charged to the child, and the two numbers are the same number.
Observed red, in the manner ADR-0041 requires. With the skip removed, #scope-outer governs 843,200 pixels instead of 806,258 and its load rises from 0.002143 to 0.00512 — it carries its child's chrome, at two and a half times its own. The run exits 1 on BASELINE MOVED, Δ 2.98e-3. The baseline is the check, which is worth stating plainly: the double charge breaks no ceiling and fails no rule, so nothing but a recorded number would ever have caught it.
#The second thing nesting breaks, found by the probe and not fixed here
The probe's first draft put the inner Scope in a Region, and the run failed:
A Scope declaring stacking context "raised" predicts a ground of 0.067205 in OKLab L; the pixels show 0.099587.
ADR-0016 has every base and raised context predict the theme substrate, and a nested Scope sits on its parent's surface. In a Region that surface is surface-raised, and the declaration is refused as dishonest by a check that is right about everything except this case.
It is not fixed in this pass and the reason is not caution. The floor check exists to catch a Scope smuggling a full-bleed layer to sink its own ground, and it does that by predicting from the *declaration* rather than from the pixels. A nested Scope's honest prediction is its parent's surface — which is a component-tier value the frame does not carry. The engine reads a frame and cannot know which component a Scope is, which is the same limitation ADR-0075 named from the other direction when it left subtree permissions declared but unenforced. Fixing this means either putting the parent's ground in the serialization surface or scoping the floor check to top-level Scopes, and both are decisions about what a frame carries rather than about how pixels are counted.
The probe is arranged around it and says so. Its outer Scope is a PageHeader, which grounds on surface-page — the theme substrate — so a Scope inside it genuinely sits where its declaration says and the floor check has something true to confirm. The generator's own note records the Region measurement rather than hiding the choice: a scene failing for two reasons could prove neither.
#Rejected options
Test containment by rect overlap rather than by walking the scope chain. Cheaper, and it would be right for every case that exists. Rejected because it is wrong for the case this rule is about: a nested Scope that overflowed its parent would take pixels from a Scope it is not inside, which is the laundering the rule prevents, arriving through the implementation of it.
Commit the probe as a must-fail scene, with the Region nesting and the floor failure it produces. Honest, and it would have pinned the second finding as a committed artifact rather than prose. Rejected because this repository's must-fail scenes demonstrate a rule working — a scene breaks a rule on purpose and the check catches it. A scene failing because a rule is *wrong about a case* is a different thing, and filing it among the twelve would blur a distinction those twelve exist to make.
Fix the floor prediction in this pass too, since both are rules written when nothing nested. Symmetrical, and tempting for that reason. Rejected because they are not the same size: containment is arithmetic the engine can do from what it already has, and the floor prediction needs a value the frame does not carry. One is a change to counting and the other is a change to what a rendered page says about itself.
Ship the rule with popover and skip the probe. The efficient path, and the one ADR-0077 rejected in advance. An engine change and a component's first measurement in one commit is two unknowns and one number.
#Consequences
Fifty-nine scenes unchanged to six decimals, and one new. Scene 63 and three themed siblings, recorded on darwin-arm64; linux-x64 is owed and standing item 12 opens with this commit.
popover is one obstacle closer and is not yet buildable. ADR-0077 named containment as what blocked it; this record removes that and names what remains. The next pass on that row is about the serialization surface, not about the component.
Two records are joined that were written apart. ADR-0038 is about covering and this is about containing; they are one rule about who owns a pixel, and the engine now says so in one place.
A second finding is named and not owed. The floor prediction is wrong for nested Scopes. It is not a check the repository owes — it is a decision about what a frame carries, and it belongs to whichever pass makes that decision.
No token moved, no component changed. An engine rule, a probe, and two baselines.
#Measured
pnpm budgetafter the change and before the probe: 59 scenes, every oneidentical to six decimals on every Scope*(darwin-arm64, this pass)*.- Scene 63:
#scope-outergoverned 806,258 / nested 36,942;#scope-innergoverned 36,942 / nested 0 — the same number twice *(darwin-arm64, this pass)*. - The same scene with the rule removed:
#scope-outergoverned 843,200, load 0.00512 against a committed 0.002143,BASELINE MOVED, exit 1. Restored, exit 0 *(darwin-arm64, this pass)*. - The
Regionnesting, measured and then not shipped: predicted ground 0.067205, rendered 0.099587,substrate floorfailure *(darwin-arm64, this pass)*. - Themed siblings —
field-day0.10138 / 0.14320,interior-dark0.08018 / 0.15292,interior-light0.06506 / 0.15134. The first draft's inner Scope drew a fill andfield-dayrefused it at 0.16800 against 0.14320, which is the per-theme ceiling doing its job on a fixture. pnpm battery— the verdict this pass is measured by.