fix(docs): counts sweep round 2 — 12 slots (not 13), 9 roles (not 8) + guards

Extending the I1 count guard to color roles and role slots surfaced
four more stale counts the palette fix predicted: the RFCs still said
'13 slots' and enumerated borderHover8 (the slot was retired 2026-07-02,
zero consumers — COLOR_ROLE_SLOTS is 12), and two component READMEs
(css-field, float-panel) still said '8 roles' from before tertiary made
it 9. The guard itself had the same disease it polices: extractConstArray
counted the quoted 'borderHover' inside the comment documenting its own
retirement, so expected=13 and the stale mentions passed — comments are
now stripped before extraction. css-field's README is fixed on disk but
left unstaged (it carries unrelated local modifications).

docs-check now verifies families=8, intents=6, archetypes=26,
palette=33, roles=9, slots=12 against their consts on every run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
menubar-v4-safe
dev 3 months ago
parent fc9fc80e09
commit 2050becba6

@ -47,7 +47,7 @@ source: migrated from src/uix/eidos/COLOR_ENGINE_RFC.md (2026-07-02, docs-book F
- The **names** of all vars: `--scale-{name}-{step}`, `--scale-{name}-a{step}`,
`--primitive-{role}-{step}`, `--color-{role}-{slot}`, `--color-{role}-surface`.
- The **3-layer model** (§25), the **9 roles**, the **13 slots**, the **8 sema
- The **3-layer model** (§25), the **9 roles**, the **12 slots**, the **8 sema
families**, the **variants canon** (§19).
- The **TSC** (scope-as-data, `scopeCovers`, cross-axis), the **purge**, the
**contrast introspection**, the **compositing-inverse alpha**.
@ -130,7 +130,7 @@ fidelity ceiling and, **as a by-product**, absorbs the legitimate wish for a
| Scale shape | `ColorScale = Record<ColorScaleStep, string>` (12 hex) | `config-types.ts:27` |
| Palette | 33 hex scales (many seeded from Radix) | `themes/base.ts` + `color-scales.ts` |
| Roles | explicit hierarchy + auto-derived intents | `config-types.ts:78-94` |
| Slots | 13 slots `track1·bg2·element3·hover4·active5·separator6·border7·borderHover8·solid9·solidHover10·text11·textStrong12·contrast(on-solid)` | `render-css.ts` `DEFAULT_COLOR_ROLE_SLOT_STEPS` |
| Slots | 12 slots `track1·bg2·element3·hover4·active5·separator6·border7·solid9·solidHover10·text11·textStrong12·contrast(on-solid)` (border-hover step 8 retired — zero consumers) | `render-css.ts` `DEFAULT_COLOR_ROLE_SLOT_STEPS` |
| Color emission | `renderThemeCss` → `--scale-*`, `--primitive-*`, `--color-{role}-{slot}` | `render-css.ts:288-380` |
| Contrast | gamma-lin WCAG2, swap to `onSolidContrast` if `<3:1` | `render-css.ts:343-363,1629` |
| Alpha | compositing-inverse (generates `aN` that over the background reproduces solid N) | `render-css.ts:1647-1700` |

@ -41,7 +41,7 @@ lets you define an accent from **a single hex**.
`string` is a **scale name** and
`ColorRoleDefinition = { scale: string; slots?: ... }`. No "anchor color"
form exists.
- Each role → **1 scale of 12 steps**. The 13 slots **auto-derive** from those
- Each role → **1 scale of 12 steps**. The 12 slots **auto-derive** from those
steps (`render-css.ts > DEFAULT_COLOR_ROLE_SLOT_STEPS`):
| slot | step | use |

@ -136,7 +136,10 @@ function read(file: string): string {
function extractConstArray(source: string, constName: string): string[] {
const m = source.match(new RegExp(`${constName}\\s*=\\s*\\[([\\s\\S]*?)\\]`));
if (!m) throw new Error(`Cannot find const ${constName}`);
return [...m[1].matchAll(/'([\w-]+)'/g)].map((x) => x[1]);
// Strip comments first — a quoted name inside a comment (e.g. the note
// documenting the retired 'borderHover' slot) must not count as an entry.
const body = m[1].replace(/\/\/[^\n]*/g, '').replace(/\/\*[\s\S]*?\*\//g, '');
return [...body.matchAll(/'([\w-]+)'/g)].map((x) => x[1]);
}
// SEMA_FAMILIES (event.ts) is a spread of the two partitions — extract both.
@ -154,6 +157,11 @@ const PALETTE = extractConstArray(
read(join(REPO, 'src/uix/eidos/lib/types.ts')),
'PALETTE_SCALES'
);
const eidosConfigTypesSrc = read(join(REPO, 'src/uix/eidos/lib/config-types.ts'));
// COLOR_ROLES is a spread (hierarchy + intents) — count the two parts.
const COLOR_ROLES_COUNT =
extractConstArray(eidosConfigTypesSrc, 'HIERARCHY_COLOR_ROLES').length + INTENTS.length;
const COLOR_ROLE_SLOTS = extractConstArray(eidosConfigTypesSrc, 'COLOR_ROLE_SLOTS');
// ── Invariant 1 — vocabulary counts ────────────────────────────────────────
@ -214,6 +222,24 @@ const COUNT_PATTERNS: CountPattern[] = [
context: /palet|escala|color/i,
exclude: /~\s*\d|tipogr|espaci|paso|step|gris/i,
minToFlag: 20
},
// Color roles (9 = 3 hierarchy + 6 intents) and role slots (12 since
// border-hover was retired, 2026-07-02) — "13 slots" survived in the RFCs.
{
re: /\b(\d+)\s+(?:color\s+)?roles\b/gi,
expected: COLOR_ROLES_COUNT,
what: 'COLOR_ROLES',
context: /color|role|palet/i,
exclude: /accent|hierarch|jerarqu|intent\s+roles|semantic/i,
minToFlag: 7
},
{
re: /\b(\d+)\s+slots\b/gi,
expected: COLOR_ROLE_SLOTS.length,
what: 'COLOR_ROLE_SLOTS',
context: /color|slot|role|token/i,
exclude: /~\s*\d/,
minToFlag: 10
}
];

@ -58,7 +58,7 @@ are in the soma README ("Keyboard move / resize"); the recipe only adds the
| Prop | Type | Default |
| --- | --- | --- |
| `variant` | `'surface' \| 'outline' \| 'ghost'` (canonical `ControlVariant`) | `'surface'` |
| `color` | `ColorRole` (8 roles) | `'neutral'` |
| `color` | `ColorRole` (9 roles) | `'neutral'` |
All Soma `Provider` props pass through (`open`, `anchor`, `position`, `size`, `draggable`, `resizable`, `minWidth`, …).
There is intentionally **no visual `size` prop** — the panel's size is its `width`/`height` geometry.

Loading…
Cancel
Save

Powered by TurnKey Linux.