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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 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 |
|---|---|---|
| **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** |
| **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 |
| **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 |
## 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 |
|---|---|---|
| **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** |
| **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.
## 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.

Powered by TurnKey Linux.