docs: record the semantic palette landing, and one claim that was false
The two findings recorded as too big for the contrast pass are fixed, so the plan says so. Also corrects a claim I made and did not check: the chrome does not stay dark under the light ramp -- that screenshot was taken before the theme propagated, which is the third time in two passes a picture read at the wrong moment produced a confident wrong claim.
This commit is contained in:
@@ -1954,3 +1954,77 @@ Nine things worth keeping:
|
||||
and every one was a *different* mechanism. A finding at 110 nodes
|
||||
hides them; at 3 they are individually obvious. Cheap tail, only
|
||||
reachable from the other side of the main fix.
|
||||
|
||||
## A role, not a value, decides whether a colour can be fixed
|
||||
|
||||
Plan 008 phase 2, third landing: the two findings the contrast pass had
|
||||
recorded as too big to fix in it, fixed — plus the check for the trap
|
||||
that has now cost four sessions.
|
||||
|
||||
The generalisation: **a token that is used for two different jobs will
|
||||
be wrong at one of them, and no amount of choosing a better value
|
||||
fixes it.** `--yj-error` was "the colour of error", which is two
|
||||
questions. As the *background of a danger button* it wants to stay red
|
||||
in every theme, and it does. As *the word `failed` on a surface* it
|
||||
cannot be one value at all — a single colour cannot clear 4.5:1 against
|
||||
both a near-black and a near-white background, which is why the fixed
|
||||
set measured 2.31–4.28:1 on nearly every combination. Splitting the
|
||||
token by the question it answers made both answerable; picking better
|
||||
hexes never would have.
|
||||
|
||||
The same shape twice more in the same landing:
|
||||
|
||||
- **A fill's foreground cannot be written down**, because the accent is
|
||||
a colour picker. `color: #000` is right for the current default
|
||||
yellow and wrong for a navy one. `readableOn()` computes it — white
|
||||
where white clears 4.5:1, black otherwise — which keeps a red danger
|
||||
button conventional (4.51:1) and flips a green one (3.45:1).
|
||||
- **`var(--yj-bg-base)` as a foreground is a token used for the wrong
|
||||
meaning.** Two accent buttons did that. It reads as "the opposite of
|
||||
the accent" and it is not: it inverts with the ramp, so the light
|
||||
theme rendered white on yellow at 1.43:1. The bug is not the value,
|
||||
it is that the *name* did not mean what the call site needed.
|
||||
|
||||
Six more things worth keeping:
|
||||
|
||||
- **The picture and the number disagreed, and the number was mine —
|
||||
again.** I recorded "the header and player chrome stay dark while the
|
||||
body goes light" as a finding, in the plan and in these notes. It is
|
||||
false: `.top-bar` is `#e9ecef` and `.sidebar` `#f8f9fa` under the
|
||||
light ramp, and a re-taken screenshot agrees with the DOM. The
|
||||
original was captured before the theme had propagated. That is the
|
||||
third time in two passes a screenshot read at the wrong *moment*
|
||||
produced a confident wrong claim, after a spec reading the DOM before
|
||||
a fetch and a sweep that had moved the app to another ramp. **A
|
||||
screenshot has a timestamp and a state; check both before quoting
|
||||
it.**
|
||||
- **A `color:` regex matches `border-color:`.** Twice in one landing —
|
||||
3 borders while rewriting semantic text, then 30 more while rewriting
|
||||
accent text. Both caught by grepping the *result*, not by any test,
|
||||
because a border in the wrong shade fails nothing and looks fine.
|
||||
When a mechanical rewrite is the right tool, the review is a grep of
|
||||
what it did, not a run of the suite.
|
||||
- **A fix at the ubiquitous case makes the rare ones findable.** The
|
||||
greyscale fix took the dark ramp to 0 and the light ramp from 50 to a
|
||||
list short enough to read individually — at which point every
|
||||
remaining item was a *different* mechanism, and two of them were the
|
||||
findings above. A queue of 110 hides its own structure.
|
||||
- **Knowledge that has been ignored three times is not a knowledge
|
||||
problem.** The backtick-in-a-`css`-comment trap is documented in
|
||||
`CLAUDE.md`, in the skill and here; I read it twice in the session it
|
||||
then cost a cycle in. It is `make css-check` now — a pre-commit hook
|
||||
and a CI step. The detection is exact rather than heuristic: if a
|
||||
backtick in a comment closed the literal early, the text the parser
|
||||
took as the literal contains an unterminated `/*`, and nothing else
|
||||
produces that.
|
||||
- **The value of that check is the sentence, not the failure.** `tsc`
|
||||
already failed on it — with `Class static side 'typeof NowPlaying'
|
||||
incorrectly extends base class static side` and `Property 'scroll'
|
||||
does not exist on type 'CSSResult'`, pointing at a line of prose. The
|
||||
check was verified by breaking a file on purpose and reading both
|
||||
reports side by side, which is also the only way to know it fires.
|
||||
- **A change can be invisible to the tier that looks the most like it
|
||||
covers it.** `make ui-visual` passed unchanged through a whole
|
||||
palette rewrite, twice, because the component tier has no `:root` and
|
||||
renders the fallbacks. The tier that *did* catch things was a unit
|
||||
test over the palette table and a probe against the running app.
|
||||
|
||||
@@ -325,23 +325,60 @@ access to any value by not being able to. **Stays dropped.**
|
||||
|
||||
#### Two things the measurements found that are not in the audit
|
||||
|
||||
Both are bigger than what they were found under, and neither is fixed:
|
||||
Both were bigger than what they were found under. Both are now fixed —
|
||||
see the third landing below.
|
||||
|
||||
- **The semantic colours are fixed across ramps, and a fixed colour
|
||||
- **The semantic colours were fixed across ramps, and a fixed colour
|
||||
cannot serve a near-black and a near-white background.** `--yj-error`
|
||||
is 3.42:1 on dark's surface and 2.55:1 on its elevated; `--yj-info`
|
||||
is 3.10:1 and 2.31:1; success and warning fail on dark and light
|
||||
both. As *backgrounds* under white text, success (3.45) and warning
|
||||
(3.58) fail too. The fix is a per-ramp semantic palette, which is a
|
||||
decision about the app's colour identity rather than a value.
|
||||
- **The light ramp is not a supported theme.** With the greyscale fixed
|
||||
it still has **50 failing nodes**: the accent yellow under white text
|
||||
(1.43:1), the autotag diff's pale greens and reds on white
|
||||
(1.36–2.59:1), and the header and player chrome staying dark while
|
||||
the body goes light. Read in a screenshot — the "Low confidence pick"
|
||||
banner is invisible and the primary button is white-on-yellow. This
|
||||
is a design job, and the honest question it raises is whether the
|
||||
light theme should ship at all in its current state.
|
||||
measured 3.42:1 on dark's surface and 2.55:1 on its elevated;
|
||||
`--yj-info` 3.10:1 and 2.31:1; success and warning failed on dark and
|
||||
light both. As *backgrounds* under white text, success (3.45) and
|
||||
warning (3.58) failed too.
|
||||
- **The light ramp was not a usable theme.** With the greyscale fixed
|
||||
it still had **50 failing nodes**: the accent yellow under white text
|
||||
(1.43:1) and the autotag diff's pale greens and reds on white
|
||||
(1.36–2.59:1).
|
||||
|
||||
### Phase 2, third landing — the ramp reaches the semantic colours
|
||||
|
||||
**2237 nodes across three ramps and twelve views, 0 failing.**
|
||||
|
||||
The split is by the question a colour answers. A **fill** is "what
|
||||
colour is a danger button" — red in every theme, unchanged. A **text**
|
||||
colour is "what colour is the word *failed* on this background" — per
|
||||
ramp, because one value cannot clear 4.5:1 against both a near-black and
|
||||
a near-white surface. `bgOverlay` keeps the exception it already had on
|
||||
the dark ramp.
|
||||
|
||||
And every fill now carries a **computed foreground**, because the accent
|
||||
is a colour picker and no fixed answer survives one: white if white
|
||||
clears 4.5:1, else black. That keeps a red danger button white and
|
||||
flips a green or amber one to black. Accent-as-text goes through
|
||||
`accentTextOn()`, which mixes along the hue until it clears the ramp's
|
||||
surface and stops — returning the accent *unchanged* on both dark
|
||||
ramps, so the dark themes are visually untouched by that half.
|
||||
|
||||
`make ui-test` 608 → **649**.
|
||||
|
||||
#### Where this pass was wrong
|
||||
|
||||
- **"The chrome stays dark while the body goes light" was mine, and it
|
||||
was false.** I read it off a screenshot; the DOM says `.top-bar` is
|
||||
`#e9ecef` and `.sidebar` `#f8f9fa` under the light ramp, and a
|
||||
re-taken screenshot agrees. The first one was captured before the
|
||||
theme had propagated. Third time in two passes that a screenshot read
|
||||
at the wrong moment produced a confident wrong claim — and the second
|
||||
time this pass that **the picture and the number disagreed and the
|
||||
number was mine**.
|
||||
- **A `color:` regex matches `border-color:`.** Twice: once rewriting
|
||||
semantic text colours (3 borders) and once rewriting accent text (30
|
||||
more). A border is a fill, not text. Caught by grepping the result
|
||||
rather than by any test, because nothing renders differently enough
|
||||
to fail.
|
||||
- **Two accent buttons took their foreground from `--yj-bg-base`**,
|
||||
which inverts with the ramp — white on yellow at 1.43:1. That is not
|
||||
a colour that was chosen badly; it is a token used for the wrong
|
||||
meaning, and it only shows up in the theme nobody looks at.
|
||||
|
||||
---
|
||||
|
||||
@@ -358,10 +395,8 @@ Two of them are not one-liners and should be treated as such:
|
||||
minimum at 800×600. Reflow at high zoom is the same question one
|
||||
variable over. It may want its own landing.
|
||||
- **The unnamed `<select>`s** from Phase 1, with `26`.
|
||||
- **The semantic palette** and **the light ramp**, from Phase 2. Both
|
||||
are larger than the rest of this tail put together and may not belong
|
||||
in it at all — the light ramp in particular is a question about
|
||||
whether that theme ships, not a contrast fix.
|
||||
- ~~**The semantic palette** and **the light ramp**~~ — both landed in
|
||||
Phase 2's third pass rather than waiting for this tail.
|
||||
- **`22`** asks for a non-colour marker on the playing row, which is a
|
||||
visual change to the densest list in the app and moves a baseline.
|
||||
|
||||
|
||||
@@ -505,6 +505,23 @@ first track arrives) and `job-indicator`, whose label swings between
|
||||
"Scanning Music", "3 background jobs" and "Finished". The notification
|
||||
surface already had one from Phase 3.
|
||||
|
||||
**A colour's role decides whether it can be fixed across themes.** A
|
||||
*fill* — `--yj-error`, `--yj-success` — is "what colour is a danger
|
||||
button", which is red in every theme and stays fixed. A *text* colour
|
||||
— `--yj-error-text` — is "what colour is the word *failed* on this
|
||||
background", which cannot be: one value cannot clear 4.5:1 against both
|
||||
a near-black and a near-white surface, and the old fixed set measured
|
||||
2.31–4.28:1 on nearly all of them. And every fill carries a **computed**
|
||||
foreground (`--yj-accent-fg`, `--yj-*-fg`) rather than a written-down
|
||||
one, because the accent is a colour picker: white on the default
|
||||
`#ffd43b` is 1.43:1. `readableOn()` keeps white where white clears and
|
||||
flips to black where it does not, and `accentTextOn()` mixes the accent
|
||||
along its own hue until it clears the ramp's surface — returning it
|
||||
unchanged on both dark ramps. Two accent buttons used to take their
|
||||
foreground from `--yj-bg-base`, which *inverts with the ramp*; that is a
|
||||
token used for the wrong meaning, and it only shows in the theme nobody
|
||||
looks at.
|
||||
|
||||
**Contrast is a property of the ramp, and the ramps are data.**
|
||||
`theme-store`'s `SHADE_PALETTES` — not `tokens.css.ts`, which holds only
|
||||
the type scale and icon sizes — is where the colours live, applied to
|
||||
|
||||
Reference in New Issue
Block a user