You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/process/PLAN-component-coherence.md

110 lines
13 KiB

# 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** |
fix(uix): C2b — invalid/disabled/readonly states: real fixes + cited exceptions The R-1.2/R-1.3/R-1.4 sweep, same method as C2a (evidence first): each offender is either a REAL missing state or a shared-layer/composed case that must not duplicate rules. Real fixes, all verified in a live browser (computed-style probes, with the transition-mid-flight trap from the demo guide s13 accounted for): switch/toggle/rating-group get the family invalid tint (--color-threat-element, the shipped checkbox/pin-input precedent); toggle gets its readonly cursor; pin-input cells get the readonly muted-surface treatment mirroring date-field segments; the SHARED spin-field layer gains the readonly treatment it lacked (one fix covers css-field + number-field); natural-time-picker gets the disabled opacity/pointer rule mirroring date-field. Exception valve wired into R-1.3/R-1.4 (was only R-1.1/1.2/1.5/E-2.2) and cited exceptions added: css-field/number-field (states live in the shared spin-field layer), dialog (data-disabled sits on the VIRTUAL provider — defaultElement none — and the pressable surfaces are composed Buttons), color-picker (color-field owns the invalid rules), date-range-field (the runtime overlays data-date-field-input on the same elements, per its own recipe header), time-picker (composed time-field chrome). natural-time-picker keeps its two warns for its C8 pass rather than guessing paint targets. All 10 audited components now PASS with 0 R-1.x pending; npm run check at the 61-error baseline. css-field/number-field READMEs fixed on disk but unstaged (unrelated local modifications). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **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** |
| **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** |
feat(eidos): C6 — universal palette cascade moves into the generator palette-{slot} is now RESERVED recipe vocabulary: normalizeRecipeTokens (render-css) appends the full per-scale color:{scale} cascade for every donor scale in PALETTE_SCALES to any token named palette-track/element/ border/solid/solid-hover/text/contrast — author-declared color:* declarations win, only absent scales are appended. This is the structural end of the hand-maintained-subset era: a recipe opts into the per-instance palette by naming the token, and the generator guarantees all scales (the 31-vs-33 drift class cannot recur at this layer). Applies to app-config recipes too, since the hook sits where every RecipeTokenSet is normalized. Button's seven manual spreads are gone from base.ts (the helpers moved into the generator); its generated output is byte-identical. Toggle — which already exposed palette-* tokens — universalized itself: +330 generated lines, and <Toggle color="teal"> / color="steel" verified resolving in a live browser (steel and fuchsia are exactly the two scales the hand-kept lists used to miss). eidos-lint now classifies donor-scale values on data-color as sanctioned eidos-only vocabulary (the TSC color:* axis extension) instead of invalid — the morfo enum keeps declaring the semantic roles, per the pilot's deliberate runtime-open design. Guard: recipe-css-contract pins the LAST scale of PALETTE_SCALES for every palette-bearing recipe in the generated css. Also: the stale '31 physical color scales' test TITLE says 33 (its body already asserted 33). Recorded in the plan: the eidos suite carries 15 pre-existing failures in 6 files (baselined against HEAD before this change) — their triage is its own batch. npm run check at the 61-error baseline; lint toggle baseline green again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **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** |
feat(eidos): C7 — size-bundle adoption swept across the recipe catalog The size bundle (--size-{k}-control-height / -font-size / -icon-size, theming/reference §5) was emitted + guarded but consumed by ONE recipe (the toggle pilot). This sweep points every recipe at the canonical size COORDINATE instead of the raw primitive of the same coordinate: 366 refs across 34 recipes (--control-height-{k} -> --size-{k}-control- height, and the font-size / icon-size coordinates likewise). Retuning a size's bundle now reaches every consumer; a recipe that maps a key to a DIFFERENT size's coordinate stays visible as a deliberate deviation. The bundle vars are pure aliases of the primitives, so this is computed-value identical — verified in a live browser: the accordion chain --accordion-trigger-min-height-md = --size-md-control-height = --control-height-md all resolve to calc(36px * 1 * 1). The generated diff is 366-for-366 pure name swaps, nothing else moved. base/xxxl have no size bundle and correctly stay on the typographic primitive. Guard: recipe-css-contract forbids the raw size-coordinate primitive in recipe token values (var(--control-height-{k}) etc.) — the drift can't creep back. This is the ⚠️->✓ that theming/notes' comparison table flags as the size canon's remaining asterisk (canon + guard, now + consumption). component:audit 0 BROKEN; npm run check at the 61-error baseline; the size-bundle guard + palette-cascade guard both green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
| **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 Palabras); dialog
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
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.
feat(eidos): C6 — universal palette cascade moves into the generator palette-{slot} is now RESERVED recipe vocabulary: normalizeRecipeTokens (render-css) appends the full per-scale color:{scale} cascade for every donor scale in PALETTE_SCALES to any token named palette-track/element/ border/solid/solid-hover/text/contrast — author-declared color:* declarations win, only absent scales are appended. This is the structural end of the hand-maintained-subset era: a recipe opts into the per-instance palette by naming the token, and the generator guarantees all scales (the 31-vs-33 drift class cannot recur at this layer). Applies to app-config recipes too, since the hook sits where every RecipeTokenSet is normalized. Button's seven manual spreads are gone from base.ts (the helpers moved into the generator); its generated output is byte-identical. Toggle — which already exposed palette-* tokens — universalized itself: +330 generated lines, and <Toggle color="teal"> / color="steel" verified resolving in a live browser (steel and fuchsia are exactly the two scales the hand-kept lists used to miss). eidos-lint now classifies donor-scale values on data-color as sanctioned eidos-only vocabulary (the TSC color:* axis extension) instead of invalid — the morfo enum keeps declaring the semantic roles, per the pilot's deliberate runtime-open design. Guard: recipe-css-contract pins the LAST scale of PALETTE_SCALES for every palette-bearing recipe in the generated css. Also: the stale '31 physical color scales' test TITLE says 33 (its body already asserted 33). Recorded in the plan: the eidos suite carries 15 pre-existing failures in 6 files (baselined against HEAD before this change) — their triage is its own batch. npm run check at the 61-error baseline; lint toggle baseline green again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
## 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.

Powered by TurnKey Linux.