Skip to contentWolf-Rayet

Decision records

ADR-0043 The ladder's first rung, and the check that could not see it missing

Accepted2026-09-04Phase 4, reopened

#Context

emitter-ambient is declared at level 1 in semantic.config.json and resolves in all four themes. It is referenced by zero components. Every component that declares both level 1 and level 2 assigns them the same colour role — 47 variant rows across 17 components — so the five-step intensity ladder §2 defines is running as a four-step ladder everywhere the set is used.

That did not happen by inattention. Two $markNotes in component.config.json record the reason and name the measurement: in field-night, emitter-ambient binds to neutral/2 and every ground an Emitter can sit on is neutral/0 or neutral/1; the repo's own contrastLc returns |Lc| 0.00 for both pairs, because all three sit inside APCA's black soft clamp. A mark nobody can find is not a resting mark, it is an absent one, and §4 designs in field-night first. Each component in turn took the same step, and the note travelled with them.

What no record contains is the other half, and it is the larger half. Rungs 1 and 2 do not form an ordered pair in any theme:

themeemitter-ambientemitter-marked\Lc\on raisedreading
interior-lightneutral/3accent/362.32 vs 61.55rung 1 is louder than rung 2
interior-darkneutral/5accent/579.99 vs 80.38separated by 0.39 — noise
field-dayneutral/2accent/293.30 vs 92.85rung 1 is louder than rung 2
field-nightneutral/2accent/30.00 vs 19.18rung 1 is invisible

The mechanism is in the generator and verify-output.js already states it: generate.js builds base once per theme and each ramp starts from base.slice(), so two roles assigned the same step index resolve to the same L by construction, differing only in hue and chroma. Three of the four themes bind emitter-ambient and emitter-marked to the same step index. In those three, the distinction between Ambient and Marked is carried by hue alone — which §4 forbids as a carrier and field-night, with one locked hue angle, cannot express at all.

This is the exact condition ADR-0039's Rule A exists to fail, and Rule A reports zero violations. It builds its role set from the component tier:

const markRoles = new Set();
for (const name of componentNames)
  for (const byLevel of Object.values(componentConfig.components[name].mark))
    for (const role of Object.values(byLevel)) markRoles.add(role);

emitter-ambient is in no component's mark table, so it is in no pair, so it is never checked. The check is green because the role is unused, and the role is unused because it is broken. That is ADR-0041's shape — a check whose passing condition its subject's absence satisfies — found for a fourth time, and this time in the token verifier rather than in a component.

The forces, stated plainly. Level 1 is "at or near the substrate" by §2, which is correct for a resting *surface* and is what makes it hard for a *mark*. A monitoring surface is mostly resting: the ordinary state of a fleet panel is thirty things that are fine. A system that cannot render "fine" distinctly from "worth noting" has lost the distinction it will make most often.

#Decision

The ladder is repaired by rebinding roles to steps, not by moving a ramp. In every theme, emitter-ambient moves off the step it shares with emitter-marked to a step that is visible against both grounds and clearly below rung 2; in field-night the whole emitter ladder shifts up one step, because that theme's first three steps are inside the APCA black clamp and its top two are reserved for text, leaving exactly four usable mark steps for exactly four levels.

themerolefromto\Lc\raised / inset
interior-lightemitter-ambientneutral/3neutral/435.0 / 16.2
interior-darkemitter-ambientneutral/5neutral/337.8 / 36.5
field-dayemitter-ambientneutral/2neutral/555.8 / 34.6
field-nightemitter-ambientneutral/2neutral/320.0 / 19.8
field-nightemitter-markedaccent/3accent/436.9 / 36.8
field-nightstatus-positive · status-caution · status-criticalstep 3step 436.9 / 36.8
field-nightemitter-directedaccent/4accent/550.7 / 50.5

