# PLAN — Coherencia del catálogo de componentes (fase 1: debilidades)
> **Kickoff para sesión nueva**: *"Lee docs/process/PLAN-component-coherence.md
> y continúa la tanda que toque."* Decisión de usuario (2026-07-02): primero
> resolver las debilidades medidas del sistema; la **web de información y de
> componentes** (ficha canónica + demos v3 + docs site) es la FASE SIGUIENTE —
> por eso las reglas D-* (demos) quedan explícitamente FUERA de esta fase.
## Diagnóstico (auditoría 2026-07-02)
`npm run component:audit` : **130 componentes → 75 PASS · 50 NEEDS-WORK · 5
BROKEN** (`cascade` · `gradient-builder` · `menu-dial` · `motion` · `qr-code` ).
Por dimensión:
| Dimensión | Estado medido |
|---|---|
| Ejes transversales | Paleta-31 (`paletteScaleDecls`) en **7** recipes; size-bundle (`--size-*`) en **1** (pilot toggle); `data-variant` en 55 CSS |
| Estados (recipe) | `:focus-visible` falta en **11** (error) · `data-invalid` en 10 · `data-disabled` en 6 · `data-readonly` en 15 (warn) |
| Tokens | **17** recipes con tipografía literal (R-2.7) |
| Sema | 82 morfos con eventos → solo **41** declaran `expression:` (13 pack · 13 family-default · 1 delegated parseados); `persistence:` en 13; `a11ySemantic` en 9 |
| Motion | 15/15 recipes sin `@keyframes` locales ✓; firma de evento (CSS `data-event` ) en **10** componentes; prop `motion` en 18 |
| A11y ancla | **33** interactivos sin URL APG (A-1.4, warn) |
| Docs por componente | **28** sin README (E-2.3); F-1.x (Baseline/Comparativa/Decisiones/Gaps) faltan en ~12– 18 más |
| Demos (FUERA de fase) | 4 tab-union viejo · 7 sin snippet · 8 sin trace · 12 ▶ play sin wire · 7 chip-parity |
## Reglas de trabajo
- Sin agentes/workflows; responder en castellano, código/docs en inglés.
- NUNCA tocar `words/` , `palabras/` , `chronos/` , `media-player` (foráneo WIP).
- Una tanda = cambios + verificación (`component:audit --only` por componente
tocado + `npm run check` scope) + commit. `git reset -q` antes de add.
- Sweeps: UN componente primero, verificar, luego el resto (no-cascade rule).
- Cada fix sistémico lleva su guard (regla nueva en audit o generador).
## Tandas
| Tanda | Contenido | Estado |
|---|---|---|
fix(uix): C1 — zero BROKEN components; documented-exception valve in the audit
The 5 BROKEN components (cascade, gradient-builder, menu-dial, motion,
qr-code) are BROKEN no more: cascade/motion/menu-dial now PASS,
gradient-builder/qr-code drop to NEEDS-WORK with only demo-phase (D-*)
and C8 items left.
Framework-level piece: component-audit gains the documented-exception
valve the checklist already used for A-2.3/R-1.7 — a greppable
'R-x.y exception: reason' line in the component README turns the rule
into a PASS that reports the reason. Wired for R-1.1, R-1.2, R-1.5 and
E-2.2; the checklist rows say the same. This separates deliberate
design (cascade and motion deliberately ship NO recipe — they ride the
foundation stagger + state presets; menu-dial's focus/disabled states
live in the composed Fab/Button recipes) from plain omission, which
stays an error.
Mechanical fixes: texts.label + langs entries for cascade/motion (new
files, registered) and gradient-builder (label added to its existing
entry); menu-dial's missing default export. README contract sections
(Baseline/Comparativa/Decisiones/Gaps/Passive justification + Audit
exceptions) added to cascade, motion, menu-dial and qr-code — mostly
re-heading content those docs already argued; comparativas grounded in
M3 speed dial/MUI SpeedDial/PrimeVue, Framer Motion/AnimatePresence/
Svelte transitions, ark-ui/qr-code-styling per component.
Verified: component:audit 130 -> 78 PASS / 52 NEEDS-WORK / 0 BROKEN;
npm run check at the 61-error pre-existing baseline (0 own).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **C0** | **Auditoría de conteos** (hallazgo usuario: "31 escalas" era 33 — UI+docs): guard I1 extendido a palette=33 · roles=9 · slots=12 (extracción sin comentarios); harness PALETTE_GROUPS +fuchsia+steel con assert de completitud; 14 menciones corregidas. **Pendiente** : misma medicina para steps=12 · planos depth=5 · sizes · weights · estilos tipográficos · packs | **HECHA (núcleo) 2026-07-02** |
| **C1** | **BROKEN mecánicos → 0 BROKEN** : válvula `R-x.y exception:` en audit (R-1.1/R-1.2/R-1.5/E-2.2 + filas checklist); cascade/motion/gradient-builder `texts.label` +langs; menu-dial default export; READMEs contrato (cascade·motion·menu-dial·qr-code: Baseline/Comparativa/Decisiones/Gaps/Passive+excepciones). cascade·motion·menu-dial → PASS; gradient-builder·qr-code → NEEDS-WORK (resto = D-* fase demos + C8) | **HECHA 2026-07-02** |
| **C2** | **Estados error-severity** . ** (a) R-1.5 HECHA 2026-07-02**: el audit ahora reconoce las 4 evidencias sancionadas (`:focus-visible` · `:focus-within` · `:has(:focus)` · `[data-focused]` canónico) — añadir rings por recipe habría sido el anti-patrón "double border" (archetypes.css:164 ya da ring universal por arquetipo); 6 excepciones citadas (css-field/number-field → spin-field compartido; date-picker/dialog → foundation+content-exclusion; metrics/timeline → sin parte enfocable); clipboard+announce esperan su README (C8). ** (b) R-1.2/1.3/1.4 HECHAS 2026-07-03**: válvula cableada también en R-1.3/R-1.4; fixes REALES verificados en navegador (switch/toggle/rating-group invalid=threat-element como checkbox·pin-input; toggle+pin-input readonly; spin-field readonly NUEVO en la capa compartida; ntp disabled); excepciones citadas (spin-field para css/number-field; dialog provider virtual; color-picker→color-field; date-range-field overlay de attrs; time-picker→time-field). ntp conserva R-1.3/R-1.4 warn para su pasada C8. media-player NO tocado (foráneo) | **HECHA** |
fix(uix): C3 — literal typography swept across 16 recipes (R-2.7 clean)
Two classes. Real fixes: 8 numeric font-weights tokenized to
var(--font-weight-medium/semibold/regular) in command,
date-range-picker, link-preview, listbox, menubar, textarea,
time-range-picker x2 — same rendered weight, but the foundation now
propagates (verified in a live browser: the token resolves to 500).
Honest annotations: the proportional/identity literals get their
/* literal: <reason> */ valve instead of a fake token — avatar
initials/badge scale with the avatar diameter (physically
proportional), the calc(1em - (md - sm)) family is the Field
label-one-step-down doctrine with a token-derived delta, 1em is
context identity (fab glyph, password toggle), the x0.85 captions are
proportional to their field token, and combobox's -1px is an optical
adjustment on a token-derived size. component:audit R-2.7: 16/16
clean; npm run check at the 61-error baseline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **C3** | **R-2.7 tipografía literal HECHA 2026-07-03** — 16 recipes: 8 font-weights → `var(--font-weight-*)` (verificado resolve=500 en navegador); ~13 proporcionales/identidad anotados `/* literal: */` con razón (avatar ∝ diámetro; `calc(1em − (md− sm))` = label one-step-down con delta token-derived; `1em` identidad de contexto; captions × 0.85; optical − 1px) | **HECHA** |
| **C4** | **A-1.4 APG HECHA 2026-07-03** — 20 morfos con patrón real (pickers/command/search→combobox · date-field→spinbutton espejo de time-field · rating→radio · nav-menu→disclosure · splitter→windowsplitter · tag-group/tags-input/virtual-grid→grid · file-upload/clipboard→button · announce→alert · form→landmark · image-adjustments→slider · table→table); válvula A-1.4 + notas en 5 READMEs (cropper·pagination·stepper·timeline·image-picker — sin patrón APG real). Restan 4 esperados: card/drag-drop/virtual-list (nota aterriza con su README en C8) + media-player (foráneo) | **HECHA** |
| **C5** | **Sema `expression:` HECHA 2026-07-03** — los 30 morfos eventful sin declaración TODOS tienen pack en `sema/components/` → `expression: 'pack'` (clasificación sin ambigüedad; D.4). `morfo:vocabulary` limpio (solo warn naming de media-player, foráneo). `persistence` /`a11ySemantic` adicionales NO añadidos de oficio — la tabla D.9 es referencia y los 6 consumidores reales ya declaran; ampliar solo con caso real | **HECHA** |
| **C6** | **Paleta universal HECHA 2026-07-03** — `universalPaletteDecls` en el generador (`normalizeRecipeTokens`): `palette-{slot}` = vocabulario reservado → cascade de PALETTE_SCALES completo automático (declaraciones de autor ganan; solo se añaden escalas ausentes). Spreads manuales de button retirados (base.ts); button regenera byte-idéntico; **toggle se universalizó solo** (+330 líneas generadas — ya exponía tokens palette-*). Lint: valores de escala en `data-color` = eidos-only sancionado (la enum del morfo sigue siendo los roles). Guard: test en recipe-css-contract fija la ÚLTIMA escala de la const. Verificado en navegador: toggle color=teal/steel resuelven | **HECHA** |
| **C7** | **Size-bundle sweep HECHA 2026-07-03** — 366 refs de coordenada cruda (`--control-height-{k}` · `--font-size-{k}` · `--icon-size-{k}` ) → coordenada del bundle (`--size-{k}-{coord}`) en base.ts; 34 recipes consumen el bundle (era 1, pilot toggle), 0 crudos restantes. El bundle = alias puro → CSS generado idéntico en VALOR computado (verificado en navegador: cadena `--accordion-trigger-min-height-md` = `--size-md-control-height` = `--control-height-md` = `calc(36px*1*1)` ). Guard: test en recipe-css-contract prohíbe la coordenada cruda en recipes. `base` /`xxxl` sin bundle → siguen en el primitivo tipográfico | **HECHA** |
| **C8** | **READMEs** — 28 nuevos + F-1.x incompletos (~18). Baseline/Comparativa (≥3 refs reales)/Decisiones/Gaps; passive → justificación. El más pesado: requiere investigación por componente | pendiente |
| **C9** | **Motion eventful gap** — decidir qué interactivos deben expresar firma de evento (hoy 10) y cablearla; criterio: alta frecuencia = sobrio (doctrina D.5) | pendiente |
fix(uix): clear the catalog's clean functional-error flags + reframe C10 tiers
Cleared the error-severity flags that were mature components missing a
documented exception, not real gaps:
- 4 service components (format-date, format-number, relative-time, trans)
get their E-2.2 exception: they render text via $format/$langs with no
visual recipe — no {name}.css by design.
- alert-dialog gets its R-1.1 exception: it composes Dialog (soma reuses the
Dialog runtime, data-dialog-* markers reach the DOM, dialog.css paints the
chrome) — a [data-alert-dialog] root rule would style nothing.
- card gets its missing A-1.3 texts.label (+ langs entry, registered) —
card had no label at all.
C10 (maturity tiers) reframed after the classification exercise showed the
audit VERDICT is the maturity oracle, and 'experimental' is nearly empty
once exceptions are documented: stable = PASS (82); preview = NEEDS-WORK on
docs/demo only (E-2.3/F-1.x/D-*) — functionally sound but underdocumented,
which includes mature components like button/table/listbox (a README gap is
not immaturity); experimental/WIP = a real FUNCTIONAL gap or foreign track.
C10 folds into C8 (document the tier + exceptions when writing READMEs).
Real gaps registered, NOT silenced: float-panel A-3.7 (28 mutating keyboard
actions, 6 events — a morfo-completeness question), card-group (no morfo),
natural-time-picker A-3.1; announce/clipboard R-1.5 (live-region /
composed-focus) await their READMEs in C8 to host the exception.
npm run check at the 59 baseline; alert-dialog -> PASS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **C10** | **Tiers de madurez — REFRAMEADO 2026-07-03** : el veredicto del audit ES el oráculo de madurez. Clasificación objetiva: **stable** = PASS (82); **preview** = NEEDS-WORK solo por docs/demo (E-2.3/F-1.x/D-*) — funcionalmente sano, subdocumentado (~35, incl. button/table/listbox — maduros con gap de README, NO inmaduros); **experimental/WIP** = gap FUNCIONAL real o foráneo (pocos: float-panel A-3.7, card-group sin morfo, natural-time-picker A-3.1, media-player+words/palabras/chronos foráneos). C10 se pliega en C8 (documentar tier + excepciones al escribir READMEs). Cerrados esta pasada los flags funcionales limpios: 4 service E-2.2 (format-date/number, relative-time, trans), alert-dialog R-1.1 (compone dialog), card A-1.3 (texts.label+langs) | **parcial (reframe + flags limpios)** |
| **Gaps reales tracked** | NO silenciados: **float-panel A-3.7** (28 teclas mutantes, 6 eventos — completitud de morfo); **card-group** sin morfo; **natural-time-picker A-3.1** (interactive sin eventos declarados) + R-2.1 (sky fixed-tone, excepción cuando tenga README); announce/clipboard R-1.5 (live-region/composed-focus, excepción cuando tengan README en C8) | pendiente |
docs+fix: old docs quarantined in docs/old-deprecated; STUMBLES doc-class fixes
Two user findings from the Knob build exercise (an agent building a new
component from the docs alone — STUMBLES.md).
Quarantine: the superseded fossils no longer share shelf space with the
live corpus. docs/old-deprecated/ (with an index README explaining what
lands there and pointing readers at docs/README.md) now holds the
executed audits and fix plans: fable_audit, fable-eidos-audit,
inherit_audit + inherit_fix_plan, ARCHETYPE_COHERENCE_AUDIT_2026-06-19
(still citable — the component-guide banner and the eidos components
README repoint to it), COMPONENT_COHERENCE_AUDIT. pendiente.md (a live
pending list, not a fossil) moved to docs/process/. docs-check treats
the folder as sealed chronicle (I1/I2 exempt; I6 skips its internal
links, as its README promises). Root-level *.md is now: README, CLAUDE,
AGENTS + the user's own working files.
STUMBLES fixes applied on the spot (the doc-class ones):
- #2 kind drift: the REAL enum is 'public' | 'private' | 'virtual'
(MorfoPartKind, 671/9/14 uses) — morfo.md omitted 'private', the
checklist invented 'internal' (0 uses). Both fixed; I2 gains the
phantom-'internal' guard. A-2.1's row now says what the audit script
actually checks (kebab only — the archetype may vary, the Toggle
provider-IS-trigger doctrine).
- #6: the langs catalog SHAPE (flat keys, per-language leaves, named
export, index registration) is now shown in morfo.md instead of only
its location.
- #8: component-audit s0 defines the minimum brief package as an
explicit 8-file list.
The engineering-class stumbles are registered as plan batches S1-S6
(generated vocabularies appendix, continuous-gesture trigger doctrine,
part-absent condition, Gesture.rotate, the soma->eidos CSS-var
contract, minor frictions). docs:check 0 errors, 11-warn baseline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
## Tandas S — hallazgos del ejercicio Knob (STUMBLES.md, 2026-07-03)
El usuario encargó a otro agente construir un Knob SOLO desde los docs; su
STUMBLES.md mide la construibilidad — dimensión que las auditorías de
conformidad no cubrían. Ya corregido en el acto (2026-07-03): #2 drift `kind`
(la enum real es public|private|virtual; morfo.md y checklist mentían distinto
+ guard I2 fantasma `'internal'` ; fila A-2.1 alineada con lo que el script
chequea — doctrina Toggle), #6 forma del catálogo langs (snippet en morfo.md),
#8 paquete mínimo (lista de archivos en component-audit §0).
| Tanda | Contenido | Estado |
|---|---|---|
feat(docs): S1 — generated canonical-vocabulary appendix (STUMBLES #1)
An agent building a component from the docs-book alone could not assign
archetypes / holds / haptic kinds: the closed sets live only in code consts
and the corpus (correctly) forbids copying them into prose, so they were
invisible from the docs. STUMBLES #1, the top stumble.
Fix: docs/canon/vocabularies.md is GENERATED from the consts by
'npm run docs:vocabularies' — the ONE sanctioned place the lists are spelled
out (generated = no drift objection), which every other doc links to. It
covers part archetypes (with a one-line role each), sema families with their
default hold/persistence + per-intent overrides, verbs by family, intents,
the perceptual-duration scale, haptic kinds, the 33 palette scales, sizes,
variant archetypes, and the shared common.* strings.
- scripts/docs-vocabularies.ts imports the consts (robust — no fragile
JSDoc/regex parsing) and formats them; the generation is an exported
function so docs-check can compare.
- Added ARCHETYPE_DESCRIPTIONS to morfo/types.ts (co-located with
ARCHETYPE_VOCABULARY, satisfies Record<MorfoArchetype,string>) as the
authoritative one-liners the appendix reads — descriptions become
first-class data instead of inline union JSDoc a tool would have to parse.
- docs-check gains I7: it regenerates in-memory and fails if the committed
file drifts from the consts (negative-tested: corrupt -> error, regen ->
green). The appendix's own counts pass I1, so I1 doubles as a second guard.
- Linked from README (E2 canon row + two 'I want to' shortcuts), CANON.md
(doctrine here, enumerated lists there), architecture/morfo.md (pick a
part's archetype), and the component-audit minimum-package list (STUMBLES
#8).
docs:check 0 errors; npm run check unchanged in my files.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **S1** | **HECHA 2026-07-03** — `npm run docs:vocabularies` → `docs/canon/vocabularies.md` GENERADO desde los consts (archetypes+one-liner vía nuevo `ARCHETYPE_DESCRIPTIONS` , families+holds/persistence/overrides, verbos por familia, intents, haptic kinds, palette 33, sizes, variants, common strings 38). Import-based (robusto, no regex). Guard **I7** en docs-check (regenera in-memory, compara; test negativo OK). Enlazado desde README E2 + 'I want to', CANON, morfo.md, component-audit paquete mínimo. Cierra stumble #1 (vocabularios invisibles) | **HECHA** |
docs+fix: old docs quarantined in docs/old-deprecated; STUMBLES doc-class fixes
Two user findings from the Knob build exercise (an agent building a new
component from the docs alone — STUMBLES.md).
Quarantine: the superseded fossils no longer share shelf space with the
live corpus. docs/old-deprecated/ (with an index README explaining what
lands there and pointing readers at docs/README.md) now holds the
executed audits and fix plans: fable_audit, fable-eidos-audit,
inherit_audit + inherit_fix_plan, ARCHETYPE_COHERENCE_AUDIT_2026-06-19
(still citable — the component-guide banner and the eidos components
README repoint to it), COMPONENT_COHERENCE_AUDIT. pendiente.md (a live
pending list, not a fossil) moved to docs/process/. docs-check treats
the folder as sealed chronicle (I1/I2 exempt; I6 skips its internal
links, as its README promises). Root-level *.md is now: README, CLAUDE,
AGENTS + the user's own working files.
STUMBLES fixes applied on the spot (the doc-class ones):
- #2 kind drift: the REAL enum is 'public' | 'private' | 'virtual'
(MorfoPartKind, 671/9/14 uses) — morfo.md omitted 'private', the
checklist invented 'internal' (0 uses). Both fixed; I2 gains the
phantom-'internal' guard. A-2.1's row now says what the audit script
actually checks (kebab only — the archetype may vary, the Toggle
provider-IS-trigger doctrine).
- #6: the langs catalog SHAPE (flat keys, per-language leaves, named
export, index registration) is now shown in morfo.md instead of only
its location.
- #8: component-audit s0 defines the minimum brief package as an
explicit 8-file list.
The engineering-class stumbles are registered as plan batches S1-S6
(generated vocabularies appendix, continuous-gesture trigger doctrine,
part-absent condition, Gesture.rotate, the soma->eidos CSS-var
contract, minor frictions). docs:check 0 errors, 11-warn baseline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **S2** | Doctrina "Continuous components" en architecture/sema.md — trigger() vs emitEvent en gestos, retención de turno con sequence:'post', throttling de commit-set en key-repeat; documentar la resolución REAL de Slider (stumble #4 ) | pendiente |
| **S3** | Condición `part-absent` en morfo (aria-label solo sin Label) — schema + compiler + runtime (stumble #5 ) | pendiente |
| **S4** | `Gesture.rotate` (centro + sweep + wrap + detents + velocidad angular) — consumidores: Knob, AngleSlider, hue ring, esfera de reloj; hoy FLAGGED GAP en el provider del Knob (stumble #3 ) | pendiente |
| **S5** | Contrato de CSS custom properties soma→eidos (`--x-progress`/`--x-angle`) — extensión del morfo, pasa 2-de-3 (soma escribe, eidos consume); hoy solo prosa en soma-architecture §9 (stumble #7 ) | pendiente |
| **S6** | Fricciones menores (#9): state< T > () vs $state (cuándo cada uno) · role en Provider-con-DOM · Without< >/PrimitiveDivAttributes definidos · ownership de pointermove/up en gesture layers — notas en soma docs | pendiente |
FASE SIGUIENTE (no aquí): ficha canónica generada por componente, demos v3
(D-*), web de docs. Ver conversación 2026-07-02.
test(eidos): triage the 15 long-red suite failures — 289/289 green, check 61→59
Accumulated test debt (the eidos suite had been red across several feature
landings — THEME-SYS-1 named z-index, palette-first static donor library,
spin-field extraction, icon stroke-map refinement — none of them regressions;
baselined against HEAD). Each triaged stale-vs-bug by confirming current
behavior in code before touching a line.
Stale tests (code correct/improved, assertion not updated):
- z-index '76' -> 'var(--z-index-overlay-tooltip)' (the code is guarded by
THEME-SYS-1 in contracts.test.ts — the raw integer is forbidden).
- frost '80%' -> 'var(--depth-overlay-translucency, 80%)' (parameterized).
- C7 size-bundle coordinate ('--control-height-md' -> '--size-md-control-height').
- icon visual-stroke ratios 1.5->1.125, 1->0.923 (stroke map md 2->1.5, xxl
icon 48->52px; the arithmetic follows).
- delegate/CSS-only purple-9: the slim foundation legitimately emits the
role-referenced donor scales (purple=primary) as overridable :root defaults;
the real delegation guarantee is 'no baked [data-theme] block', which the
assertion now checks.
Test over-flagging (fixed the test, not the code):
- CSS-only shared layer: spin-field (no wrapper/index) excluded from the
wrapper/barrel/namespace contracts (CSS_ONLY_LAYERS).
- soma-runtime vars: 'var(--x, fallback)' is runtime-optional (the STUMBLES #7
soma->eidos surface) — only bare 'var(--x)' requires a recipe declaration.
- orphan check made corpus-wide: composition means a sibling consumes a
component's tokens (date-picker/month-grid consume calendar-control-*).
- natural-time-picker fixed-tone sky colors documented-exempt (Words-rail
doctrine).
- dialog drift-detector converted to a synthetic fixture (dialog.css no longer
ships the dead rule it self-tested against).
Real code fixes:
- declare '--pin-input-cell-readonly-bg' (I consumed it in C2b without
declaring it).
- remove 5 truly-dead tokens (drawer content-bg + 4 color-field
format-select/segment — 0 consumers anywhere in eidos/soma/web).
- clamp time-picker's 'size' to PopoverSize before forwarding (xs->sm):
TimePickerSize has xs, PopoverSize doesn't — a latent type bug my recipe
change surfaced via a complexity-budget flip. The fix dropped check 61->59,
also clearing navigation-menu-content of the same class.
card-group flagged as a REAL gap (KNOWN_MISSING_MORFO): it ships parts + chrome
but no morfo (morfo-first violation) — tracked, not silenced.
Verified: vitest src/uix/eidos 23 files / 289 tests green; npm run check 59
(better than the 61 baseline); component:audit 0 BROKEN.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
## Triage suite eidos — HECHA 2026-07-03 (289/289 verde)
Los **15 fallos preexistentes** (deuda acumulada, el suite llevaba rojo tiempo;
baselined contra HEAD — no eran regresiones) triados uno a uno, stale-vs-bug
confirmado en código antes de tocar:
- **Stale tests** (código correcto/mejorado, test no actualizado): z-index `76`
→ `var(--z-index-overlay-*)` (guard THEME-SYS-1 lo prueba); frost `80%` →
`var(--depth-overlay-translucency, 80%)` ; C7 size-bundle (`--control-height-md`
→ `--size-md-control-height` ); icon stroke (mapa refinado md 2→1.5, xxl 48→52
→ 1.125 / 0.923); purple-9 en delegate (foundation slim emite legítimamente
escalas de roles → assert cambiada a la garantía real: no hornear bloque
`[data-theme]` ).
- **Test over-flagging** (arreglado el test): spin-field capa CSS-only
(`CSS_ONLY_LAYERS`); vars soma-runtime con fallback (`var(--x, default)` =
runtime-opcional, no exige declaración); orphan cross-component (calendar-*
consumidos por date-picker/month-grid → corpus completo); natural-time-picker
colores fijos del cielo (`FIXED_TONE_COMPONENTS`, doctrina rail Words); dialog
drift-detector → fixture sintético.
- **Fixes reales de código**: `--pin-input-cell-readonly-bg` declarado (lo
introduje en C2b sin declarar); 5 tokens muertos borrados (drawer content-bg +
4 color-field format-select/segment, 0 consumidores en TODO el repo);
**time-picker `size` clampado a PopoverSize** (`xs`→`sm`: `TimePickerSize`
tiene `xs` , `PopoverSize` no — bug de tipos latente que mi cambio de recipe
afloró vía flip de complejidad; el fix bajó check 61→**59**, arreglando también
navigation-menu-content de la misma clase).
- **card-group** flaggeado como GAP REAL tracked (`KNOWN_MISSING_MORFO`): tiene
partes + chrome pero no morfo (viola morfo-first); NO silenciado — pendiente
de build pass.
Verificado: `npx vitest run src/uix/eidos` 23 archivos / 289 tests verde;
`npm run check` **59** (mejor que baseline 61); `component:audit` 0 BROKEN.
## Verificación de cierre de fase
`npm run component:audit` → 0 BROKEN, NEEDS-WORK solo por reglas D-* (demos,
fase siguiente); paleta y size-bundle universales con guard activo.