Skip to content

feat(photos): zenc:bench, a byte-identity gate and timer for zenc speed work - #888

Merged
oddharsh merged 2 commits into
mainfrom
claude/agentic-iteration-optimization-17c1b2
Sep 22, 2026
Merged

oddharsh merged 2 commits into
mainfrom
claude/agentic-iteration-optimization-17c1b2

Conversation

@oddharsh

@oddharsh oddharsh commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

bun run zenc:bench answers one question: is the working tree's zenc faster than a baseline, with byte-identical output? It's the instrument for running Max Woolf's agentic-iteration loop on this crate.

How it works

  1. Builds the merge-base with origin/main as the baseline (cached by zenc tree, so a loop pays for it once), and the working tree as the candidate.
  2. Gate: runs both on six sources, one per class production meets (HIF upright and rotated, X-T50 JPEG upright, rotated and orientation 6, Monochrom gray path), with add-photos.sh's exact square command. Every output and all 258 histograms must match byte for byte.
  3. Control: re-encodes one source at q83 and requires exactly its 600.jpg to move. A comparison that has never found anything proves nothing.
  4. Timer, only if 2 and 3 pass: 7 alternating A/B trials per source, reported as wall-clock and as CPU (user + sys), each source called by an exact two-sided Mann-Whitney U at p < 0.01. --parallel 8 measures throughput, which is how add-photos.sh runs.
  5. Split: prints how much of each photo is zenc's own code, so nobody iterates past the ceiling.

A moved byte prints no timing at all. /i/ is content-addressed, so a faster zenc with different output is a different encoder, and it re-mints URLs (gotchas 35, 46). That also closes every cheat Woolf caught (skipping work, loosening a knob, trimming epochs): each one fails cmp on the first source.

What its first run found

share of a photo
libavif (speed 2, knobs are quality flags per gotcha 43) ~72%
zenc's own code: decode, orient, linearise, 3 full-frame resamples 28%

So byte-identical wins on our code cap at about 1.39x. The sharpest lead: rotated sources spend 39-47% in our code against 13% upright. On one 26 MP JPEG the floor reads 520 ms upright and 745-880 ms rotated, so orient() costs 225-360 ms, and 135 of 185 sources are rotated. Reading the source through the orientation inside the resample is identity-safe by construction. That's the next PR, not this one.

Proven on real binaries

case result
unchanged tree (noise floor) 1.000x, nothing called, every p ≥ 0.38
byte-moving change (crop shifted 1 px) exit 1, 8 outputs listed, no timing; only the 2 landscape frames moved, as they should
byte-neutral source change (unused default q84 to q83) gate passes, timings print, no difference
candidate that panics exit 2, names the source

Fixed by running it