field-night's ladder then reads 20.0 < 36.9 < 50.7 < 59.9 on surface-raised, one ordered rung per level, on steps 3, 4, 5 and 6 — the four steps that theme has. emitter-demanded stays at critical/6. No ramp, no curve, no range and no ground binding changes in any theme; surface-raised and surface-inset keep their steps and their hexes everywhere.

Every component's level 1 is then reassigned from the role it borrowed to emitter-ambient, across the 47 variant rows that currently duplicate level 2. In field-night this is emission-neutral by construction: the level-1 mark moves from accent/3 at deviation 0.4468 to neutral/3 at 0.4479, a change of 0.2% per mark pixel, because the new rung sits where the borrowed one was.

And Rule A gains its positive half, as ADR-0041 requires. Its pair set is built from every role declared at an emitting level in semantic.config.json, not from the roles a component happens to reference, and the check is observed failing on the current bindings before it is trusted green on the new ones. A ladder rung that no component uses is the case the rule most needs to cover, because an unused rung is the symptom this record exists to name.

A count in this record was wrong when it was written, and is corrected here rather than quietly. The first revision said 42 variant rows across 17 components; the number was eyeballed off a printed list rather than counted, and the measured figure is 47 — 31 rows whose level 1 borrows emitter-marked and 16 whose level 1 borrows a status role. The component count, 17, was right. Everything the record decides is unchanged by the correction: the defect, the mechanism, the rebinding and the rejected options all concern role bindings and not row counts. What the corrected number changes is the size of the unit this record schedules next, and the split inside it — which is why the miscount is worth naming rather than silently overwriting.

#Rejected options

Re-curve field-night from its S-curve to an ease-out. Tested through the repository's own generateTheme rather than argued: cubic-bezier [0.3,0,0.3,1] → [0,0,0.35,1], range unchanged. It works on its own terms and it is the option this investigation started with — the ambient mark goes from |Lc| 0.00 to 15.34 on raised, the mark ladder widens 48% (marked 19.18 → 28.4), every APCA floor still passes, and the emission ceiling does not move at all, because mean adjacent ΔL is (max−min)/8 for any monotonic curve and only the *range* enters ADR-0030's formula. It lost on a number that has nothing to do with marks. surface-inset binds to neutral/1, and the ease-out moves neutral/1 from L 0.148 to L 0.295 — deviation from the substrate 0.0859 → 0.2452, 2.9× — against a field-night ceiling of 0.128641. A ground alone would then read nearly twice the entire budget of the Scope standing on it, and grounds are the large-area term the ceiling exists to bound. The option repairs the small-area channel by wrecking the large-area one.

Rebind field-night's ambient alone and leave everything else. The minimal change, and the one to try first: emitter-ambient is referenced by no component, so moving it moves no pixels at all. It lost on the ramp's own shape. neutral/2 reads 0.00 and neutral/3 reads 20.00, against emitter-marked at 19.18 — there is no step between invisible and louder than the rung above it. Taking neutral/3 without moving rung 2 inverts the ladder, which is the same defect as interior-light's and field-day's rather than a fix for field-night's.

Give field-night more ramp steps. Intuitive — the theme is short of room, so add rungs. Simulated at 9, 11, 13 and 15 steps through the real solver, and it makes the problem worse in every case: more steps across a fixed range shrinks every adjacent delta, so more of the bottom falls inside the black clamp, and by 13 steps the ambient mark is back to 0.00 with the mark ladder collapsing behind it (marked 19.18 → 14.9 → 11.3). The binding constraint is the range, not the count.

Widen field-night's range upward so the bottom steps clear the clamp. Directly addresses the cause. It lost because the range is what ADR-0006 and the theme's own note are about — L_max is the lowest in the system deliberately, and it is what makes this theme's emission ceiling the lowest. Raising the floor also raises surface-raised and surface-inset and so moves the ceiling and every load at once, which is the previous option's defect arriving by a different route. If the four usable steps ever prove too few, this is the option to reopen, and it is an ADR of its own because it changes what field-night is for.

