Skip to contentWolf-Rayet

Decision records

ADR-0118 The docs shell declares what it carries and what it draws, and the ground is synthesized rather than found

Accepted2026-09-20Phase 5

#Context

ADR-0117 made the ration read pixels and named the debt that came with it: the docs markup declares no slots, so the route column counted the site's prose as chrome. That was the correct behaviour under ADR-0009 given a markup that declares nothing, and it was the wrong number to gate anything on. A record page is two thirds writing. Measuring it as chrome measures the writer.

ADR-0009 settles the principle and the mechanism together. The budget governs chrome, not content. Content is attention the product carries, chrome is attention the system spends, and the exemption travels through slot contracts, with no hand-maintained exclusion list anywhere in the system. packages/core already declares the vocabulary: two slots, content exempt and chrome not, with EXEMPT_SLOTS derived from the contracts rather than listed beside them.

So nothing here needed inventing either. What needed deciding is where the line falls on a site whose subject is a design system.

#Decision

On this site the system is Wolf-Rayet, so chrome is what it draws and content is what it carries. The shell, the tables, the intensity bars, the lozenges and every rendered component example are the system drawing itself and are governed. The writing is the payload: page titles, intros, section headings and their notes, the Prose paragraphs, and the whole body of a decision record.

That is a boundary about authorship rather than about appearance, and it is the one ADR-0009 draws. A <pre> in a record's body paints a ground and is still content, because the record is what the site carries. The same <pre> in a component's Examples tab is the system showing its own code block.

Every exempt region is hosted, and the audit fails one that is not. ADR-0009 grants the exemption to a region a component declares and says what is still paid for around it: the container, its border, and anything the system draws on it. .ds__content declares level 1 and is that container. An exempt region whose nearest declared ancestor is its own Scope has nothing paying for its frame, which packages/core already names: *"that is not a contract, it is an assertion, and it is the laundering case."* The harness reports it as a failure rather than a warning, because pixels leaving the budget with no contract behind them is the one thing that record exists to refuse.

A Prose component rather than a ds__prose class, so the next paragraph written cannot quietly be the one that forgets.

The mask derives from the contract. EXEMPT_SLOTS is imported from @wolf-rayet/core; the harness recognises no slot by name. An exempt pixel leaves the numerator and the denominator together, because ADR-0004 says governedPixels counts chrome only, so masking a region changes what is measured rather than how it is scored. Chrome inside a content region still counts, by the rule measure.js already spells: a non-exempt slot says it explicitly, a level says it implicitly and more strongly, because a level is a claim to an allocation and only chrome holds one. Without that, a banner parked in a legitimately hosted region would have its pixels masked.

#The ground is synthesized, and an attempt to find it was removed

ADR-0005 excludes the Scope's ground from the Directed contest, and defines it as any member that encloses every other member. ADR-0117 implemented the exclusion but left the identification to the harness, which credits every pixel no block covers to a synthetic residual. That residual is the Scope's own surface by construction, and no member can enclose it.

Once .ds__content became a host, it became a block, and on a prose route it is a container owning most of what is left. So the enclosure test was implemented literally, over the declared members, and it worked on the routes with many of them. It was removed, because with two members it is a different rule. A Scope holding a container and one child satisfies "encloses every other member" the moment the container holds the child, which is "encloses something smaller" — the intermediate rule ADR-0005 tried and rejected:

a .row carrying a chip encloses the chip, so every row in every scene left the contest and a figcaption inherited the lead of 03-violations.

It did exactly that here. div.ds__theme left the shell header's contest because the theme toggle contains its own two option buttons. A rule that is right at 439 members and wrong at 2 is not the rule; it is a heuristic that happens to agree with one on dense markup.

The consequence is stated rather than engineered away. In a Scope that declares few blocks, a container can hold Directed on the strength of the text attributed to it, and on /thesis one does. That is a true reading of markup that declares almost nothing: the thesis page's route column is prose, links and headings, and links and headings are marks, which this system does not yet score. The remedy is more declarations, not another exclusion.

#Rejected options

Exempt by a list of routes or selectors held in the tool. Merit: immediate, needs no markup change, and would have produced the same numbers today. It lost to the sentence ADR-0009 puts in its own Decision: there is no hand-maintained exclusion list anywhere in the system, because a manual mask drifts the moment a layout changes and a stale mask silently corrupts every receipt downstream. A list in the audit tool is that mask with a different file extension.

Treat every route column as content, since a documentation site is documentation. Merit: honest about what the site is for, and it is the reading that makes the budget's number about the system rather than about the site. It lost because the component pages render the real components, and those pixels are the system spending attention on exactly the thing being measured. Exempting a route column wholesale would exempt the Examples tab, which is the one place the measurement has a subject.

Declare the slot on each paragraph rather than on titles and headings too. Merit: the narrowest possible change, and a heading is arguably the site's own furniture rather than the writer's text. It lost on the measurement. With paragraphs alone the host still owned every title, intro, section heading and note, and held Directed on two routes with a share that was nothing but that text. A boundary that leaves most of the writing on the chrome side is a boundary in name.

Make a host never contend, as a rule. Merit: it would have fixed /thesis in one line, and there is a real argument for it — ADR-0009 says the container is counted, which is not the same as saying it competes. It lost because it is too strong as stated. A host is any container around content, and a bright card holding an image is a host whose ground is a real appearance competing for real attention. Excluding all of them would exempt a class of element from the contest on the strength of what its children are.

#Consequences

The route column's load is a number about the system. All 12 route readings shared with ADR-0117's run fell, between 0.6% and 63.8%, in proportion to how much prose each page holds: the button Examples tab by 0.9%, the thesis page by 63.8%. Nothing else moved in the same direction by accident, because nothing else changed.

The content fraction is now a reported property of a route, from 1.2% on the button Examples tab to 59.2% on a decision record. It is printed beside the load, because a load measured after masking two thirds of a page is unreadable without knowing that.

Three Directed verdicts moved. /thesis gains one in both themes, .ds__content, which is the container case described above. /components/button/examples in light loses one: the button's lead over the code samples no longer clears a rung once the sample captions are exempt.

The laundering rule is checked, not asserted. Removing host from .ds__content turns 22 exempt regions into unhosted-exemption failures and the run exits non-zero. That is how the rule was verified.

The exemption is still not enforced by the linter. packages/core says "the engine and the lint each enforce it and each cite this", and the lint in question is in @wolf-rayet/eslint-plugin, which has zero references and is awaiting deletion. Today only the audit enforces it, and only on the routes the audit visits. This is the third thing the deletion unit has to answer, after the PNG decoder and the battery's shape.

Marks are still not scored, and this record is where that started to cost something. A link, a heading and a checked checkbox have no ground, so they are not blocks, so a Scope made of them declares nothing and its container inherits the lead. It is named in the intensity foundation already; it is now also the reason one reading reads oddly.

#Measured

  • 8 routes, 2 themes, 46 Scope readings, 0 failures, 30 warnings *(this pass)*.
  • All 12 of 12 route readings common with ADR-0117's run fell: / −33.8% light and −33.0% dark, /components −2.5% and −2.2%, /components/alert/examples −4.8% and −2.9%, /components/button/examples −0.9% and −0.6%, /foundations/intensity −32.5% and −31.1%, /thesis −63.8% in both.
  • Content fraction across all 16 route readings: 1.2% (/components/button/examples) to 59.2% (/thesis/decisions/0009-content-pixels).
  • /thesis/decisions/0009-content-pixels route column: load 0.002460 light, 0.003363 dark, Directed span.wr-lozenge#1. On a record page the only thing the system draws in the route column is the status lozenge and the frame.
  • Directed verdicts moved: 3.
  • Mutation: host removed from .ds__content produces 22 unhosted-exemption failures on one route and a non-zero exit. Restored, the run passes *(this pass)*.
  • The enclosure test, before removal, excluded div.ds__theme from shell-header on / in both themes, because the toggle encloses its two option buttons *(this pass)*.
  • tsc --noEmit clean on docs; pnpm --filter @wolf-rayet/react run test 28 checks *(this pass)*.