The first loop through the bench (#889) found two flaws in it, fixed in the second commit here:

  • Wall-clock can't see throughput. The pipeline is CPU-bound at 8 workers, and the tiled orient read 1.004x on wall-clock at --parallel 8 while saving 5.4-7.0% of CPU per rotated photo. Every run now prints a CPU table.
  • The first verdict called false wins. "Beyond its own (max - min) / median spread" called one of six sources faster, in both tables, on a noise-floor run of identical source at 3 trials. It's an exact Mann-Whitney now, with 7 trials by default; below 5 no ordering can reach p < 0.01, so the CLI refuses. The noise-floor control at 7 trials calls nothing (every p ≥ 0.38), and perf(photos): orient full frames by row and by tile instead of per pixel #889's rotated sources are called at p = 0.0006 while its upright ones stay uncalled.

Deliberately not here

  • criterion, which is what I first proposed. It times functions inside one build, and the question is two builds of one command. It would also land in zenc's Cargo.lock, a declared input to the histogram derivation, and compile inside validate via clippy --all-targets.
  • The orientation optimization. Separate PR.

Also

  • contract-zenc-bench-times-the-production-command pins the bench's argv to add-photos.sh, with three controls proving the comparison has teeth.
  • zenc/README.md gains "Optimizing zenc": Woolf's AGENTS.md benchmarking rules adapted to a content-addressed crate.
  • CLAUDE.md: the "~19s histogram bake" figure is stale; it's 0.6 s for 258 stems now.

Checks: lint, full typecheck, test (847 pass / 0 fail), test:node (837 pass / 0 fail on the first commit), derive:check, tools:check.

…ed work

bun run zenc:bench builds the merge-base as a baseline, gates every zenc square
output and all 258 histograms byte for byte, runs a control that must fire, and
only then times both binaries interleaved. A moved byte prints no timing at all,
because /i/ is content-addressed and a faster encoder with different output
re-mints URLs.

Its first run found where the time goes: libavif is about 72% of a photo and
its knobs are quality flags, zenc's own code is 28%, and rotated sources spend
225-360 ms in orient() alone. That is the first target for the loop.

Also corrects CLAUDE.md's stale "~19s histogram bake": it is 0.6 s now.
@github-actions github-actions Bot added area: docs Runbooks and repository prose area: infra Declared Cloudflare state, wrangler config, pins area: photos The photo pipeline and everything it emits area: tools Developer tooling and the contract suite type: feat New capability or surface labels Sep 22, 2026
@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Wire-size diff vs merge base

f03b0107b87dc5c3c696b6031478cc639c4f95ea → e5c2c1b7d055cf0de450062416dbb96774a00c5b

Brotli q11, the quality the edge serves. Every number here is deterministic:
an unchanged file produces no row. Advisory — this check fails on nothing.

Client assets

No change. 26 files, 87.55 KiB Brotli total.

Pages

No change. 57 files, 585.04 KiB Brotli total.

Worker bundle

No change. 250.16 KiB gzip.

Dictionary transport

Family dictionary acquisition: no change, 14.41 KiB q11.

pd/: no change. 113 deltas, 488.91 KiB total.

…t test

Two flaws the first loop through the bench turned up.

Wall-clock cannot see a throughput change. add-photos.sh runs 8 photos at once
and the pipeline is CPU-bound, so the tiled orient() read 1.004x at --parallel 8
(load 7.4, noise +-11.7%) while saving 5.4-7.0% of CPU per rotated photo. Every
run now prints a CPU (user + sys) table beside the wall one.

The per-source verdict called false wins. "beyond its own (max - min) / median
spread" called one of six sources faster, in both tables, on a noise-floor run
of identical source at 3 trials. Each source is now judged by an exact
two-sided Mann-Whitney U at p < 0.01, with 7 trials by default; below 5 per side
no ordering can reach that, so the CLI refuses. The noise-floor control at 7
trials calls nothing, every p at 0.38 or above.
@oddharsh
oddharsh added this pull request to stack #890 September 22, 2026 19:01
@oddharsh
oddharsh merged commit b9f8150 into main Sep 22, 2026
15 checks passed
@oddharsh
oddharsh deleted the claude/agentic-iteration-optimization-17c1b2 branch September 22, 2026 19:01
oddharsh added a commit that referenced this pull request Oct 6, 2026
…s they hid

The token contract read oklch() only, and the site writes most of its colour
in hex: 2,248 hex and 82 rgb() literals on 2026-10-06. Measured against the
tokens by OKLab distance, 87 were a token retyped in sRGB (#f3f6fa for
--row-alt 51 times over, #888 for --ink-faint, #e8eef7 for --surface-desktop).

- colorLiteralsIn() reads oklch(), hex and rgb()/rgba() with one set of
  guards: SVG presentation attributes, and for the sRGB spellings anything
  outside a declaration value, so #fab in a selector or a hex in a comment
  (access's note on why its greys moved) is never a colour.
- tokenCopiesIn() and colors:drift both use it. The report now covers 3,884
  literals and lists 156 colours hand-written in 3+ files with no token.
- 84 copies swept to var(): 55 in pages, stylesheets and Workers, 29 inside
  garage and lwe spec CSS (pageCss/demoCss lines only, never demoJs), with
  every generated page regenerated. Two whole gradients were --grad-raised
  stop for stop (luna's button face, serendipity's) and now say so.

Invisible: every swap is under dE 0.004 of its token.
oddharsh added a commit that referenced this pull request Oct 6, 2026
…s they hid

The token contract read oklch() only, and the site writes most of its colour
in hex: 2,248 hex and 82 rgb() literals on 2026-10-06. Measured against the
tokens by OKLab distance, 87 were a token retyped in sRGB (#f3f6fa for
--row-alt 51 times over, #888 for --ink-faint, #e8eef7 for --surface-desktop).

- colorLiteralsIn() reads oklch(), hex and rgb()/rgba() with one set of
  guards: SVG presentation attributes, and for the sRGB spellings anything
  outside a declaration value, so #fab in a selector or a hex in a comment
  (access's note on why its greys moved) is never a colour.
- tokenCopiesIn() and colors:drift both use it. The report now covers 3,884
  literals and lists 156 colours hand-written in 3+ files with no token.
- 84 copies swept to var(): 55 in pages, stylesheets and Workers, 29 inside
  garage and lwe spec CSS (pageCss/demoCss lines only, never demoJs), with
  every generated page regenerated. Two whole gradients were --grad-raised
  stop for stop (luna's button face, serendipity's) and now say so.

Invisible: every swap is under dE 0.004 of its token.
oddharsh added a commit that referenced this pull request Oct 6, 2026
…s they hid

The token contract read oklch() only, and the site writes most of its colour
in hex: 2,248 hex and 82 rgb() literals on 2026-10-06. Measured against the
tokens by OKLab distance, 87 were a token retyped in sRGB (#f3f6fa for
--row-alt 51 times over, #888 for --ink-faint, #e8eef7 for --surface-desktop).

- colorLiteralsIn() reads oklch(), hex and rgb()/rgba() with one set of
  guards: SVG presentation attributes, and for the sRGB spellings anything
  outside a declaration value, so #fab in a selector or a hex in a comment
  (access's note on why its greys moved) is never a colour.
- tokenCopiesIn() and colors:drift both use it. The report now covers 3,884
  literals and lists 156 colours hand-written in 3+ files with no token.
- 84 copies swept to var(): 55 in pages, stylesheets and Workers, 29 inside
  garage and lwe spec CSS (pageCss/demoCss lines only, never demoJs), with
  every generated page regenerated. Two whole gradients were --grad-raised
  stop for stop (luna's button face, serendipity's) and now say so.

Invisible: every swap is under dE 0.004 of its token.
oddharsh added a commit that referenced this pull request Oct 6, 2026
…s they hid (#1183)

The token contract read oklch() only, and the site writes most of its colour
in hex: 2,248 hex and 82 rgb() literals on 2026-10-06. Measured against the
tokens by OKLab distance, 87 were a token retyped in sRGB (#f3f6fa for
--row-alt 51 times over, #888 for --ink-faint, #e8eef7 for --surface-desktop).

- colorLiteralsIn() reads oklch(), hex and rgb()/rgba() with one set of
  guards: SVG presentation attributes, and for the sRGB spellings anything
  outside a declaration value, so #fab in a selector or a hex in a comment
  (access's note on why its greys moved) is never a colour.
- tokenCopiesIn() and colors:drift both use it. The report now covers 3,884
  literals and lists 156 colours hand-written in 3+ files with no token.
- 84 copies swept to var(): 55 in pages, stylesheets and Workers, 29 inside
  garage and lwe spec CSS (pageCss/demoCss lines only, never demoJs), with
  every generated page regenerated. Two whole gradients were --grad-raised
  stop for stop (luna's button face, serendipity's) and now say so.

Invisible: every swap is under dE 0.004 of its token.

Co-authored-by: Aadharsh Pannirselvam <19518661+oddharsh@users.noreply.github.com>
oddharsh added a commit that referenced this pull request Oct 6, 2026
…ue holds (#1193)

* feat(type): every pt size and font family names a typography token

typography.css has carried a pt scale and three family stacks since the
design system was written. On 2026-10-06 the scale had 23 consumers against
1,072 hand-written sizes in 70 distinct values, and 55 family stacks were
spelled out by hand (31 of them "Courier New",monospace, the mono token with
its fallbacks dropped).

- The scale grows to what the site sets: --text-lg 13pt, --text-lede 11pt,
  --text-2xs 8pt, --text-3xs 7.5pt, --text-4xs 7pt. 8pt alone had 98 uses.
- 989 declarations in the sources rewritten to tokens; generated garage and
  lwe pages regenerated from their specs and generators.
- 121 off-grid declarations snapped to the nearest step, ties down. Most move
  0.2pt or less (8.6 and 8.4 -> 8.5, 8.8 -> 9, 8.2 and 7.8 -> 8). Six move
  0.4-0.5pt: 12.5 -> 12 and 11.5 -> 11 (two each), 6.5 and 6.6 -> 7.
- contract-type-comes-from-the-tokens refuses a pt size up to 14pt or a family
  stack outside var(--font-*). px (pixel-exact chrome, SVG text), relative
  units and display sizes over 14pt stay legal; three rules say @type demo
  (horizon's console caret, the polaroid's handwriting, lwe's CJK avatar).
- The homepage loads luna.css without blocking, so it inlines the five size
  tokens it reads; the contract holds that copy to typography.css.
- cssSources() now reads lwe specs' demoCss, which neither contract saw.
- colors.css's --text-body: var(--ink) is gone. typography.css's --text-body
  (10.5pt) loads after it in luna.css, so the colour alias never applied.

Checked in a browser: no element on 8 sampled pages computes to the 16px
default; /garage/useragent's size histogram moves exactly by the snaps.

* fix(tokens): read hex and rgb() as colours, and sweep the token copies they hid

The token contract read oklch() only, and the site writes most of its colour
in hex: 2,248 hex and 82 rgb() literals on 2026-10-06. Measured against the
tokens by OKLab distance, 87 were a token retyped in sRGB (#f3f6fa for
--row-alt 51 times over, #888 for --ink-faint, #e8eef7 for --surface-desktop).

- colorLiteralsIn() reads oklch(), hex and rgb()/rgba() with one set of
  guards: SVG presentation attributes, and for the sRGB spellings anything
  outside a declaration value, so #fab in a selector or a hex in a comment
  (access's note on why its greys moved) is never a colour.
- tokenCopiesIn() and colors:drift both use it. The report now covers 3,884
  literals and lists 156 colours hand-written in 3+ files with no token.
- 84 copies swept to var(): 55 in pages, stylesheets and Workers, 29 inside
  garage and lwe spec CSS (pageCss/demoCss lines only, never demoJs), with
  every generated page regenerated. Two whole gradients were --grad-raised
  stop for stop (luna's button face, serendipity's) and now say so.

Invisible: every swap is under dE 0.004 of its token.

* fix(tokens): the chrome and title blues resolve to the XP hex their comments name

colors.css said its values "resolve to period-correct Luna" and never
measured it. They came in with a generated design system on 2026-06-05 and
sat up to dE 0.040 from their hex (--darkshadow vs #716F64) and 0.042 for the
title blues (--blue-95 vs #3D95FF): every chrome colour darker and greyer
than XP, with round-number lightness that read like an estimate.

- Chrome: --hue-chrome 96.85, --chroma-chrome 0.0228, exact lightness and
  chroma per token. One knob still drives all four; each lands within
  dE 0.0008 of ButtonFace, ButtonLight, ButtonShadow and the 3D dark shadow.
- Title blues: --chroma-luna 0.2274 and a per-token hue offset (the ramp
  already used them) put --blue-65, --blue-95, --blue-inactive and --blue-50
  within dE 0.0001 of ActiveTitle, GradientActiveTitle, InactiveTitle and
  Highlight. Every title bar and the selection colour move with this.
- The contract now reads a hex in a token's comment as a claim and holds it
  within dE 0.002. Control: the old values fail it on seven tokens.
- With the tokens on XP, 12 hand-typed XP hex values became copies and are
  swept (#316ac5, #ece9d8, #aca899, #0054e3).
- A var() fallback is now legal for a colour literal, as it already was for
  a font stack. luna's client edge says var(--face,#ece9d8): build.ts mirrors
  it into the homepage, which paints before luna.css defines --face, and a
  bare var() would drop the 6px border the mirror exists to keep. build.ts's
  extractor and its homepage check accept that form.

Rendered (local build, 9 pages): the chrome retune moves 0 to 0.4% of
pixels on 8 pages by at most 5/255; the title blues move about 2% (the title
bars) by up to 28/255.

* feat(tokens): snap near-miss colours onto their token only when the hue holds

Decision C from the palette proposal. 1,054 literals sat 0.004 to 0.02 from
a token, and the prototype that snapped all of them turned /whoareyou's
content pane cream. Two causes, both measured:

- 357 of them were white. White is four tokens' value, so the contract never
  calls it a copy, and the prototype read #fff as a near-miss of the warm
  --paper. White and black are never near-misses of one token now.
- A move that changes hue, or puts a tint on a neutral, changes temperature
  even under the just-noticeable difference. Each near-miss is split into its
  lightness, chroma and hue parts, and it snaps only when the hue part is
  under 0.003 and the chroma change under 0.004: greys onto the ink ramp,
  blue-greys onto --surface-desktop and --rule, a lighter --row-alt.

- New --paper-cool, oklch(98% 0.004) at --hue-luna - 13: the cool twin of
  the warm --paper, which the site already wrote as a hand-mixed near-white
  in 18 files. 22 copies of it swept.
- 252 literals in 55 source files now name a token, garage and lwe spec CSS
  included (pageCss/demoCss lines only); every generated page regenerated.
- 400 near-misses stay literal because the move would shift their hue or
  tint. colors:drift keeps listing them.

Rendered against #1190 (local build, 9 pages): 0 to 2.1% of pixels move on
eight pages and 15.9% on /access, and nothing anywhere moves by more than 6
of 255 levels. The all-in prototype moved up to 60% of a page past that.

* fix(tokens): the chrome and title blues resolve to the XP hex their comments name

colors.css said its values "resolve to period-correct Luna" and never
measured it. They came in with a generated design system on 2026-06-05 and
sat up to dE 0.040 from their hex (--darkshadow vs #716F64) and 0.042 for the
title blues (--blue-95 vs #3D95FF): every chrome colour darker and greyer
than XP, with round-number lightness that read like an estimate.

- Chrome: --hue-chrome 96.85, --chroma-chrome 0.0228, exact lightness and
  chroma per token. One knob still drives all four; each lands within
  dE 0.0008 of ButtonFace, ButtonLight, ButtonShadow and the 3D dark shadow.
- Title blues: --chroma-luna 0.2274 and a per-token hue offset (the ramp
  already used them) put --blue-65, --blue-95, --blue-inactive and --blue-50
  within dE 0.0001 of ActiveTitle, GradientActiveTitle, InactiveTitle and
  Highlight. Every title bar and the selection colour move with this.
- The contract now reads a hex in a token's comment as a claim and holds it
  within dE 0.002. Control: the old values fail it on seven tokens.
- With the tokens on XP, 12 hand-typed XP hex values became copies and are
  swept (#316ac5, #ece9d8, #aca899, #0054e3).
- A var() fallback is now legal for a colour literal, as it already was for
  a font stack. luna's client edge says var(--face,#ece9d8): build.ts mirrors
  it into the homepage, which paints before luna.css defines --face, and a
  bare var() would drop the 6px border the mirror exists to keep. build.ts's
  extractor and its homepage check accept that form.

Rendered (local build, 9 pages): the chrome retune moves 0 to 0.4% of
pixels on 8 pages by at most 5/255; the title blues move about 2% (the title
bars) by up to 28/255.

* fix(test): guard the hex-claim test's parses so typecheck holds its baseline

parseOklch and parseSrgb return null for input they cannot read, and the
test used both results without a check: two TS2531 errors that validate's
typecheck refused against config/ts-baseline.json. Assert both parsed, then
use them.

* fix(tokens): narrow the parsed colours before measuring them

parseOklch and parseSrgb return null on a miss, so typecheck refused the
hex-claim test against the baseline. Assert both parsed, then measure.

* fix(tokens): the chrome and title blues resolve to the XP hex their comments name

colors.css said its values "resolve to period-correct Luna" and never
measured it. They came in with a generated design system on 2026-06-05 and
sat up to dE 0.040 from their hex (--darkshadow vs #716F64) and 0.042 for the
title blues (--blue-95 vs #3D95FF): every chrome colour darker and greyer
than XP, with round-number lightness that read like an estimate.

- Chrome: --hue-chrome 96.85, --chroma-chrome 0.0228, exact lightness and
  chroma per token. One knob still drives all four; each lands within
  dE 0.0008 of ButtonFace, ButtonLight, ButtonShadow and the 3D dark shadow.
- Title blues: --chroma-luna 0.2274 and a per-token hue offset (the ramp
  already used them) put --blue-65, --blue-95, --blue-inactive and --blue-50
  within dE 0.0001 of ActiveTitle, GradientActiveTitle, InactiveTitle and
  Highlight. Every title bar and the selection colour move with this.
- The contract now reads a hex in a token's comment as a claim and holds it
  within dE 0.002. Control: the old values fail it on seven tokens.
- With the tokens on XP, 12 hand-typed XP hex values became copies and are
  swept (#316ac5, #ece9d8, #aca899, #0054e3).
- A var() fallback is now legal for a colour literal, as it already was for
  a font stack. luna's client edge says var(--face,#ece9d8): build.ts mirrors
  it into the homepage, which paints before luna.css defines --face, and a
  bare var() would drop the 6px border the mirror exists to keep. build.ts's
  extractor and its homepage check accept that form.

Rendered (local build, 9 pages): the chrome retune moves 0 to 0.4% of
pixels on 8 pages by at most 5/255; the title blues move about 2% (the title
bars) by up to 28/255.

* fix(tokens): narrow the parsed colours before measuring them

parseOklch and parseSrgb return null on a miss, so typecheck refused the
hex-claim test against the baseline. Assert both parsed, then measure.

---------

Co-authored-by: Aadharsh Pannirselvam <19518661+oddharsh@users.noreply.github.com>
oddharsh added a commit that referenced this pull request Oct 6, 2026
…iles (#1196)

* feat(type): every pt size and font family names a typography token

typography.css has carried a pt scale and three family stacks since the
design system was written. On 2026-10-06 the scale had 23 consumers against
1,072 hand-written sizes in 70 distinct values, and 55 family stacks were
spelled out by hand (31 of them "Courier New",monospace, the mono token with
its fallbacks dropped).

- The scale grows to what the site sets: --text-lg 13pt, --text-lede 11pt,
  --text-2xs 8pt, --text-3xs 7.5pt, --text-4xs 7pt. 8pt alone had 98 uses.
- 989 declarations in the sources rewritten to tokens; generated garage and
  lwe pages regenerated from their specs and generators.
- 121 off-grid declarations snapped to the nearest step, ties down. Most move
  0.2pt or less (8.6 and 8.4 -> 8.5, 8.8 -> 9, 8.2 and 7.8 -> 8). Six move
  0.4-0.5pt: 12.5 -> 12 and 11.5 -> 11 (two each), 6.5 and 6.6 -> 7.
- contract-type-comes-from-the-tokens refuses a pt size up to 14pt or a family
  stack outside var(--font-*). px (pixel-exact chrome, SVG text), relative
  units and display sizes over 14pt stay legal; three rules say @type demo
  (horizon's console caret, the polaroid's handwriting, lwe's CJK avatar).
- The homepage loads luna.css without blocking, so it inlines the five size
  tokens it reads; the contract holds that copy to typography.css.
- cssSources() now reads lwe specs' demoCss, which neither contract saw.
- colors.css's --text-body: var(--ink) is gone. typography.css's --text-body
  (10.5pt) loads after it in luna.css, so the colour alias never applied.

Checked in a browser: no element on 8 sampled pages computes to the 16px
default; /garage/useragent's size histogram moves exactly by the snaps.

* fix(tokens): read hex and rgb() as colours, and sweep the token copies they hid

The token contract read oklch() only, and the site writes most of its colour
in hex: 2,248 hex and 82 rgb() literals on 2026-10-06. Measured against the
tokens by OKLab distance, 87 were a token retyped in sRGB (#f3f6fa for
--row-alt 51 times over, #888 for --ink-faint, #e8eef7 for --surface-desktop).

- colorLiteralsIn() reads oklch(), hex and rgb()/rgba() with one set of
  guards: SVG presentation attributes, and for the sRGB spellings anything
  outside a declaration value, so #fab in a selector or a hex in a comment
  (access's note on why its greys moved) is never a colour.
- tokenCopiesIn() and colors:drift both use it. The report now covers 3,884
  literals and lists 156 colours hand-written in 3+ files with no token.
- 84 copies swept to var(): 55 in pages, stylesheets and Workers, 29 inside
  garage and lwe spec CSS (pageCss/demoCss lines only, never demoJs), with
  every generated page regenerated. Two whole gradients were --grad-raised
  stop for stop (luna's button face, serendipity's) and now say so.

Invisible: every swap is under dE 0.004 of its token.

* fix(tokens): the chrome and title blues resolve to the XP hex their comments name

colors.css said its values "resolve to period-correct Luna" and never
measured it. They came in with a generated design system on 2026-06-05 and
sat up to dE 0.040 from their hex (--darkshadow vs #716F64) and 0.042 for the
title blues (--blue-95 vs #3D95FF): every chrome colour darker and greyer
than XP, with round-number lightness that read like an estimate.

- Chrome: --hue-chrome 96.85, --chroma-chrome 0.0228, exact lightness and
  chroma per token. One knob still drives all four; each lands within
  dE 0.0008 of ButtonFace, ButtonLight, ButtonShadow and the 3D dark shadow.
- Title blues: --chroma-luna 0.2274 and a per-token hue offset (the ramp
  already used them) put --blue-65, --blue-95, --blue-inactive and --blue-50
  within dE 0.0001 of ActiveTitle, GradientActiveTitle, InactiveTitle and
  Highlight. Every title bar and the selection colour move with this.
- The contract now reads a hex in a token's comment as a claim and holds it
  within dE 0.002. Control: the old values fail it on seven tokens.
- With the tokens on XP, 12 hand-typed XP hex values became copies and are
  swept (#316ac5, #ece9d8, #aca899, #0054e3).
- A var() fallback is now legal for a colour literal, as it already was for
  a font stack. luna's client edge says var(--face,#ece9d8): build.ts mirrors
  it into the homepage, which paints before luna.css defines --face, and a
  bare var() would drop the 6px border the mirror exists to keep. build.ts's
  extractor and its homepage check accept that form.

Rendered (local build, 9 pages): the chrome retune moves 0 to 0.4% of
pixels on 8 pages by at most 5/255; the title blues move about 2% (the title
bars) by up to 28/255.

* feat(tokens): snap near-miss colours onto their token only when the hue holds

Decision C from the palette proposal. 1,054 literals sat 0.004 to 0.02 from
a token, and the prototype that snapped all of them turned /whoareyou's
content pane cream. Two causes, both measured:

- 357 of them were white. White is four tokens' value, so the contract never
  calls it a copy, and the prototype read #fff as a near-miss of the warm
  --paper. White and black are never near-misses of one token now.
- A move that changes hue, or puts a tint on a neutral, changes temperature
  even under the just-noticeable difference. Each near-miss is split into its
  lightness, chroma and hue parts, and it snaps only when the hue part is
  under 0.003 and the chroma change under 0.004: greys onto the ink ramp,
  blue-greys onto --surface-desktop and --rule, a lighter --row-alt.

- New --paper-cool, oklch(98% 0.004) at --hue-luna - 13: the cool twin of
  the warm --paper, which the site already wrote as a hand-mixed near-white
  in 18 files. 22 copies of it swept.
- 252 literals in 55 source files now name a token, garage and lwe spec CSS
  included (pageCss/demoCss lines only); every generated page regenerated.
- 400 near-misses stay literal because the move would shift their hue or
  tint. colors:drift keeps listing them.

Rendered against #1190 (local build, 9 pages): 0 to 2.1% of pixels move on
eight pages and 15.9% on /access, and nothing anywhere moves by more than 6
of 255 levels. The all-in prototype moved up to 60% of a page past that.

* fix(tokens): the chrome and title blues resolve to the XP hex their comments name

colors.css said its values "resolve to period-correct Luna" and never
measured it. They came in with a generated design system on 2026-06-05 and
sat up to dE 0.040 from their hex (--darkshadow vs #716F64) and 0.042 for the
title blues (--blue-95 vs #3D95FF): every chrome colour darker and greyer
than XP, with round-number lightness that read like an estimate.

- Chrome: --hue-chrome 96.85, --chroma-chrome 0.0228, exact lightness and
  chroma per token. One knob still drives all four; each lands within
  dE 0.0008 of ButtonFace, ButtonLight, ButtonShadow and the 3D dark shadow.
- Title blues: --chroma-luna 0.2274 and a per-token hue offset (the ramp
  already used them) put --blue-65, --blue-95, --blue-inactive and --blue-50
  within dE 0.0001 of ActiveTitle, GradientActiveTitle, InactiveTitle and
  Highlight. Every title bar and the selection colour move with this.
- The contract now reads a hex in a token's comment as a claim and holds it
  within dE 0.002. Control: the old values fail it on seven tokens.
- With the tokens on XP, 12 hand-typed XP hex values became copies and are
  swept (#316ac5, #ece9d8, #aca899, #0054e3).
- A var() fallback is now legal for a colour literal, as it already was for
  a font stack. luna's client edge says var(--face,#ece9d8): build.ts mirrors
  it into the homepage, which paints before luna.css defines --face, and a
  bare var() would drop the 6px border the mirror exists to keep. build.ts's
  extractor and its homepage check accept that form.

Rendered (local build, 9 pages): the chrome retune moves 0 to 0.4% of
pixels on 8 pages by at most 5/255; the title blues move about 2% (the title
bars) by up to 28/255.

* fix(test): guard the hex-claim test's parses so typecheck holds its baseline

parseOklch and parseSrgb return null for input they cannot read, and the
test used both results without a check: two TS2531 errors that validate's
typecheck refused against config/ts-baseline.json. Assert both parsed, then
use them.

* fix(tokens): narrow the parsed colours before measuring them

parseOklch and parseSrgb return null on a miss, so typecheck refused the
hex-claim test against the baseline. Assert both parsed, then measure.

* fix(tokens): the chrome and title blues resolve to the XP hex their comments name

colors.css said its values "resolve to period-correct Luna" and never
measured it. They came in with a generated design system on 2026-06-05 and
sat up to dE 0.040 from their hex (--darkshadow vs #716F64) and 0.042 for the
title blues (--blue-95 vs #3D95FF): every chrome colour darker and greyer
than XP, with round-number lightness that read like an estimate.

- Chrome: --hue-chrome 96.85, --chroma-chrome 0.0228, exact lightness and
  chroma per token. One knob still drives all four; each lands within
  dE 0.0008 of ButtonFace, ButtonLight, ButtonShadow and the 3D dark shadow.
- Title blues: --chroma-luna 0.2274 and a per-token hue offset (the ramp
  already used them) put --blue-65, --blue-95, --blue-inactive and --blue-50
  within dE 0.0001 of ActiveTitle, GradientActiveTitle, InactiveTitle and
  Highlight. Every title bar and the selection colour move with this.
- The contract now reads a hex in a token's comment as a claim and holds it
  within dE 0.002. Control: the old values fail it on seven tokens.
- With the tokens on XP, 12 hand-typed XP hex values became copies and are
  swept (#316ac5, #ece9d8, #aca899, #0054e3).
- A var() fallback is now legal for a colour literal, as it already was for
  a font stack. luna's client edge says var(--face,#ece9d8): build.ts mirrors
  it into the homepage, which paints before luna.css defines --face, and a
  bare var() would drop the 6px border the mirror exists to keep. build.ts's
  extractor and its homepage check accept that form.

Rendered (local build, 9 pages): the chrome retune moves 0 to 0.4% of
pixels on 8 pages by at most 5/255; the title blues move about 2% (the title
bars) by up to 28/255.

* fix(tokens): narrow the parsed colours before measuring them

parseOklch and parseSrgb return null on a miss, so typecheck refused the
hex-claim test against the baseline. Assert both parsed, then measure.

* feat(tokens): name the 64 colours the site already shared across 5+ files

The palette proposal's alternative to hue ramps: name what the site already
uses rather than snapping it onto a scale. After #1193, 73 colours were still
hand-written in 5+ files. Each is a cluster of near-duplicates within
dE 0.01, and the token's value is the cluster's most-used colour, so those
uses move by nothing (worst dE 0.0001).

- 64 tokens in a SHARED PALETTE block in colors.css (and luna.css's copy),
  named family + OKLCH lightness: --grey-*, --mist-*, --slate-*, --luna-*
  (the window-frame blues), --violet-96, --red-*, --amber-*, --green-*.
  --slate-84 is a slate at L 84%; two same-lightness pairs take a -b suffix.
  Hues hang off the existing knobs, so a knob turn retunes these too.
- Nine clusters within dE 0.01 of an existing token are not named: a second
  name for nearly the same colour would make the choice ambiguous.
- 687 copies swept to var(), 80 near-misses snapped under #1193's hue-aware
  rule, 103 literals in garage and lwe spec CSS, two in the garage generator's
  scaffold, and lwe's encoding concept's accentSoft now names --mist-96.
  Every generated page regenerated.

Rendered against #1193 (local build, 9 pages): 0.5 to 4.8% of pixels move,
none by more than 5 of 255 levels.

* feat(tokens): merge the near-twin greys, and --red-46 into --danger-deep

The owner's call on the merges #1196 listed:

- --grey-30 into --grey-28, --grey-33 into --grey-35, --grey-72 into
  --grey-70. Each pair sat 0.02 apart, the just-noticeable difference; the
  more-used member of each pair stays, so the fewest uses move.
- --red-46 into --danger-deep. --red-46 was exactly #AA0000, the red the
  site has written by hand since the initial import; --danger-deep arrived
  with the generated design system as #AA0018, a bluer approximation of it.
  The name stays and takes the period value: --danger-deep's 2 uses move
  dE 0.014, --red-46's 13 do not move, and its comment's #AA0000 is now held
  by the hex-claim contract.

18 files repointed, specs included; every generated page regenerated.

* fix(email): keep mail colours literal; a token in an email paints nothing

#1183 swept eight colours in two email templates into var(): four #888s in
the coffee-booking mail (cal/src/email.ts) and the webmention moderation
mail's #888s and #555 (src/worker/webmention.ts) became var(--ink-faint) and
var(--ink-quiet). No mail client loads luna.css and many ignore var()
outright, so since #1183 deployed those borders, notes and dates have
rendered in the client's default colour.

The cause was the shared walk: cssSources() read every Worker source as page
CSS that links luna.css. Email HTML does not.

- Both files are back to their pre-#1183 text (it was their only change).
- EMAIL_TEMPLATES lists them, and cssSources() skips them, so neither the
  colour nor the type contract asks them to name a token again.
- A contract test holds both directions: no var() in an email template, and
  every file that calls resendSend is listed. Control: main's current
  email.ts fails it.

---------

Co-authored-by: Aadharsh Pannirselvam <19518661+oddharsh@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: docs Runbooks and repository prose area: infra Declared Cloudflare state, wrangler config, pins area: photos The photo pipeline and everything it emits area: tools Developer tooling and the contract suite type: feat New capability or surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant