Skip to contentWolf-Rayet

Decision records

ADR-0068 A tree is a machine for hiding demands, and §5 is right for a different reason than it gives

Accepted2026-09-05Phase 4, reopened

#Context

ADR-0061 audited section B and named tree-view as the one row this system's own layer model might refuse: *"arbitrary nesting is its entire subject and §5 forbids Arbiters inside Arbiters."* It listed three honest options — a recursion below the Arbiter tier, an argued exclusion, or a change to §5 — and decided none of them.

This record decides it, and the deciding argument is not the one that was expected.

#§5's stated reason is not the operative one

The rule reads:

Arbiters do not nest inside Arbiters. Emitters do not contain Arbiters. Scopes do not nest more than two deep. Each rule exists because breaking it makes budget resolution ambiguous.

Budget resolution is not ambiguous, and the engine is the evidence. packages/budget/src/engine.js does not contain the word arbiter. A Scope's members are selected like this:

const members = dom.nodes.filter(
  (n) => n.rendered && n.level !== null && !n.inExemptSlot
    && (n.scopeIndex === scopeMeta.index || n.index === scopeMeta.index),
);

scopeIndex is the nearest enclosing Scope, and emission rolls up to it regardless of how many Arbiters sit between. Nest Arbiters ten deep and every one of their descendants still lands in exactly one Scope's budget, attributed by ownershipMap to the topmost declared element per pixel. There is nothing to resolve ambiguously.

What Arbiter nesting *would* affect is the grant — and the grant did not exist when §5 was written. ADR-0054 found that four Arbiters had been built without any of them assigning a level to anything, and it is the newest capability in the tier. A nested grant is not obviously ambiguous either: each Arbiter grants to its own children, the sets are disjoint, and depth would descend the rung until it floors at Ambient, which is buttonGroupGrant's existing behaviour.

So the rule is defended by a reason that does not hold, and that matters: a rule defended by the wrong reason is a rule that will be broken by the first person who notices the reason is wrong. §5's sentence is amended by this record to say what is actually true of the three rules it governs — Scope depth is bounded because the *budget* nests, and Arbiter nesting is refused for the reason below.

#The reason that does hold, and it is ADR-0040's

A tree view is a component whose normal state is illegal.

ADR-0040: a demand may not be inside a panel that has been removed from the frame. ADR-0059 restated it on the property rather than on the accordion, and tabs is the case where disclosure is the resting state rather than an act — a strip of n panels has n−1 absent at every moment.

A tree raises that to arbitrary depth and to arbitrary proportion. A tree exists to keep most of itself closed; that is what it is for. A demand anywhere below a collapsed branch is a demand present in the markup and absent from the frame, and Salience — hidden refuses it.

The three remedies all fail, and each fails for a reason already on the record:

Never collapse. Defeats the component. A tree that is always fully expanded is a stack of indented rows, which is markup.

Lift the demand to every ancestor. Draws one alarm once per level of depth. That is ADR-0055's refusal — *"two components saying one thing with two allocations is a screen that can disagree with itself about how loud the same fact is"* — multiplied by the depth of the tree.

Lift it to the root alone. The one that looks workable, and the one ADR-0040 already refuses in terms. The hidden node still declares level 4 and is still not rendered, so the scene fails whatever the root draws; and re-declaring the hidden node lower to make it pass is named and refused in that record's own remedy: *"Do not lower the declaration to hide it: this check reads levels, and a demand re-declared at Directed is a different screen rather than the same one passing."*

So the only legal place for a demand on a screen with a tree is outside the tree, always. A component that may never contain the thing this system exists to ration cannot participate in its central claim.

And Carbon says the same thing from the other side. Its own page refuses the tree for primary navigation — *"instead, use the UI Shell left panel"* — and for single-level nesting — *"use the accordion or data table."* What is left is browsing file systems and organising large amounts of information, which is a document-management need rather than a supervision one.

#Decision

**tree-view is removed from the roster and enters *Not carried, with the reason*. Roster 51 → 50; the Carbon term 37 → 36; dropped 8 → 9; the identity holds at 9 + 34 = 43**.

§5's justification sentence is amended. The three rules it states all stand; the single reason given for all three does not cover all three, and this record supplies the missing one rather than leaving a rule propped up by an argument its own engine contradicts.

Section B is complete: five rows, all built — queue-item, table-row, accordion, tabs, progress-indicator — from fourteen at ADR-0021.

#Rejected options

Change §5 to permit Arbiter nesting. The option this pass expected to take, because the stated reason is wrong and the grant would cascade cleanly. It lost on what would then be buildable: permitting the nesting does not make a tree legal, because ADR-0040 is what refuses a tree and ADR-0040 is untouched. Changing a rule to admit a component that a *different* rule still refuses is a change that buys nothing and costs the closed nesting table — the thing every contract's slot types are derived from. The rule stays; only its reason moves.

Build a tree that never collapses. Legal, and it is a stack of indented rows. Nothing in it needs a component: indentation is layout, a selected node is navigation-item's current variant, and the set is plain markup — which is exactly what ADR-0061 decided for breadcrumb and ADR-0067 for file-uploader.

Build it and forbid demands inside it, in the contract. Honest, and it would compile: a tree whose subtree may not hold a level-4 element, refused in the type. It lost because the refusal cannot be expressed where it needs to be — a subtree is not a type, as page-header and tabs both record — so the rule would live in prose and be enforced only by a scene nobody had written. And a component whose documentation begins "this may not contain the most important thing on the screen" is a component asking the reader to remember a rule the system could have made unrepresentable.

Keep the row open for a later decision. ADR-0061 did that once, correctly, because the audit had not derived the layer. This pass has derived it: the layer model does not refuse a tree — ADR-0040 does — and that answer does not improve by waiting.

#Consequences

Roster 50, built 32. Eighteen rows remain to build, none of them in section B.

Section B is closed at five rows from fourteen. Nine left: three collapsed to data-table and table-row (ADR-0057), one re-filed as a Scope (ADR-0058), one as an Emitter (ADR-0066), one collapsed to tabs at a lower rung (ADR-0060), one to navigation-item in plain markup (ADR-0061), one to five built components (ADR-0067), and this one refused by ADR-0040. Every one left for a stated reason and every reason is in the exclusion table or in another section's row.

§5 keeps three rules and loses one sentence's worth of justification. The amendment is small and it is the kind this repository has made before: ADR-0050 amended two stylesheet comments, ADR-0021 amended §11, ADR-0030 superseded ADR-0011. A rule whose reason is wrong is worse than a rule with no reason, because the wrong reason invites exactly the change this record rejected.

The adversarial sample has reported on the layer model itself. ADR-0021 took Carbon to test §3's claim that the authority question *"has exactly one answer per component and no ambiguous cases."* Across this session that test found two rows the roster had answered wrongly, and one — this one — where the answer is that no layer helps, because the refusal comes from the ration rather than from the tier. That is a stronger result than parity would have been.

#Measured

  • packages/budget/src/engine.js contains the word arbiter zero times; a Scope's members are selected by scopeIndex, the nearest enclosing Scope — *disk, this pass*.
  • Carbon's tree-view page, 2026-09-05: refused for primary navigation (*"use the UI Shell left panel"*) and for single-level nesting (*"use the accordion or data table"*).
  • Section B: 14 rows at ADR-0021, 5 now, all built.
  • Roster 51 → 50; the roster's Carbon rows 37 → 36; dropped 8 → 9; the identity 9 + 34 = 43 holds.
  • Built 32, unchanged. pnpm battery — the verdict this pass is measured by.