commit 233e68ee3f2e335082ea1f1397e3488c20c19a96
parent bb864680ab5cd306d1f1d6d4780ad650f2d6790c
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Mon, 28 Sep 2026 03:45:50 -0400
plans: O2b follow-ups — the hub's added archives fitted, clip paths in the single-colour rule, the no-data spec, R2's nits; FACTS on perBaseColor's contract; brand-and-themes' token count
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
3 files changed, 102 insertions(+), 3 deletions(-)
diff --git a/plans/FACTS.md b/plans/FACTS.md
@@ -6752,7 +6752,11 @@ S4, as shipped"; `release-10.md` "Slice L2 / L1, as shipped". Every anchor below
`var(--swatch-<id>)` (per base) from the summary's `accentId`, used only when `hub-sites.json`'s
hex (on-dark only) is absent or equal to the summary's; the homepage's `ArchiveCards` use the
same helper. A CUSTOM hex is fitted per base (release 11, slice O2): `perBaseColor(resolveAccent(hex))`,
- one `rgb(calc(…))` over tokens.css's one-hot `--base-light|sepia|dark`. With no accent the
+ one `rgb(calc(…))` over tokens.css's one-hot `--base-light|sepia|dark`. That value is CSS ONLY —
+ never parse or compare it as a hex; `perBaseColor` throws on anything but a `#rrggbb` per base, and a
+ fourth base must add its own flag to tokens.css (`themeTokens.test` holds one 1 per base over
+ `BASE_GROUND_IDS`). A visitor-ADDED hub archive's published hex goes through the same fit
+ (`fittedHex`, in `useHubSites`; release 11 O2b), and a non-hex accent is dropped. With no accent the
fallback is the site's CHART colour, `siteChartColors(sites)`: the `--chart-N` of its accent's hue
family (blue 1, green 2, violet 3, brass 4, sakura 5, vermilion 6 — `--chart-6` is a rust since
release 11), else `seriesColor(i)` when free (the first SIX are `var(--chart-1..6)`), else the
diff --git a/plans/brand-and-themes.md b/plans/brand-and-themes.md
@@ -113,7 +113,9 @@ ground and with white ink. A unit test enforces it.
### Bases
Each base declares all 48 colour tokens listed in `homepage/e2e/theme.spec.ts:63-112`, plus
-`color-scheme`.
+`color-scheme`. (2026-09-28: 50 now — `REQUIRED_TOKENS` in `common/components/themeConfig.ts`, which
+the spec reads; `--chart-6` came in release 11, slice O2. Each base also declares the non-colour
+flags `--base-light|sepia|dark`.)
| Base | Source | Values |
|---|---|---|
diff --git a/plans/release-11.md b/plans/release-11.md
@@ -1030,7 +1030,7 @@ surface | page ground> --pairs all|adjacent`. Log: `o2-validate.log`.
- no sixth hue clears both `--chart-1..5` and gone ≥ 15 on every base; the gone-constrained
search's best, an electric violet, fails the palette's own normal floor (14.4 on light and
sepia; `o2-chart6-hue-gone.log`);
- - on the homepage, gone is the FamilyStats figure and the rail's badge.
+ - on the homepage, gone shows only as the FamilyStats figure (`RecentAdditions` would badge it, but is rendered nowhere).
**Forced colours, as rendered** (`o2-shots.mjs`, `o2-shots.log`, `o2-forced.png`).
- **Normal modes are unchanged.** Each mark was shot as built and again with the two new classes
@@ -1111,6 +1111,99 @@ with the new tests kept:
and the hub's fitted hex), the homepage (all four), and the editor on its next restart (the
sidebar outline).
+### Follow-ups O2b (2026-09-28)
+
+After O2's review (`o2-review.md`, SHIP) and the merge (`main` `139a648e`: O4, O3, O6-A, O1, O2), one
+small round on the same branch and worktree. `main` merged first (a fast-forward).
+
+**What changed**
+- **The hub's visitor-added archives are fitted per base** (O2's found-and-left, now safe: O1 is
+ merged).
+ - `useHubSites` maps every external archive's accent through `fittedHex`, which is
+ `perBaseColor(resolveAccent(hex))` (`common/lib/siteColor.ts`; `siteColor` uses it too).
+ - So the card stripe, the scope chip's dot, the search result edge and the channel group all get
+ the fitted value from the one place.
+ - A value that is not a `#rrggbb` is dropped, so it never reaches a style. Before, a remote
+ `/site.json` could put any string there. The card then falls back to `var(--brand)`, as with no
+ accent.
+- **R2's low 2, recorded here:** O2 also changed the hub's DEGRADED path.
+ - This is an official archive with a named accent whose `hub-summary.json` is missing, or whose own
+ hex disagrees with it.
+ - It used to paint the on-dark hex on every base, and now paints that hex fitted per base (for
+ example Brass `#e3b15c` → `#8a6c38` on light, against the swatch `#95661a`).
+ - The export changelog now says so.
+- **`normalizeSocialSvg` passes over a `<clipPath>` exactly like a `<mask>`** (O1 review, re-read
+ low).
+ - It handles the block and the self-closing form, the self-closing one first.
+ - So Figma's usual one-colour export counts as ONE colour and is themed: a black path in a group
+ clipped by `<clipPath><rect fill="white"/></clipPath>`.
+ - x.com and Kiwi Farms are byte-for-byte as before (their tests pin the whole output), and the
+ rule is still idempotent (the Figma icon is in the idempotence loop).
+- **R2's nits:**
+ - `tokens.css`: the chart-6 CVD pairs are "deutan", as the validator prints.
+ - `homepage/app/lib/summary.ts`: the comment names the synthetic summary.
+ - `ArchiveGrowthChart.tsx`: the today-order numbers are "today's mapping — release 10's slice MC,
+ re-run in release 11".
+ - This record: gone shows only as `FamilyStats`' figure (`RecentAdditions` is rendered nowhere).
+ - `brand-and-themes.md`: 50 colour tokens (a dated note).
+ - `perBaseColor` throws a `RangeError` on anything but a `#rrggbb` per base, rather than paint
+ `rgb(NaN …)`.
+ - FACTS: `perBaseColor`'s value is CSS only (never parse or compare it as a hex); a fourth base must
+ add its flag; the added archives use the same fit.
+- **The no-data pages are specced again** (R2's low 4). `homepage/e2e/no-data.spec.ts` runs serially.
+ - It renames `e2e/.e2e-summary.json` to `.e2e-summary.json.aside`, which is gitignored by the same
+ pattern, and restores it in `finally`.
+ - It asserts `/` shows "Every word a channel said, searchable to the second." with no growth
+ chart, no Official Instances and no build date.
+ - It asserts `/stats/` shows "This build shipped without dashboard data" and no chart.
+ - It then checks the next `/stats/` draws the fixture again.
+- **Changelogs:**
+ - export `[Unreleased]` gains one bullet: the added archives and the degraded path, fitted per
+ base.
+ - O1's single-colour bullet now says clip paths are left alone and do not count (the Figma case).
+ - `homepage/CHANGELOG.md` gains the single-colour social icon (the homepage footer's links are the
+ same normalized `socialLinks`), on the parent's ruling on O1's question.
+
+| sha | what |
+|---|---|
+| `c17ead28` | `common:` `normalizeSocialSvg` passes over `<clipPath>` (block + self-closing); the Figma-shape test |
+| `ee0a252e` | `hub:` the added archives' accent through `fittedHex` (`useHubSites`); `perBaseColor`'s input check; `ArchiveShelf` comments; unit tests; the hub e2e |
+| `ac8c4d2b` | `homepage(e2e):` `no-data.spec.ts` |
+| `36e4fabd` | `comments:` the three code-comment nits (`tokens.css`, `summary.ts`, `ArchiveGrowthChart.tsx`) |
+| `36fc74f8` | `changelogs:` export (the fitted hub archives; clip paths in O1's bullet), homepage (the single-colour icon) |
+| _this_ | `plans:` this section; the record's gone line; FACTS; `brand-and-themes.md`'s token count |
+
+**Gates** (logs `o2b-*.log`):
+- **tsc** clean before the code commits (89 s, `o2b-tsc1.log`).
+- **common 2,110/2,110:** `main` `139a648e`'s count + 3 (the Figma test, `fittedHex`, the input
+ check).
+- **e2e** (queued behind nothing; nothing failed, so no re-runs):
+ - `e2e:hub` full **33 passed** (1.2 min; 32 at O1 + the added-archive test);
+ - export `site-branding` **7 passed** (12 s);
+ - homepage full **31 passed, 0 skipped** (44 s; 30 + `no-data.spec`), from this worktree with no
+ `homepage/public` data;
+ - after the homepage run the fixture file is back in place and no `.aside` is left.
+- **The primary's `export/public`** is byte-identical before and after (392 entries, 380 files).
+
+**They bite:**
+- **Figma:** against the previous `settingsSchema.ts`, the Figma test fails with the fills
+ `['none', 'black', 'white']`: two colours, so nothing is themed. The other 13 pass
+ (`o2b-bite-svg.log`).
+- **The added archive:** with `useHubSites`' `.map(fittedHex)` removed, the hub test fails on light,
+ expecting `rgb(132, 105, 116)` and receiving `rgb(244, 194, 215)` for both the stripe and the dot
+ (`o2b-e2e-bite-hub.log`).
+- **The input check:** without it, `perBaseColor`'s throw test fails (1 of 15;
+ `o2b-bite-unit-check.log`). Against `main`'s `siteColor.ts` the test file does not load at all
+ (no `fittedHex`).
+- **No data:** with the loader's old bug (a zero-filled summary when there is none),
+ `no-data.spec` fails: `/stats/` never says "This build shipped without dashboard data"
+ (`o2b-e2e-bite-nodata.log`).
+
+**Found and left**
+- **A dev-console warning, not O2b's:** the homepage run logs `[browser] Received NaN for the width
+ attribute` during `stats.spec`'s Customize test (ranked / small multiples). It is in O2's runs too,
+ so it predates O2b.
+
## Rollout
Nothing is rolled out tonight. The morning runbook lists what is owed: the :3001 editor restart,