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/continue-cleanroom-fixes-20...

276 lines
18 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 de ataque — fixes de la auditoría clean-room (2026-07-10)
**Handoff turnkey + plan aprobable. Creado: 2026-07-11.** Rama `alpha-0.1-sec-dom`.
> **Fuente**: la tabla §9 de
> [`docs/audit-new-10-july/audit-active-uix.md`](../audit-new-10-july/audit-active-uix.md)
> — leerla ENTERA antes de tocar nada. El programa anterior está COMPLETO
> (cierre en [`docs/audit/components/_cierre.md`](../audit/components/_cierre.md)).
> Este plan cubre **todas** las IDs de la §9 (P1/P2/P3 + GAP-\*); nada queda
> sin fase asignada — la tabla de cobertura del final es el checklist.
## Reconciliación de estado (la clean-room es snapshot del 2026-07-10)
- **SOM-5 (P1) ✅ CERRADO** post-snapshot: field `commit-submit` al Enter
(`33f346ed`) + float-panel kb-gestos por handle-events (`bdd17f04`).
- **SOM-3 (P2) ◐**: float-panel ya en `uix.timers` (`bdd17f04`);
media-provider es PUERTO Svelte-agnóstico exento por diseño. Quedan ~6
`setTimeout` (image-provider, safe-polygon, dismissal, datetime/announcer,
tags-input, announce/global).
- Badge R-4.3 (única violación R-4.x viva en su §5.3) ✅ cerrada en el censo
R-1.x (`ee9786bc`). Su matriz (102/32/0) es previa: hoy **134/0/0**.
## Principios de secuencia
1. **La máquina primero.** Los fixes que amplían el enforcement (THM-1,
MOR-4, guard de enumeración) van ANTES que el resto: destapan trabajo que
las fases posteriores deben ver en el tablero.
2. **Rojo = parar la línea.** Una suite/guard en rojo (hoy: THM-3) se arregla
antes de cualquier otra cosa de la sesión. Ninguna sesión cierra en rojo.
3. **No-cascada**: un fix → gates → el siguiente. Fix sistémico ⇒ guard que
lo fije (doctrina del programa 2026-06-26).
4. **Iniciativas ≠ fixes.** THM-2, SEM-4, DOC-1/2 y los GAP-\* requieren
decisión de alcance del usuario ANTES de ejecutar — este plan las
dimensiona y propone, no las arranca en frío.
---
## F0 — La máquina, en verde y completa ✅ EJECUTADA 2026-07-11
> Resultado: matriz **135/0/0** (card-group dentro) · contracts **38/38**
> (guard MOR-4 nuevo) · suite eidos **306/306** · baseline 57 · vocab exit 0.
> Verificación en navegador: shake `commit-block` vivo (`block-shake`,
> `--duration-moderate`, stamp `commit · risk`) + chevrons a
> `--opacity-muted` (0.65 computado). Extras que destapó la ejecución:
>
> - El spectrum de color-picker había sido creado **para evadir los
> escáneres** (su header lo admitía; reescrito con doctrina honesta) y
> `recipe-css-contract.test.ts` tenía el MISMO agujero de enumeración —
> cerrado también (concatena hermanos; `color-picker` en
> `FIXED_TONE_COMPONENTS`); R-2.1 ahora caza hsl/hwb/lab/lch/oklab/oklch
> y escanea texto sin comentarios.
> - `commit-block` promovido a firma global de `EidosConfig.motion`
> (`block-shake` + reduce) — completaba un peldaño ausente (el ladder
> tenía fulfill/affirm/threat): ahora TODO rechazo de ToggleGroup lleva
> la firma de denegación en vez del settle de éxito.
> - **Hallazgo sistémico (pre-existente, registrado abajo)**: las reglas de
> cascada de entrada (`[data-stagger][data-state='open'] >
> [data-animation-style]`, (0,3,0)) retienen `animation` para SIEMPRE y
> sombrean cualquier firma de evento de igual/menor especificidad — el
> shake shipped de card-group YA estaba muerto en grupos con `motion`.
> Card-group lo resuelve re-afirmando a (0,4,0); el arreglo sistémico
> queda en cola.
> - `morfo/internal/` existe (picker-shell.ts vive ahí); el guard MOR-4
> acepta ambas raíces. `icon-button` (alias puro de Button, 0 css) y
> `svg` (glifos) exentos con auto-vigilancia (si les aparece css, el
> guard exige morfo); `spin-field` queda como única capa sin contrato
> (F1). Gap real registrado en el dossier de card-group: `disabled` no
> llega al Collapsible (la tabla de props promete selection+toggle).
| Ítem | Qué | Tamaño |
| --- | --- | --- |
| **THM-3** P2 | Voltear el canario vencido: toggle ya lee 0 class-hooks → `lint.test.ts:110` a `toBe(0)`. Suite eidos 305/306 → **306/306**. | S |
| **THM-1** P1 | Extender `component-audit.ts:698,756` a **todos** los `*.css` del directorio del componente (hoy solo `{kebab}.css`). Pagar lo que destape: `hsl()` ×8 en spectrum (anotar `/* literal: physically-fixed */`), `opacity: 0.6` (calendar-select.css:27), fallback mágico `var(--calendar-month-gap, 36px)`. Mismo espíritu que la válvula R-2.1: máquina primero, luego los fixes, no-cascada. | M |
| **MOR-4** P1 | Morfo para `card-group` (doctrina morfo-first, `scope:['eidos']` si procede): leer CSS+wrapper existentes para derivar parts/attrs, recordar la decisión de cardinalidad 2026-06-27 (ToggleGroup OWNS cardinality) en el docblock. Entra en la matriz (→135) con dossier F-1.x y R-\* limpias (incluida su opacidad literal, TOK-3). | M |
| **Guard de enumeración** (contramedida) | La matriz enumera por `MORFO_DIR` — un dir de eidos sin morfo es invisible (así se escondió card-group). Guard nuevo: `eidos/components/*` ↔ morfos, con exenciones explícitas (picker-shell, spin-field = capas compartidas). | S |
**Salida de F0**: matriz 135/0/0 · contracts 38/38 · suite eidos 306/306.
## F1 — Coherencia P1: foco y voz (≈1 sesión)
| Ítem | Qué | Tamaño |
| --- | --- | --- |
| **EID-1** P1 | Anillo de foco de la fundación (`archetypes.css:162-167`) en `box-shadow` vs §32 que canoniza **outline**. Propuesta: retirar el condicionante (el `outline: none` global de `web/routes/layout.css` — inversión de dependencia app→fundación), migrar el anillo a outline con `--focus-ring-*`, conservar la vía forced-colors. **Verificación visual obligatoria** (focus visible en varios componentes, light/dark; 57/130 recetas caen a este anillo). Alternativa (si el usuario prefiere): anotar la excepción en §32. **DECISIÓN #2**. | M |
| **EID-2** P2 | Misma pasada, mismo fichero: `opacity: 0.5/0.85` literales en la fundación → `var(--opacity-disabled)` / token o anotación. | S |
| **Fundación bajo R-\*** (contramedida) | La fundación violaba su propia disciplina porque nadie la escanea. Añadir `archetypes.css` + capas compartidas sin morfo (`picker-shell/*.css`, `spin-field.css`) al alcance del escáner R-2.x/R-4.x o test dedicado. Nota THM-1 (2026-07-11): `recipe-css-contract.test.ts` ya cubre esas capas para color/typo/phantoms (enumera por directorio y ahora concatena hermanos); lo que falta aquí es la vía `component-audit` (enumera por morfo). | S |
| **SEM-1** P1 | Unificar la prioridad de live-region: runtime (`family==='signal' ∧ intent∈{threat,loss}` → assertive, `runtime.svelte.ts:725`) vs AnnounceChannel (solo intent, `announce.ts:55`). Propuesta: canónica = **intent** (lo que sugiere el libro); alinear el runtime + test que fije la política. **DECISIÓN #1**. | S–M |
| **AUX-1** P3 | Mismo territorio: párrafo de doctrina que ordene los TRES mecanismos de live-region (uix.announce zwsp-toggle · fallback del canal · `<Announce>` soma) — quién es para qué capa. | S |
## F2 — Lote mecánico P2/P3 (≈1 sesión, sin decisiones de usuario)
Batch de fixes pequeños, cada uno con su test donde aplique; gates al final:
- **DEP-2** P2 — eliminar `ogl` de `package.json` (0 imports; doctrina
zero-dependence en su forma más barata).
- **DEP-1** P2 — `clsx` fantasma (`soma/props/props.ts:1`): inlinear
implementación propia mínima (doctrina zero-dependence) y cerrar el
"pending decision" de `architecture/soma.md` §12.
- **MOR-1** P2 — `semaSelector`: escape propio de valores (isomorfo, sin
`CSS.escape` del DOM) + validación de nombres de attr en matchers string
(`selectors.ts:141-155`); tests con `"` y `]`.
- **MOR-2** P3 — des-duplicar la convención de marker (`selectors.ts:121`
re-implementa lo que el compilador ya posee): exportarla de un solo sitio.
- **MOR-3** P3 — `_resetCompileCache()` no-op: implementar (WeakMap
reasignable) o eliminar según uso real.
- **SOM-1** P2 — `await handler()` vs contrato "handler síncrono": censo de
handlers async registrados; si 0 → quitar el await (contrato cumplido,
timing más limpio incluso para síncronos); si hay async → **DECISIÓN #3**.
- **SOM-2** P2 — `keydown` corta en el primer match sin handler
(`runtime.svelte.ts:562`): `continue` en vez de `return false` + test con
dos planes de la misma tecla.
- **SEM-2** P2 — política de errores: logging por defecto (dev) en fallos de
canales sin `logger` inyectado; el camino `void trigger(...)` no puede
producir unhandled rejection en producción (catch+log en la vía void,
throw intacto para llamadores que awaitean).
- **SEM-3** P3 — motor: fallback muerto de `applyDominance` (engine.ts:518)
+ cancelar el timer tope de `awaitExpression` cuando `finished` gana
(callback fantasma ≤1500 ms).
- **SEC-1** P2 — endurecer el serializador de `renderCssVariables`:
rechazar `;`/`}` embebidos en valores + test.
- **THM-7** P2 — ejemplo de `sema.md` §packs con selector manual → reescribir
con `semaSelector` (el código real ya está limpio).
- **THM-6** P3 — `var(--radius-full, 1px)` en menu-dial.css:293 → `9999px`.
- **EID-4** P3 — comentarios "31-scale" → 33 (`active-eidos.svelte.ts:653`,
`arts/color/README.md:65`).
## F3 — Censos con guard (≈2 sesiones; SOM-4 puede parir lotes)
| Ítem | Qué | Tamaño |
| --- | --- | --- |
| **SOM-3** P2 ◐ | Migrar los ~6 `setTimeout` restantes a `uix.timers.schedule` (key+meta, patrón float-panel) y retirar sus exenciones del guard de contracts. | S–M |
| **THM-5** P2 | Doctrina para los 17 `!important`: anotación en línea (`/* important: <razón> */`) + regla de máquina R-\* nueva que marque los no anotados. color-picker (4) y group (8) ya tienen razón — anotarla; drawer/float-panel/tabs/select: revisar (fix o anotar). | S–M |
| **SOM-4** P2 | Censo de providers que re-declaran `role`/`aria-*` en `props` getters en vez de `renderProps()` ("most existing providers", guía §Part props). Entregable: tabla censo + guard (WARN) + migración de los mecánicos; si el volumen es grande → plan por lotes tipo S4 con sizing para aprobación. | M (censo) |
| **THM-4** P2 | Doctrina para los 1150 selectores de contrato sin consumidor CSS: criterio en `eidos.md` (attr de comportamiento puro = legítimo y declarado; resto = consumir o podar del contrato) + quemar hotspots (media-player 47 · stepper 30 · color-picker 29 · avatar 28 · trp 26; words 149 excluido). | M |
## F4 — Iniciativas con decisión de usuario (cada una, su sesión)
### F4-A · THM-2 P1 — paleta 33 por instancia (2/17 superficies)
Es un ROLLOUT, no un fix. Triple acción de la clean-room + sizing previo:
1. **Medir** el delta de CSS generado por superficie (33 escalas × 15
componentes en `generated/base.css` — el peso decide el alcance).
2. **DECISIÓN #4**: rollout completo (15), subconjunto razonado, o
re-redactar la promesa de demo-authoring §6 ("acepta las 33") al estado
real. Mecanismo real: `universalPaletteDecls` (`render-css.ts:1766`) —
el doc cita un helper inexistente (`paletteScaleDecls`): corregirlo.
3. **Tracker con hogar**: el registro de rollout borrado renace en
`docs/theming/` (contramedida: borrar un tracker exige puntero sucesor).
### F4-B · SEM-4 P2 — firma perceptiva declarada y no emitida
Deuda "sin urgencia" desde 2026-05/06 — ponerle fecha (**DECISIÓN #5**):
- **close polimórfico inerte** (5 pickers togglean `open` sin disparar el
evento): cablear `runtime.trigger('close-*')` con el patrón
dialog/popover — el intent per-evento ya está declarado.
- **packs dormant** (6 morfos menú/árbol sin emitir): cablear triggers en
providers (D.6).
- **flag `emission`** (D.2) en el morfo para que esto sea auditable por la
máquina (cumple la regla 2-de-3: sema + auditoría).
### F4-C · Corpus documental (DOC-1/2 P1 · DOC-3/4 P2 · DOC-5/6, EID-3, AUX-2 P3)
1. **DOC-1** — migrar el contenido canonizado FUERA de audit/deprecated:
registro de intent-assignment (CANON §3 ← `_veredictos.md`) y
build-contract (component-guide ← ARCHETYPE_COHERENCE §13) a E1/E2;
los audits quedan como historia. **DECISIÓN #6** (hogares exactos).
2. **DOC-2** — ancla editorial: existe edición FINAL sin trackear
(`docs/Disenando_lo_que_ocurre_FINAL.{pdf,docx}`, 426 págs.) y los
punteros apuntan a ficheros inexistentes (README.md:138 · CANON.md:295).
**DECISIÓN #7**: ¿commitear los binarios (hoy excluidos por norma) o
punteros a edición externa? Reconciliar en cualquier caso.
3. **Barrido editorial** (una sesión): DOC-3 enlaces muertos ×15 · DOC-4
secciones stale (cadena de hold sin `SEMA_MAP.families[*].hold`,
`event:*` obsoleto en notes.md, `gradient` omitido en reference §10 +
channels §5, `paletteScaleDecls`) · DOC-5 recuentos fósiles (95/62/25/66/31
→ reales) · DOC-6 menudencias (§4.11 duplicado, TODO(reconcile) huérfanos,
stub TSC, enlace air-old) · **EID-3** párrafo de excepción de *placement*
físico en el mandato logical-RTL · **AUX-2** documentar `disabledDom`
mixto en la tabla de contratos.
4. **Contramedida**: tras limpiar, `docs:check` enlaces muertos WARN→**error**
(que nunca vuelva a tolerarse ×15).
### F4-D · GAP-\* — menú de personalización (§7; el usuario elige)
| Iniciativa | Contenido | Tamaño |
| --- | --- | --- |
| Selection/caret/cursor | La fundación no emite `::selection`, `caret-color` ni tokens de cursor (cableados por arquetipo) — los 3 huecos sistémicos visibles. | M |
| Scrollbar global | `scrollbar-color`/webkit sistémico fuera de scroll-area. | S–M |
| Layer 4 | `--{c}-{role}-{slot}` sin consumidores; la FAQ la marca candidata a colapso "si en 6 meses nadie la usa" → decidir: consumir o colapsar. | decisión |
| Jaulas abiertas | `scrim` sin regla consumidora · `--depth-{plane}-z` 0 consumidores · container queries 0 consumidores — fecha de consume-o-poda para que no fosilicen. | decisión |
| Assets variables | Motor de fuentes variables listo, assets aún TTF estáticos (rfc-typography §5). | M |
| Límites a registrar (sin código) | Sonido por tema = app/dev (D.7) · icon-set no temable · touch-target constante (§37) · `ThemeDefinition` sin `recipes` (§19). Registrarlos como decisiones en el gap-log y cerrar. | S |
---
## Tabla de cobertura (toda ID de §9 → fase)
| Fase | IDs |
| --- | --- |
| ✅ hecho | SOM-5 (`33f346ed`+`bdd17f04`) · badge R-4.3 (`ee9786bc`) |
| F0 | THM-3 · THM-1 · MOR-4 (+guard enumeración) |
| F1 | EID-1 · EID-2 (+fundación bajo R-\*) · SEM-1 · AUX-1 |
| F2 | DEP-1 · DEP-2 · MOR-1 · MOR-2 · MOR-3 · SOM-1 · SOM-2 · SEM-2 · SEM-3 · SEC-1 · THM-7 · THM-6 · EID-4 |
| F3 | SOM-3◐ · SOM-4 · THM-5 · THM-4 |
| F4-A | THM-2 |
| F4-B | SEM-4 |
| F4-C | DOC-1 · DOC-2 · DOC-3 · DOC-4 · DOC-5 · DOC-6 · EID-3 · AUX-2 |
| F4-D | GAP-\* (§7) |
## Decisiones que solo puede tomar el usuario
1. **SEM-1**: política canónica de assertive — propuesta: **intent** ∈
{threat, loss} (el libro), alineando el runtime.
2. **EID-1**: migrar fundación a outline + retirar el reset del app
(propuesta) — o anotar excepción en §32.
3. **SOM-1**: solo si el censo encuentra handlers async reales (si 0, se
quita el await sin preguntar).
4. **THM-2**: alcance del rollout de paleta (15 / subconjunto / re-redactar
promesa), tras la medición de peso.
5. **SEM-4**: prioridad y fecha (close ×5 · packs ×6 · flag `emission`).
6. **DOC-1**: hogares E1/E2 exactos del contenido migrado.
7. **DOC-2**: destino de los binarios del libro (commit vs puntero externo).
8. **F4-D**: qué iniciativas GAP se arrancan y cuáles se registran como
límite deliberado.
9. **Contramedidas**: adoptar rojo=parar · fundación bajo R-\* · guard de
enumeración · trackers con sucesor · deuda con fecha (book-deviations) ·
docs:check en error · clean-room periódica al cierre de cada programa.
## Protocolo de verificación (invariantes)
- `npx tsx scripts/component-audit.ts` → **134/0/0 debe MANTENERSE** (→135
al entrar card-group; nunca hacia abajo).
- `npx vitest run src/uix/contracts.test.ts` → **37/37** (→38 con el guard
de enumeración).
- `npm run check` fuera de `alpha|words|palabras|chronos` → **57**.
- `npx tsx scripts/morfo-vocabulary-check.ts` → exit 0 (WARN cropper conocido).
- Suite eidos → **306/306 tras F0** y se mantiene.
- Cambios observables → verificación en navegador (gesto/tecla/inspección
real). Gotchas de entorno en la memoria del proyecto (rAF congelado en tab
desenfocado, dev server flaky, HMR de `.svelte.ts`).
## Exclusiones DURAS (sin cambios)
- `words/**` · `palabras/**` · `chronos` (ACTIVE_DEV_TRACK) · `web/routes/alpha/**`.
- **Demos**: NO son fix — frame nuevo de sistema pendiente de diseño
(decisión 2026-07-10, `e53bf0e8`); las D-\* son verdict-neutral.
- Nada a git sin petición; commits con paths explícitos (excluir `.claude/`,
`rt.css`, README stub, binarios del libro — salvo que la DECISIÓN #7 los
incorpore).
## Cola lateral (no bloqueante, registrada)
- **Cascada de entrada vs firmas de evento (sistémico, shipped)**: las
reglas generadas `[data-stagger][data-state='open'] >
[data-animation-style='…']` (0,3,0) siguen reclamando `animation` tras
terminar la entrada (data-state persiste) y sombrean las firmas de evento
(0,2,0) en cualquier ítem escalonado — commit-settle/announce-\* incluidos.
Card-group re-afirma la suya a (0,4,0) como parche local; el arreglo de
sistema (¿liberar `animation` durante `data-event-phase='active'`? riesgo:
re-disparo de la entrada al soltar) es diseño de motion — adjudicar en
F2/F4-B.
- `spin-field`: única capa compartida sin morfo/contrato (guard MOR-4 la
exime con nota) — darle contrato en F1 junto a la fundación.
- `card-group.disabled` no alcanza el Collapsible compuesto (promesa de la
tabla de props a medias) — dossier `## Gaps` con «implementar»; toca
wrapper eidos de collapsible (reenvío) o corregir el doc.
- class-hooks preexistentes: color-picker(2) · time-picker(8) ·
time-range-picker(12) — extensión del codemod S1 cuando cuadre; nota:
`.range-time` / `.picker-time-row` (CSS secundarios, ahora escaneados)
pertenecen al mismo censo.
- `task_d66356de` (trp `data-size` a endpoints) · Task #31 (pickers →
`PickerProvider<TValue>`) · `FieldLangsSnippetProps` sin uso.
- Hallazgos trascendentes del programa anterior (en `_cierre.md`):
holiday/event de range-calendar · naming gemelos tree · invalid de rango.

Powered by TurnKey Linux.