ADR-0084 The affordance is the perimeter, and a corner is what a perimeter has when there is a box
#Context
ADR-0082 kept link as the roster's last row and named two questions for its build. This record answers the one that is not the component's: a link is the first interactive component in this system that draws no perimeter, and ADR-0045 makes a turned corner the one thing that says a reader may act.
That record's rule is stated on corners:
The spatial tier acquires a radius scale, and a turned corner means exactly one thing: this component accepts input.tokens:verify enforces it in both directions and grants one exemption — radiusExemption: 'shape', for a component whose perimeter is already turned completely, verified against the stylesheet for a 50% radius. One component claims it.
#The rule was never about corners, and the set is why nobody noticed
**Measured this pass: all ten interactive components declare a surface-* ground. Every one of them draws a box, so every one of them has an outer edge, so "a turned corner" and "the perimeter says it" have been the same sentence for ten components. Twenty non-interactive components draw a ground too — so drawing one is not the affordance; turning its edge is**.
A link has no box. It is a run of text inside a line of other text, on whatever surface is behind it, and there is nothing for a radius to turn. The rule as written has no answer for it, and the exemption as written is the wrong shape: radiusExemption: 'shape' is for a perimeter that is *already turned*, not for a component that has none.
#Decision
ADR-0045's rule generalises rather than gaining an exception: an interactive component says so on its perimeter, and there are three carriers.
corner— the default. Aspace.radiustoken turns the ground's edge. Nine components.shape— the perimeter is already turned completely, which ADR-0028 owns as a silhouette. One component,radio-button.underline— the component draws no ground, so it has no box to turn, and its only edge is the line under its own text. None yet.
The carrier is declared and not inferred, which is ADR-0045's own rule for interactive and its own reason: a treatment that appeared without a declaration and a declaration with no treatment are the same bytes on disk. affordance defaults to corner and to shape for the component already claiming the old key, so no committed component moves.
Each carrier is verified positively against the stylesheet, in the manner the shape exemption already was. shape must draw the 50%. underline must draw a rule under its text — text-decoration-line: underline or a block-end border — and must genuinely have no ground, because a component with a box that claimed this carrier would be opting out of the corner rather than lacking one.
And the rule gains a direction it could not have had before. An interactive component taking corner must draw a ground: *a component with nothing to turn may not claim to turn it.* That check was unreachable while every interactive component drew a box, which is exactly why the rule could be written about corners and stand for ten components.
This is ADR-0078's shape and ADR-0079's, applied to a check instead of the engine. Both of those found a rule written while a case did not exist, and both generalised it — *a pixel covered* to *a pixel inside*, *the theme substrate* to *the ground of whatever Scope contains it*. Each is one rule with two cases rather than a rule and an exception.
#Rejected options
A second radiusExemption value. The smallest diff, and it keeps the wrong noun. What a link needs is not an exemption from a radius; it is a different perimeter. A list of exemptions grows by one every time the rule meets a case it was not written for, and the third entry is where that becomes visible.
Give links a box. Declare a ground and a radius and let a link be a small bounded control. Available, consistent with every other interactive component, and it destroys the distinction that kept the row: ADR-0082 separated link from button on what its copy is obliged to say, and a link drawn as a button is a button with different words in it.
Let colour carry it. The web's other convention, and refused by this system twice over: §4 designs in field-night first, where there is almost no hue to spend, and ADR-0039 forbids any state whose only carrier is lightness or hue. An underline survives both.
Infer the carrier instead of declaring it — a component with no ground obviously takes the underline. True, and it is the option ADR-0045 already rejected for interactive in the same words: declared, not inferred, because the two are indistinguishable on disk. It also loses the check that matters most, the one that catches a component drawing no rule at all.
Wait for link and change the check in its pass. ADR-0077's separation argument, and it does not apply here: that record is about the *engine*, where a change moves every scene's numbers or none of them, and this is a check that adds a branch nothing takes. It is provably inert — tokens:verify is VERIFY OK unchanged on all thirty-seven — and its second direction is a real assertion over the existing set rather than a vacuous one, because *every interactive component draws a ground* is a fact about those thirty-seven and not about the row that has not been built.
#Consequences
Nothing committed moves. Nine components take corner by default, one takes shape by the key it already had, and no component declares affordance at all.
Two silent tallies are now reported, and their silence was the finding underneath this one. interactiveCount and radiusExemptions were both accumulated by the verify loop and printed nowhere — so ADR-0045's single narrow exemption had no reader, and a second could have been added without anything saying so. tokens:verify now prints the carriers and the ground invariant beside the acknowledgement, persistence and identity lines.
The invariant is stated for the first time: every interactive component in this system draws a ground. It is the thing ADR-0045's wording rested on, it was true by accident of the set rather than by rule, and a check now says so on every run.
link is buildable. ADR-0082's second question stands — whether its ceiling is Marked, argued from §2's language column — and that one is the component's, to be settled while building on ADR-0069's precedent.
#Measured
component.config.json, this pass: **10 interactive components, 10 declaring asurface-*ground, 0 without one**; 20 non-interactive components declare one too — *disk, this pass*.tokens:verifyafter the change: VERIFY OK,affordance 10 component(s) accept input, by carrier: corner 9, shape 1 — not by a radius token: radio-button, and10 of 10 draw(s) a surface-* ground— *darwin-arm64, this pass*.- Observed red, three branches, each restored to green *(this pass)*:
buttongivenaffordance: 'underline'— three failures at once: no rule drawn inbutton.css, asurface-*ground declared, and aspace.radiusbeside it.buttonstripped of itssurface-*roles while takingcorner—there is no perimeter for the radius to turn, the direction that was unreachable before this record.- Config restored byte-identical to HEAD,
VERIFY OK. pnpm battery— the verdict this pass is measured by.