diff --git a/docs/design-system/HANDOVER-2026-08-07.md b/docs/design-system/HANDOVER-2026-08-07.md index d8f1c35cc1..c2c9938ec1 100644 --- a/docs/design-system/HANDOVER-2026-08-07.md +++ b/docs/design-system/HANDOVER-2026-08-07.md @@ -19,7 +19,9 @@ full session to establish. ## 1 · Measured state -All figures measured on `origin/main` at handover, not recalled. +All figures measured on `origin/main` at handover, not recalled. **Re-measure before acting** +— they drift. The staleness figure below was 111 commits when first written and 129 two days +later; quote your own measurement, never this one. | Metric | Value | | ------------------------------------------ | ------------------------------------------------ | @@ -47,12 +49,12 @@ npm run design-system:adoption:update && npm run check:design-system-contract ## 2 · What landed on 7 August 2026 -| PR | Commit | What | -| ------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -| [#1655](https://github.com/BigSimmo/Database/pull/1655) | `cc349d130` | Gate 3's false `--focus` evidence, GATES §1's false "type-step unenforced" note, three stale §0.4 rows, ToggleSwitch knob onto `transform` | -| [#1658](https://github.com/BigSimmo/Database/pull/1658) | `d9221389c` | `AnswerCard` adopted on the live answer surface; `#207`-vs-`#227` resolved. Adoption 27 → 29 | -| [#1663](https://github.com/BigSimmo/Database/pull/1663) | `82b6f5a4c` | Five named tracking tokens + `arbitraryTracking` contract ratchet | -| [#1669](https://github.com/BigSimmo/Database/pull/1669) | open at handover | 68 tracking sites across 40 files migrated; ratchet baseline 68 → **0** | +| PR | Commit | What | +| ------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| [#1655](https://github.com/BigSimmo/Database/pull/1655) | `cc349d130` | Gate 3's false `--focus` evidence, GATES §1's false "type-step unenforced" note, three stale §0.4 rows, ToggleSwitch knob onto `transform` | +| [#1658](https://github.com/BigSimmo/Database/pull/1658) | `d9221389c` | `AnswerCard` adopted on the live answer surface; `#207`-vs-`#227` resolved. Adoption 27 → 29 | +| [#1663](https://github.com/BigSimmo/Database/pull/1663) | `82b6f5a4c` | Five named tracking tokens + `arbitraryTracking` contract ratchet | +| [#1669](https://github.com/BigSimmo/Database/pull/1669) | `b557a26b8` | 68 tracking sites across 40 files migrated; ratchet baseline 68 → **0** | ### The clinical decision recorded in #1658 @@ -110,11 +112,42 @@ measurement and cost real time. ### Track A — finish the kit **A1 · `cn()` + tailwind-merge (`#218`).** The keystone. Blocks Chip/metadataPill -convergence and any reliable size override; `cn()` is plain concat today and two source -sites already carry workaround comments. **Its own PR** — it adds a dependency -(`operationalRisk: true`) and changes class resolution across ~200 importing files, so it -must not be bundled or landed alongside a visual change whose Chromium job you still need to -read. +convergence and any reliable size override. **Its own PR** — it adds a dependency +(`operationalRisk: true`), so it must not be bundled or landed alongside a visual change +whose Chromium job you still need to read. + +Blast radius, measured: `cn(` is called **1 888 times across 188 source files**; **210 files** +reference `ui-primitives`. Five comments across four files already document working around the +concat behaviour — `page-header.tsx:150` (names `#218`), `document-search-results.tsx:368` and +`:636`, `master-search-header.tsx:2085`, `mode-home-template.tsx:106`. Note the last one does +not merely comment: it **strips stray `justify-*` tokens** from incoming `className`, so +twMerge would make that workaround redundant or double-handle it. Grep for "plain join" and +"concatenates" as well as "tailwind-merge" — a literal grep for the hyphenated term finds only +three of the five. + +**The deliverable is the `extendTailwindMerge` config, not the `cn()` body.** This is the part +that will bite. Stock tailwind-merge classifies an unknown `text-` as a **text colour**, and +this repo's `@theme` defines scales it has never seen: `text-2xs`, `text-3xs`, the five +`tracking-*` roles, `min-h-tap` / `h-tap` / `w-tap`, `size-icon-*`, thirteen `shadow-*`, custom +`radius-*` and `leading-*`. So `cn(eyebrowText)` — `text-2xs … text-[color:var(--text-muted)]` +— would have one of those two silently deleted, shipping a size or colour regression across the +kit with **no type or lint signal**. Declare every custom group in the config, comment it +against its `globals.css` source of truth, and pin it with tests that prove custom groups do +not collide while real conflicts still resolve last-wins. + +Requires **tailwind-merge v3.x** — v2 targets Tailwind 3, and this repo is on `tailwindcss ^4.3.1`. +Neither `tailwind-merge` nor `clsx` is currently a dependency. + +Two hazard classes to audit before switching, in this order: + +1. **Order-reliance** — anywhere a later class currently loses to an earlier one, twMerge flips + it. `page-header.tsx` documents exactly this shape (`hidden` + `sm:grid` + `grid`) and dodged + it with `max-sm:hidden`; other sites may not have dodged. Do **not** revert those dodges in + this PR — that is a visual change and belongs elsewhere. +2. **Custom-token misclassification** — the landmine above. + +Baseline the three known-failing Windows suites on the untouched base **before** touching +`cn()`. Without a before-shot, "unchanged, not mine" is an assertion rather than proof. **A2 · `--shadow-focus`.** Replace the composer's companion ring with the sanctioned `outline` / `--focus` treatment used everywhere else, then delete the token (both theme @@ -267,9 +300,22 @@ check so a rewrite could not silently move an unrelated number. > and the component DOM suites in §8. Expect three pre-existing Windows test failures listed in > §7 — confirm they are unchanged rather than treating them as yours. > +> **Pre-authorised, do not stop to ask:** `git fetch` (read-only, and the local `main` ref is +> reliably stale so you need it), cutting a worktree off latest `origin/main`, and +> `npm install tailwind-merge` as a single package. These are routine and inside the dependency +> change already approved. Still ask before: OpenAI or Supabase calls, hosted-CI mutations, +> `npm ci`, deploys, or anything touching production data. +> > Do not commit visual baselines, do not merge any `codex/v2-*` branch, do not build the > outlined P1/P2 components, and do not write a lint duplicating `check:type-scale`. +**Why that pre-authorisation paragraph exists.** The first session handed this file stalled +before step 0, asking whether `git fetch` fell inside the provider-confirmation boundary. It +was right to read the earlier wording that way — "do not touch … any provider-backed workflow +without asking" plainly covers a fetch. The boundary exists for spend, mutation and production +risk, none of which a read-only fetch carries. Name the routine operations explicitly, or the +next session stalls on the same gate. + Register the Track A and Track B items in the durable ledger with `/issues capture` rather than hand-writing rows into [`docs/outstanding-issues.md`](../outstanding-issues.md) — ids are allocated read-modify-write and hand-edits have collided before (`#156`).