Accept the collapse and amend §2 to four rungs. Honest, costs nothing, and it is what the system does today — the ladder would simply be declared as Substrate, Marked, Directed, Demanded, with Ambient a surface level rather than a mark level. It lost on the identity: level 1 is the most common state on a monitoring surface, and a system that rations attention is judged by how well it renders the things that are *not* asking for any. Dropping the rung the operator sees most is the wrong economy, and it would also make §2's "all three channels ride the same five-step ladder" false for the light channel while staying true for language and motion.

#Consequences

Three themes move no pixels. In interior-light, interior-dark and field-day only emitter-ambient is rebound, and no component references it, so the generated component tier is unchanged and every fixture renders identically. Those three themes' baseline values must be proved *unmoved* rather than re-recorded, which is a stronger assertion than a re-record and is checkable at exact equality.

field-night moves, and its blast radius is known. emitter-marked, emitter-directed and the three status roles are referenced heavily, so the 40 unthemed scenes — all authored in field-night — and the 7 themed field-night scenes move: 122 of 434 Scope values per platform, 28%. The other 312 must not move, and that is the pass's own check. Per mark pixel, emitter-marked rises 33% in deviation and emitter-directed 16%; emitter-demanded is unchanged. Against a tightest field-night margin of +33.6% (21-proof-supervisor-queue, #scope-queue, load 0.096293 against ceiling 0.128641) and a declared-element term of 13–52% of a Scope's load, the change is expected to fit. Expected is not measured, and the pass measures it.

Measured, and the prediction was high. The estimate above was taken from scene counts; the pass measured Scope values. On darwin-arm64: 68 of 101 unthemed values moved and 33 did not, and 21 of 333 themed values moved — 89 of 434 in all, 21%, against the 122 predicted. The gap is the 33 unthemed Scope values whose Scopes contain no element resolving through a moved role. Every one of the 21 themed movements is a field-night scene and no value in interior-light, interior-dark or field-day moved at all, which is the assertion this record staked itself on. No scene key and no Scope key was added or removed on either platform, and linux-x64 is byte-identical in both files. All 40 unthemed scenes and all 128 themed scenes kept their declared verdicts — 9 and 30 declared must-fails, failing, and nothing else failing *(darwin-arm64, this pass)*.

The level-1 reassignment is a second unit, not this one. Rebinding the roles and repairing Rule A is one commit; reassigning 47 variant rows across 17 components to the restored rung is the next, because it changes what every component draws at level 1 and needs its own before-and-after on the same baseline. Each carries its own linux-x64 follow-up under ADR-0032.

The enforcement table grows by nothing and Rule A changes shape. No new check kind: §9 Rule A keeps its name, its message and its place, and gains a wider pair set and a positive half. Its printed count rises, because roles that were invisible to it are now in it. tokens:verify must be observed failing on the committed bindings before the new ones are written, per ADR-0041.

ADR-0039 is not superseded; it is completed. Its Rule A and its reading of ADR-0027 — that same-level roles sharing a lightness is the ladder rather than a defect, and cross-level sharing is the defect — are both correct and both stand. What this record adds is that the rule was applied to a set that could not contain its own worst case. The four cross-level collisions ADR-0039 found and corrected were real; a fifth was standing in all four themes at the same time and was never a candidate.

A claim in fixture 26 is falsified and is corrected separately. The scene's header says its three button rows' shares "rise monotonically" and that the differences are the emphasis ramp priced in emission. Its committed receipt reads 0.004333, 0.004333, 0.004224 — flat, then down. The flatness is this record's subject and this record fixes it. The descent is not: it follows from surface-raised sitting closer to the substrate than surface-inset in all four themes, so ADR-0027's ground step reduces measured emission by construction. That is a separate question about whether emission is the right currency for emphasis, it is left open here, and the fixture's sentence is corrected to describe what it measures rather than what it predicted.