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-audit-fixes-2026-0...

387 lines
26 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.

# Continue — Auditoría de componentes + fase de fixes (P0–P7)
> **⛔ PROGRAMA COMPLETO (2026-07-11) — este handoff queda CERRADO como
> histórico.** Matriz 134/0/0 · contracts 37/37. Cierre formal:
> [`docs/audit/components/_cierre.md`](../audit/components/_cierre.md).
> **La continuación viva es**
> [`continue-cleanroom-fixes-2026-07.md`](./continue-cleanroom-fixes-2026-07.md)
> (los P1 de la auditoría clean-room). No arrancar sesiones desde aquí.
**Handoff. Fecha: 2026-07-08 · actualizado 2026-07-10 (S4 lote 1 ✅).** Rama `alpha-0.1-sec-dom`.
> **S4 COMPLETO (2026-07-10) → el audit-fix P0–P7 está CERRADO.**
> E-2.3 = 0 en el catálogo (29 dossiers eidos + README soma field-langs;
> máquina 81→**102** PASS; baseline 57). Los NEEDS-WORK restantes son flags
> no-README documentados en los `## Gaps` de cada dossier (S9, demos D-\*,
> censos R-1.x). **Pendiente de decisión del usuario**: (a) los one-liners
> recopilados abajo; (b) ¿"lote 6" opcional? — 13 READMEs ANTIGUOS con
> F-1.x en warn (color-swatch, float-panel, format-date/number,
> gradient-\*·metrics [son S9], onion-menu, radio-cards, relative-time,
> scroll-frames, timeline, trans) que existen pero no tienen forma dossier;
> NO estaban en el plan S4 (solo cubría los ausentes). Después: S9 en
> sesiones dedicadas + reconciliación touch-rows↔§37.
> **P5 y P6 están CERRADOS**: P5 = S1·S5·depth·touch·S6·S8 ✅ (S6 `53b6f629..d1670caa`;
> S8 `83e13be6`). P6 = C6 `3b02fd11` · C7 `444e05eb` · B.11 `0f0feb4f` ✅.
> Pende tu decisión touch-rows↔§37. Follow-ups no bloqueantes abajo.
Documento de continuación para retomar la fase de fixes de la re-auditoría de
componentes. La **fuente de verdad de los veredictos** es
[`docs/audit/components/_veredictos.md`](../audit/components/_veredictos.md)
(bloques N1–N10 · S1–S11 · C1–C8 + fixes obvios). Los censos de apoyo:
[`_naming.md`](../audit/components/_naming.md) y
[`_system.md`](../audit/components/_system.md). Las 91 fichas pilotadas viven en
`docs/audit/components/{kebab}.md`.
## Estado por paquete
| Paquete | Estado |
|---|---|
| **P0** doctrina (sema participation, CANON §3 intent, component-guide §5 + API naming, §32 outline) | ✅ |
| **P1** guardas (vocab-check S10/S11d, component-audit A-3.1/A-1.4/S9, eidos lint classHooks) | ✅ |
| **P2** contratos morfo (role=application×4, aria-selected fuera del Day, drp translationRef, field data-state, pin-input commit-set, media-player renames) | ✅ |
| **P3** packs sema (13 packs nuevos + 12 morfos `family-default`→`'pack'`) | ✅ |
| **P4** naming/API N1–N10 | ✅ **COMPLETO** |
| **P5** sistema/eidos | ✅ **CERRADO** — S1 ✅ · S5 ✅ · depth ✅ · touch-rows ✅ · **S6 ✅** (composición + poda + de-alias) · **S8 ✅** (`--calendar-range-*` API pública `83e13be6`) · (touch↔§37 pende decisión) |
| **P6** C7 textarea-measure + D13 · C6 weekInfo · B.11 splitter | ✅ **CERRADO** — C6 `3b02fd11` · C7 `444e05eb` · B.11 `0f0feb4f` |
| **P7** S9 iniciativas · S4 READMEs · S7 papeleo · errores de tipo baseline | ✅ **S4 COMPLETO 2026-07-10** (baseline ✅ · S7 ✅ · S4 29+1 dossiers ✅, E-2.3=0, máquina 102 PASS) — S9 queda como sesiones dedicadas POST-audit-fix |
## ✅ Reconciliación touch-rows ↔ §37 — CERRADA (decisión usuario 2026-07-10)
**Opción (a) con nota**: el `::before` hit-slop queda CONFIRMADO como mecanismo
para markers desnudos (linaje Material `mdc-touch-target` / Android
touch-delegates / iOS hit-test insets). El argumento WCAG-solape del §37
original se resuelve con (1) requisito de spacing en pilas táctiles densas
(pitch ≥ `--touch-target`; AA garantizado en el peor caso por la excepción
Spacing) y (2) la **fila-label de Field sigue viva como mejora ADITIVA** — la
fila será el target AAA real cuando exista (2.5.5 Equivalent) y el pseudo queda
de red. Redactado en `changelog.md §37` (reconciliación) + `reference.md §37`
(standing "confirmed 2026-07-10").
## P4 — hecho este bloque (N1–N10)
- **N1 `selectionMode`**: select, combobox, toggle-group, **calendar** (unión
discriminada; `data-type` como atributo se conserva — contrato eidos; solo prop
+ opts key → `selectionMode`). date-picker interno migrado; range-calendar N/A.
file-upload conserva `multiple` (espejo nativo).
- **N2 `onValueCommit`** (norma única callback terminal): pin-input `onComplete`→,
search/password `onSubmit`→, date/time/color-field **añaden** el callback
disparado en `commit-set` (solo al completar, no al limpiar), **textarea**
`onSubmit`→ (hueco de censo cazado). 5 sitios internos de picker/rango pasan
`undefined`.
- **N3** carousel `value`→`index`/`onIndexChange`. **N5** `deselectable`
(calendar migra `preventDeselect` con inversión de polaridad). **N6** tooltip
`openDelay`/`closeDelay`, `groupSkipDelay`. **N7** combobox `allowCustomValue`.
**N8** poda `defaultValue` (editable/select/grid-list; knob conserva). **N4/N10**
= veredictos que ratifican el statu quo (sin código).
- **N9 razón tipada + `onInvalid`**: tags-input migra `validate`-boolean→mensaje +
`onValueInvalid`→`onInvalid(reason, value, msg?)` con `'duplicate'|'custom'`.
**Verificado que date/time/ranges YA cumplían** (razones tipadas via
`DateOnInvalid`/`TimeOnInvalid` = `'min'|'max'|'custom'`). **css-field nivelado**
(decisión del usuario): `onInvalid(reason, value, msg?)` con `'parse'|'custom'`,
reenviando el `message` que ya computaba. (file-upload N/A — `FileRejectionReason[]`
ya tipado; words excluido.)
## P5 — hecho este bloque
- **S1 codemod 22 class-hooks** → `[data-{c}-{part}]` (plantilla + CSS): cropper 8
(+ estado `.is-zoomed`→`data-zoomed`), button 6 (+ `:is()` simplificado), image-picker
6, toggle 1, image-adjustments 1. eidos-lint: class-hooks 0 / invalid 0 en los 5.
- **S5 outline**: eliminado el remanente `box-shadow` (transición muerta) de
field.css; el resto del catálogo ya canonizado (comentarios post-migración).
- **depth pass**: `data-depth="overlay"` en tooltip-content, toast-item,
float-panel-content. **No-destructivo** (probado: la regla propia de cada overlay
gana la cascada por orden de fuente; el plano solo aporta identidad frost/Cristal
+ forced-colors). banner **fuera** (decisión del usuario — es strip inline).
- **touch-rows**: token `--touch-target: 44px` (`:root` en archetypes.css). Botones
tokenizados. checkbox/switch: `::before` transparente `max(100%, var(--touch-target))`
gated a coarse → **crece el ÁREA, no el visual** (modelo React Aria / Material
`mdc-touch-target`; suelo único 44 AAA). radio-group row tokenizado.
### Decisiones de método relevantes (para no repetir errores)
- **depth**: la disyuntiva "migrar-al-plano vs quitar-shadow" partía de una premisa
falsa (el "doble shadow" — `box-shadow` NO es aditivo). El fix correcto era el
simple: solo añadir `data-depth`; la regla propia gana. Verificado en vivo.
- **touch-rows**: NO anclar en "44px" sin ver que (a) **área ≠ visual** son ejes
distintos, y (b) el visual depende de size/fuente. Se comparó con 5 frameworks
(React Aria, Radix, Material/MUI, Ark, Base/Bootstrap/shadcn): solo React Aria y
Material desacoplan área/visual; **nadie** hace split AA/AAA por talla (el análogo
MUI se considera bug). → suelo único 44 AAA sobre el ÁREA.
## P5 — S6 Field composition (HECHO 2026-07-08→09, pusheado)
Doctrina del usuario: **todos los fields deben SER fields** (componen `field.css`),
**y ningún field concreto declara tokens que aliasen los de Field**. Commits
`5eb92132..d1670caa` (12). Detalle en memoria: `compose-base-field-not-replicate`,
`no-token-aliases`, `recipe-orphan-test-prune`.
- **16 fields componen `field.css`** — cuatro cardinalidades descubiertas y
documentadas:
1. **multi-field** (date/time-range-field): montan un `<DateField>`/`<TimeField>`
real por endpoint (soma), tamaño/variant/color via visual context.
2. **single-field picker** (date/time-picker): el root ES el field
(`data-field` + `data-{c}-field`), chrome de `field.css`.
3. **single-control text** (search/mask/number/css): colapsan `fieldRole('provider')`
+ `fieldRole('control')` en la única caja; `field.css [data-field-control]` fija
`flex-direction: row` (evita que la columna del provider apile los afijos).
4. **field con contenido debajo** (password: strength meter): estructura Field
canónica completa con una parte `<Control>` real + el meter como hermano del stack.
- **Poda de recipe-tokens** (`a820e5f3` + `d1670caa`, **199 tokens**): mover el chrome
a `field.css` dejó los `--{c}-field-height/padding/border/bg/font/...` **huérfanos**
(emitidos sin consumidor). El guard **`recipe-css-contract.test.ts` "orphaned"** los
caza (167 en la 1ª pasada + 32 tras de-aliasar los pickers). mask-field quedó sin
tokens propios → entrada de recipe eliminada.
- **De-alias de pickers** (`d1670caa`): date-range/time/time-range-picker aliasaban
`--date-field-*`/`--time-field-*` para su parte "field-shaped" → retargeteados a los
**tokens públicos de Field** (`--field-control-*`/`--field-*`/`--field-segment-height`)
o al primitivo donde Field no tiene equivalente (wrap column-gap = segment gap).
Value-preserving (mismo primitivo tras un hop), verificado con revisión adversarial
(workflow, 4 agentes) + navegador en los 4 pickers.
### Lecciones de método (S6) — no repetir
- **El baseline `svelte-check` NO corre vitest.** Tras cualquier refactor de
recipe/CSS, corre además `npx vitest run src/uix/eidos/recipe-css-contract.test.ts`
(25 tests: huérfanos, phantom, "todo var resuelve", scope-contract). La regresión
de 167 huérfanos fue invisible al baseline durante toda la composición S6.
- **`--field-segment-height` solo existe bajo `[data-field][data-size]`.** Un elemento
compuesto SIN `[data-size]` cae al default `[data-field]` = **md, fijado**. Antes de
cambiar un `calc(--control-height - space-2)` por `--field-segment-height`, verifica
en el DOM (xs/sm/lg) que el elemento consumidor lleva `[data-size]`. La revisión
adversarial cazó exactamente esto en time-range-picker.
## P5 — CERRADO ✅ (S8 hecho 2026-07-09, `83e13be6`)
- **S8 calendar-surface**: 8 tokens públicos `--calendar-range-{start,end}-*` en el
recipe `calendar` (API de la capa); range-calendar los consume por el nombre
público; drp deja de tunear los `--_calendar-range-*` privados. Value-preserving
(25/25, baseline 59, eidos-lint 0, navegador idéntico en 4 colores + drp popover).
Asimetría deliberada documentada: start desde `:root` (tema-overrideable), end atado
al accent en el host. Detalle en memoria [[recipe-orphan-test-prune]] /
[[compose-base-field-not-replicate]] (mismo patrón anti-alias que el de-alias de pickers).
## P6 — CERRADO ✅ (2026-07-09→10)
- **C6** (`3b02fd11`): `getWeekInfo(locale)` público en `$libs/days` (convención Intl
1=lun..7=dom; `firstDay` espeja el `getWeekStart` interno; weekend de Intl con
fallback sáb/dom documentado, caché por locale). Calendar + range-calendar derivan
`weekend` del locale (antes: hardcoded sáb/dom con 'en-US' — mal para ar-SA).
Verificado en vivo (ar-SA → vie/sáb). **Hallazgo extra arreglado**: `getSimpleWeekNumber`
mezclaba marcos (weekStartsOn absoluto + locale-relativo) → semanas 'simple'
desplazadas −1 en es-ES; ancla en marco en-US fijo + test de regresión.
- **C7** (`444e05eb`): textarea `measureAutosize` difiere la lectura vía
`dom.measure` del contexto (antes: reflow forzado POR TECLA). Censo D13:
violaciones arregladas en scroll-area (getters del thumb leían clientHeight en
`$derived` → reflow por tick; ahora track medido por RO en $state), virtual-list
(×2 viewports), virtual-grid, carousel (seed diferido + fallback vivo en render
eliminado). Conformes sin cambio: float-panel, cropper, splitter (lecturas
event-time antes de write — D13 es regla de timing). Suites actualizadas al
contrato diferido.
- **B.11** (`0f0feb4f`): par bindable del splitter — `sizes` (bindable, % por orden
de registro: seed + sync + escritura externa clampada) + `onResize`→`onSizesChange`
(norma X+onXChange; dos nombres = alias). `onResizeEnd` se queda (momento commit).
Verificado en vivo en ambas direcciones.
- **Gotcha de entorno registrado** (memoria `hidden-pane-suspends-raf`): el Browser
pane oculto (`visibilityState: hidden`) suspende rAF + entrega de RO → sondas de
medición "muertas", screenshots en timeout. Chequear la vitalidad de rAF ANTES de
diagnosticar; verificar vía suite de navegador de vitest en su lugar. La sonda
reflowDetector quedó pendiente por esto (opcional, no bloqueante).
## P7 — estado (2026-07-10)
- **Baseline** ✅ (`c0ae3de1`): editable + grid-list arreglados (tipos-solo, cast
sobre renderProps) → protocolo ahora **57**. Quedan 9 src/ + ~48 web/ fuera de
mandato (inventario arriba en el protocolo).
- **S7 papeleo** ✅ (`fe844c62`): doctrina §5 + clasificador + F-1.5 ya existían
(P0/P1); añadidos los 2 artefactos que faltaban — `## Passive justification` en
color-swatch (F-1.5 verificado verde en la máquina) + README de capa de
spin-field. radio-cards = interactive para la máquina (F-1.5 N/A; su cita
canónica es el header del morfo, verificada).
- **S4 READMEs** ◐ — **decisión del usuario (2026-07-10): dossier completo, por
lotes de ~6/sesión, máquina en verde por lote**. Forma real (hallazgo): F-1.x
lee el README de eidos como dossier de embarque (`## Baseline` / `## Comparativa`
≥3 refs / `## Decisiones` / `## Gaps` con disposiciones) + puerta del consumidor
(plantilla date-field); el grandfather.json existe para que estos dossiers se
escriban en P7. Gran parte = trasplante ficha→README (las 91 fichas ya tienen
Baseline/Comparativa). **Lotes propuestos** (28 + field-langs):
1. ✅ **forms (2026-07-10, `7b82aa79`)**: button · password-field ·
time-range-field · textarea · knob (READMEs eidos) + **soma field-langs**
(contrato headless).
Máquina: 81→85 PASS; los 5 E-2.3 limpios; F-1.x verde en los 6; baseline 57.
Método fijado: exceptions `R-1.x exception:` SOLO con evidencia leída (pf
R-1.3/R-1.4 → field.css; trf R-1.5/R-1.3/R-1.4 → endpoints TimeField reales,
espejo drf) + gaps de ficha aún vivos trasladados a `## Gaps` con disposición.
button sigue NEEDS-WORK solo por `D-1.5` (regla de DEMO, fuera del alcance).
One-liners detectados y NO ejecutados (decisión pendiente): apg de trf
(`spinbutton`) y apg none-con-razón de field-langs (su `A-1.4 exception` en
README ya no se honra tras C5); README soma de button drifted
(`pending`/`pressed` vs types reales) + docblocks F-2/F-3 de la ficha.
2. ✅ **pickers/nav (2026-07-10)**: range-calendar · natural-time-picker ·
menubar · navigation-menu · command · listbox. Máquina 85→90 PASS; F-1.x
verde en los 6; baseline 57. Verificado pre-escritura el estado
post-fixes (los 6 con hallazgos de ficha YA resueltos por P2/P3/S3b/S8:
packs de range-calendar y listbox, aria-selected, role application, apg
de ntp). **Hallazgo nuevo con evidencia** (README de range-calendar,
Gaps): las marcas holiday/event siguen MUERTAS en range-calendar — sus 2
tokens (`--calendar-day-holiday-shadow`, `--calendar-event-shadow`) se
emiten bajo `[data-calendar]` en generated/base.css y no resuelven bajo
`[data-range-calendar]` (el resto del préstamo va en `:root` y sí).
ntp sigue NEEDS-WORK por su paquete S9 "ntp integral" (A-3.1 del Picker
genérico sin eventos · R-2.1 los 9 cielos sin anotar · README soma +
tests) — todo trasladado a su `## Gaps` con disposición; one-liner
`expression: 'delegated'` en ntp pendiente de decisión (diría la verdad
y silencia A-3.1). R-1.3 readonly de range-calendar/listbox = gap real
(no pinta en ningún sitio) → censo, SIN exception.
3. ✅ **data (2026-07-10)**: table · tree-view · tree-grid · grid-list ·
feed · virtual-list · virtual-grid. Máquina 90→95 PASS; F-1.x verde en
los 7; baseline 57. Los 7 tenían soma README ✓ y suite ✓; varios
hallazgos de ficha ya resueltos post-audit y documentados en los
dossiers (table pack S3b + sort reclasificado a commit.set; apg de
virtual-list en forma C5 "none — rationale"; D13 de virtual-* vía
dom.measure, C7; error de tipos de grid-list en baseline `c0ae3de1`).
virtual-list/virtual-grid quedan NEEDS-WORK SOLO por `D-1.5` (regla de
DEMO, fuera del alcance — mismo caso que button). **Hallazgo nuevo**
(Gaps de tree-grid): asimetría de naming entre gemelos — tree-grid usa
`value`+`expanded`, tree-view usa `selectedValue`+`expandedValue` (N4
solo ratificó el segundo; ambos multi-eje) → decisión de espejo
pendiente. R-1.3 readonly de tree-grid/grid-list = gap real → censo,
SIN exception.
4. ✅ **typography/display (2026-07-10)**: s-text · s-text-virtual-list ·
badge · card · image · skeleton · spinner. Máquina 95→99 PASS; F-1.x (+
F-1.5 en los 4 pasivos: s-text, image, skeleton, spinner) verde en los
7; baseline 57. Quedan NEEDS-WORK con F-1.x verde y el resto en Gaps:
badge (R-4.3 hover del Remove con color-mix hand-rolled → censo
state-layer; R-4.3 NO honra exceptions de README), s-text-virtual-list
(R-1.5 = ARTEFACTO del `archetype: 'item'` en Row — display de 0
eventos `scope: ['eidos']`; one-liner de morfo pendiente que lo vuelca
a passive, el README ya trae la Passive justification preparada) y
spinner (D-7.4, demo). apg de badge/card/virtual-list ya estaban en
forma C5 "none — rationale" ✓.
5. ✅ **util (2026-07-10)**: link-preview · announce · clipboard +
**drag-drop** (el nº29 del censo E-2.3, omitido del plan de 5 lotes e
incorporado al cierre — el "28" del plan era 29 en el censo real).
Máquina 99→102 PASS. Exceptions con evidencia: announce R-1.5 (cero
partes interactivas — eventos programáticos de live region) y
clipboard R-1.5 (el Trigger compone `<Button>`; focus en button.css).
Estados post-fixes verificados: clipboard y drag-drop con pack S3b ✓,
link-preview con `expression: 'delegated'` ✓, apg C5 en drag-drop ✓
(link-preview aún sin apg → one-liner en su Gaps).
Criterio de éxito por lote: `npx tsx scripts/component-audit.ts` → los F-1.x
del lote pasan (el informe cae en `tmp/component-audit.md`).
- **S9 iniciativas** ◐ — sesiones dedicadas POST-S4. **gradient-* ✅ CERRADA
(2026-07-10, `45ae3691`)**: la memoria "trabajo sin commitear" era stale
(todo estaba en `b3d0e290`/`f5eb8acb`); la sesión graduó ambos de
`ACTIVE_DEV_TRACK` (única violación: barrel soma; contracts quedan con los
mismos 13 fallos AJENOS preexistentes — knob/menu-dial/metrics/onion-menu),
declaró apg ×2, subió ambos READMEs a dossier y arregló el falso negativo
D-1.2 del builder. **ntp integral ✅ CERRADA (2026-07-10, `dd249eac`)**: el
ítem estrella (eventos del Picker genérico) YA estaba pagado en S3b (la
ficha era stale — verificado: morfo+pack+triggers+suite); lo que la sesión
añadió: R-2.1 aprende la válvula `literal:` (espejo R-4.x) + los 9 colores
del cielo anotados (no tokenizados, F-2) + README soma (contrato del
coordinador de dominio + cadena delegada) + suite del provider 12/12.
**metrics+suite ✅ CERRADA (2026-07-10, `8e3a67bd`) — S9 COMPLETO**: metrics
reclasificado como puente interno (`SOMA_INTERNAL_PRIMITIVES`, con
picker-shell — su soma es una función sin Provider POR DISEÑO; contracts
13→12 fallos, cero metrics) + import self-alias arreglado + apg C5 +
dossier (goodTrend como diferencial) + suite 7/7 (helper `resolveDeltaIntent`
extraído puro + el puente signal con intent del prop source y contrato de
live region). **Censo contracts ✅ (2026-07-10, `cb554ae2`) — 12→3
fallos**: knob (barrel + README soma) · menu-dial/onion-menu = puentes
internos (`SOMA_INTERNAL_PRIMITIVES`; el guard de scope resta el set de
AMBOS lados — un puente puede declarar 'soma' con verdad sin ser namespace
público) · 6 barrels desacoplados del filename del provider (patrón
`internals.ts` del picker: calendar/cropper/field-langs/gradient-*/
image-adjustments) · `listSourceFiles` salta el ACTIVE_DEV_TRACK
(words/chronos fuera de los guards de ficheros) · `data-archetype` = attr
conocido del compilador + los 4 triggers field-overlay (color-picker/drp/
time-picker/trp) alineados al precedente date-picker/ntp (el contrato ya
coincide con el DOM; cero cambio runtime) · marker
`data-float-panel-no-drag` declarado en el morfo. **Cola
runtime-discipline ✅ CERRADA (2026-07-11, `bdd17f04` + field `33f346ed`)
— contracts.test 37/37 VERDE por primera vez**: field adopta
`commit-submit` al Enter (doctrina de familia, verificado en vivo: stamp
`commit/neutral/active` + traza de la demo) · float-panel migra TODO a
`dom.writeProperty`/`removeProperty` (síncrono — el hot-path pegado al
cursor conserva su timing, verificado en vivo píxel-perfecto puntero Y
teclado) + `uix.timers.schedule` para el readout + los modos kb ahora
suenan por los MISMOS handle-events que el puntero (pick al entrar, drop
al salir/cancelar) · A-3.7 afinado a acciones DISTINTAS (Set — la
semántica de su propio comentario; 0 fallos de catálogo) · media-provider
= PUERTO Svelte-agnóstico por diseño documentado → excepción del guard de
listeners (la válvula que timers ya tenía para announce). Matriz: **120
PASS / 14 NEEDS-WORK / 0 BROKEN**.
**Censo R-1.x ✅ CERRADO (2026-07-11, `ee9786bc`)**: 9 componentes — badge
con fix REAL (hover del Remove al velo `--state-hover` §38, verificado en
demo) + 8 exceptions con evidencia leída (alert-dialog/fab/split-button/
qr-code componen `<Button>`; date-picker superpone `data-field` y su
trigger es DateField.Input compuesto; drf = layout-only espejo de trf;
mask-field IS-A Field ×4 reglas; pin-input YA pinta el ring en
`[data-active]` con tokens canónicos — vehículo que la heurística no
reconoce). Matriz: **129 PASS / 5 NEEDS-WORK / 0 BROKEN** — los 5 = el
lote 6 final (color-swatch · onion-menu · radio-cards · scroll-frames ·
timeline, cero errores, solo dossiers antiguos).
**Lote 6 ✅ CERRADO (2026-07-11, `7f2bcc28`) → PROGRAMA COMPLETO: la
matriz entera en VERDE — 134 PASS / 0 NEEDS-WORK / 0 BROKEN** (+ timeline
gana apg C5 y sus dos `1em` anotados `literal:`; onion-menu renombra
"## Decisions"→"## Decisiones"; scroll-frames gana su Passive
justification). contracts 37/37 · vocab 0 · baseline 57. **La cola del
programa de auditoría está VACÍA. Siguiente = los P1 de la auditoría
clean-room del usuario (`docs/audit-new-10-july/audit-active-uix.md`)** —
los dos que amplían la máquina primero (CSS secundarios sin escaneo R-* ·
card-group sin morfo, invisible a la matriz) y el resto de frentes
(literales en archetypes.css, live-region dual, paleta 33 2/17…).
**Demos FUERA del fix (decisión usuario 2026-07-10, `e53bf0e8`)**: habrá un
frame NUEVO para exponer las demos de todo el sistema → las reglas D-* son
verdict-NEUTRAL en la máquina (datos visibles, matriz sin pintar; se
reescriben contra el frame nuevo). **Matriz resultante: 118 PASS / 16
NEEDS-WORK / 0 BROKEN**, y los 16 = tres familias reales:
(1) censo R-1.x focus/disabled ×9 (alert-dialog/date-picker/drf/fab/
mask-field/pin-input/qr-code/split-button + badge R-4.3 state-layer);
(2) dossiers antiguos ×6 = lote 6 reducido (color-swatch/onion-menu/
radio-cards/scroll-frames/timeline/float-panel);
(3) contrato ×2: field A-3.1 + float-panel A-3.7 — **convergen con el
hallazgo "field/float-panel infra-declarados" de la clean-room nueva**.
Otros: class-hooks preexistentes color-picker(2)/time-picker(8)/trp(12).
**Audit-fix cerrado con S4; S9 cerrado; la auditoría viva ahora es la
clean-room del usuario en `docs/audit-new-10-july/`.**
## Lo que queda — **S4 CERRADO; siguiente = decisiones + S9**
### Follow-ups no bloqueantes (registrados)
- **`task_d66356de`** — **TimeRangePicker no propaga `data-size` a sus endpoints**
(caja fijada a md en todo tamaño; verificado en DOM 2026-07-08). DateRangePicker SÍ
lo hace (via el visual context de date-range-field). Espejar ese patrón; luego el
embedded-trigger de time-range-picker podrá volver a `--field-segment-height` (hoy usa
el privado `--_time-field-height` a propósito, por este hueco).
- **Task #31 (memoria)** — migrar los date/time pickers al `PickerProvider<TValue>`
genérico (deferValue). **POST audit-fix**, no ahora.
## Protocolo de verificación (invariante en toda la fase)
- **Baseline de tipos**: `npm run check` → errores **fuera de**
`alpha|words|palabras|chronos` debe seguir en **57** (era 59; P7 arregló los 2
mandados: editable + grid-list — tipos-solo, cast sobre renderProps). (Comando:
`npm run check 2>&1 | grep " ERROR " | grep -vaiE "alpha|words|palabras|chronos" | wc -l`.)
Quedan 9 src/ fuera de mandato (file-upload ×4 aria-label, navigation-menu
sideOffset, arts/connection ×4) + ~48 en web/ (demos) — candidatos, no mandato.
- **Vocab guard**: `npx tsx scripts/morfo-vocabulary-check.ts` → exit 0 (el único
WARN preexistente es `cropper.commit-crop`, descubribilidad, no mandato).
- **eidos-lint**: `npx tsx scripts/eidos-lint.ts <componente>` → class-hooks 0 /
invalid 0.
- **Suites por componente** en verde antes de pasar al siguiente (no-cascada: UN
componente, verificar, luego el siguiente).
- **UI**: check en navegador con los `preview_*` (no screenshot — flaky; usar
`preview_eval`/`preview_inspect`). Limitación conocida: no se puede forzar
`pointer: coarse` en el preview headless (el resize a móvil no cambia el tipo de
puntero) — verificar coarse por CSSOM + gating en fine.
## Exclusiones DURAS (no tocar / no commitear)
- `words/**`, `palabras/**`, `chronos` — el rename N1 los rompió; **decisión del
usuario: dejarlos rotos** (excluidos del baseline y del commit).
- `web/routes/alpha/**` — sitio de docs TERMINADO.
- Nada a git sin petición explícita; al commitear, **paths explícitos** excluyendo
lo de arriba + `.claude/` (settings locales).

Powered by TurnKey Linux.