ADR-0089 A numeric field owes its unit and its bounds, and the scene caught the scene
#Context
ADR-0081 audited section C as a group and found the collapse the identity test exists to refuse sitting inside the built half: input-field, text-area, select and number-input share all six tier axes, declare identical governed copy — *what this field collects* and *guidance, or the correction when the value is invalid*, character for character — and none of them discloses. Four built components alike on all eight of §12's dimensions.
That record claimed two of the four were separable. ADR-0083 retracted one of those claims after measuring it: a closed select's options are not hidden, they were never in the frame, so select does not carry D5. One separation was left, and standing item 24 has held it since.
#The separation
A numeric field owes what no other field owes: the unit it collects in and the values it will accept.
71 is not a reading. 71 degrees, 40 to 90 is. And neither half can be verified by looking at the control — a number box shows no sign of its unit and no sign of its bounds until it refuses something.
That is the same property that made region's count required (ADR-0058) and kept pagination when the audit was run at it (ADR-0066): §12's D4 asks for *a classification of the thing it sits on that the reader cannot verify by looking*, and this is one.
So range is a third governed part, required, with no default — for those records' reason, that an optional obligation is not one. A field that omitted it would be a box asking for a number without saying which numbers.
It is a string rather than a min/max/unit triple, on region's reason: what a reader needs is the system's words, not a format this component invents. The control's own min and max are the input element's concern and stay there.
#The scene caught the scene
The component was built, the tier grew two tokens, and the fixture was re-recorded. The baseline moved the wrong way and the receipt said why.
before governed 216000 load 0.074435 attribution 6 after governed 216000 load 0.067155 attribution 5
Identical governed pixels and less emission, which is not what adding a caption line to five fields does. The attribution names the cause: #field-retention is gone. A fourth line per field overflowed a Scope whose height the scene stylesheet fixes at 640px, and the fifth field fell outside it. The load fell because part of the screen had left the screen.
A baseline cannot see this on its own — the number moved, which is what a baseline reports, and the direction is not something it has an opinion about. What made it visible is that the receipt lists *which elements* the load came from, and one of them stopped being listed.
#Decision
number-input declares a third governed part, range, required, whose role is *the unit it collects it in and the values it will accept*. It renders under the control rather than beside the label, because a reader checking whether a value is legal is looking at the control when they ask.
The scene gets its own stylesheet. _scene-input.css is shared by the input, number-input, select and text-area scenes, so raising its height would move four scenes' baselines for one component's change. _scene-number-input.css is a sibling of it at 780px — the pattern every scene stylesheet in this repository already follows, and for the reason each of them states: baseline.json is calibrated against the scenes that already exist.
Standing item 24 narrows from four components to three. input-field, text-area and select remain alike on all eight dimensions, and the item's other half is unchanged: what distinguishes text-area from input-field is a line count, and ADR-0057 removed three roster rows to keep quantities out of the tier.
#Rejected options
Take min and max and render them. The component already has both, so the copy could be computed — and it would be this component inventing a format, in a system where region states a count in the product's own words for exactly that reason. It also cannot carry the unit, which is half the obligation.
Make it optional, so existing callers keep compiling. Every caller in this repository was updated in this pass and there are eleven of them. An optional obligation is not an obligation, and D4 is about what the parts are *obliged* to say.
Raise _scene-input.css to fit. One line, and it moves the baselines of four scenes — three of which have nothing to do with this change. A shared stylesheet is shared.
Drop a field from the scene so it fits. The scene would measure five fields where it says five and show four, which is the defect this pass found rather than a fix for it.
Separate text-area instead and leave this alone. It is the other live half of item 24 and there is nothing to separate it on: a line count is a quantity.
#Consequences
Three of the four are still one component on the eight dimensions. This closes one quarter of standing item 24 and the record says so rather than claiming the item.
The component's copy obligation is checked end to end. content-lint:scan reads the story's real strings: 72 real strings across 39 scan entries, three of them this component's, the new one clean at its role.
Two tier tokens, 805 across 38 components, and no APCA check moved — the new part takes text-secondary at caption size, which is hint's weight, because both are annotations on the control rather than claims of their own.
linux-x64 holds stale values for scene 38 and its three themed siblings. The scene counts are unchanged, so status:check is green and the gap is a *movement* gap rather than an absence gap — which standing item 12 has never had before. It will surface as BASELINE MOVED on the next push rather than as an absence, and it cannot be closed this evening because nothing is being pushed.
#Measured
- Governed copy across the four-component bucket before this pass:
input-field,text-area,selectandnumber-inputall declaring{"label":"what this field collects","hint":"guidance, or the correction when the value is invalid"}— identical objects *(disk, this pass)*. - Scene 38 with the part added and the scene's inherited height: governed 216000, load 0.067155, attribution 5 — down from 0.074435 and 6, with
#field-retentionabsent *(darwin-arm64, this pass)*. - With
_scene-number-input.cssat 780px: governed 266400, load 0.070331 against a ceiling of 0.128641, attribution 6,#field-retentionrestored *(darwin-arm64, this pass)*. tokens:verify— VERIFY OK; 805 component tier tokens across 38, up from 803; 2,216 APCA checks, unchanged *(darwin-arm64, this pass)*.content-lint:scan— 72 real strings, 0 violations; the new part reads *the unit it collects it in and the values it will accept* *(this pass)*.- Every battery check but
build:checkrun green before the commit;build:checkcompares against HEAD and passes with it.