28 KiB
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. La continuación viva escontinue-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
## Gapsde 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 ✅ (S653b6f629..d1670caa; S883e13be6). P6 = C63b02fd11· C7444e05eb· B.110f0feb4f✅. 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
(bloques N1–N10 · S1–S11 · C1–C8 + fixes obvios). Los censos de apoyo:
_naming.md y
_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-typecomo atributo se conserva — contrato eidos; solo prop- opts key →
selectionMode). date-picker interno migrado; range-calendar N/A. file-upload conservamultiple(espejo nativo).
- opts key →
- N2
onValueCommit(norma única callback terminal): pin-inputonComplete→, search/passwordonSubmit→, date/time/color-field añaden el callback disparado encommit-set(solo al completar, no al limpiar), textareaonSubmit→ (hueco de censo cazado). 5 sitios internos de picker/rango pasanundefined. - N3 carousel
value→index/onIndexChange. N5deselectable(calendar migrapreventDeselectcon inversión de polaridad). N6 tooltipopenDelay/closeDelay,groupSkipDelay. N7 comboboxallowCustomValue. N8 podadefaultValue(editable/select/grid-list; knob conserva). N4/N10 = veredictos que ratifican el statu quo (sin código). - N9 razón tipada +
onInvalid: tags-input migravalidate-boolean→mensaje +onValueInvalid→onInvalid(reason, value, msg?)con'duplicate'|'custom'. Verificado que date/time/ranges YA cumplían (razones tipadas viaDateOnInvalid/TimeOnInvalid='min'|'max'|'custom'). css-field nivelado (decisión del usuario):onInvalid(reason, value, msg?)con'parse'|'custom', reenviando elmessageque 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(:rooten archetypes.css). Botones tokenizados. checkbox/switch:::beforetransparentemax(100%, var(--touch-target))gated a coarse → crece el ÁREA, no el visual (modelo React Aria / Materialmdc-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-shadowNO es aditivo). El fix correcto era el simple: solo añadirdata-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:- multi-field (date/time-range-field): montan un
<DateField>/<TimeField>real por endpoint (soma), tamaño/variant/color via visual context. - single-field picker (date/time-picker): el root ES el field
(
data-field+data-{c}-field), chrome defield.css. - single-control text (search/mask/number/css): colapsan
fieldRole('provider')fieldRole('control')en la única caja;field.css [data-field-control]fijaflex-direction: row(evita que la columna del provider apile los afijos).
- field con contenido debajo (password: strength meter): estructura Field
canónica completa con una parte
<Control>real + el meter como hermano del stack.
- multi-field (date/time-range-field): montan un
- Poda de recipe-tokens (
a820e5f3+d1670caa, 199 tokens): mover el chrome afield.cssdejó los--{c}-field-height/padding/border/bg/font/...huérfanos (emitidos sin consumidor). El guardrecipe-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-checkNO corre vitest. Tras cualquier refactor de recipe/CSS, corre ademásnpx 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-heightsolo existe bajo[data-field][data-size]. Un elemento compuesto SIN[data-size]cae al default[data-field]= md, fijado. Antes de cambiar uncalc(--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 recipecalendar(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;firstDayespeja elgetWeekStartinterno; weekend de Intl con fallback sáb/dom documentado, caché por locale). Calendar + range-calendar derivanweekenddel locale (antes: hardcoded sáb/dom con 'en-US' — mal para ar-SA). Verificado en vivo (ar-SA → vie/sáb). Hallazgo extra arreglado:getSimpleWeekNumbermezclaba marcos (weekStartsOn absoluto + locale-relativo) → semanas 'simple' desplazadas −1 en es-ES; ancla en marco en-US fijo + test de regresión. - C7 (
444e05eb): textareameasureAutosizedifiere la lectura víadom.measuredel 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).onResizeEndse 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 justificationen 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/## Gapscon 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):- ✅ 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: exceptionsR-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## Gapscon disposición. button sigue NEEDS-WORK solo porD-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 (suA-1.4 exceptionen README ya no se honra tras C5); README soma de button drifted (pending/pressedvs types reales) + docblocks F-2/F-3 de la ficha. - ✅ 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:rooty 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## Gapscon disposición; one-linerexpression: '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. - ✅ 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 porD-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 usavalue+expanded, tree-view usaselectedValue+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. - ✅ 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 eventosscope: ['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" ✓. - ✅ 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 conexpression: '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 entmp/component-audit.md).
- ✅ forms (2026-07-10,
- S9 iniciativas ◐ — sesiones dedicadas POST-S4. gradient-* ✅ CERRADA
(2026-07-10,
45ae3691): la memoria "trabajo sin commitear" era stale (todo estaba enb3d0e290/f5eb8acb); la sesión graduó ambos deACTIVE_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álvulaliteral:(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 (helperresolveDeltaIntentextraí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óninternals.tsdel picker: calendar/cropper/field-langs/gradient-/ image-adjustments) ·listSourceFilessalta 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) · markerdata-float-panel-no-dragdeclarado en el morfo. Cola runtime-discipline ✅ CERRADA (2026-07-11,bdd17f04+ field33f346ed) — contracts.test 37/37 VERDE por primera vez: field adoptacommit-submital Enter (doctrina de familia, verificado en vivo: stampcommit/neutral/active+ traza de la demo) · float-panel migra TODO adom.writeProperty/removeProperty(síncrono — el hot-path pegado al cursor conserva su timing, verificado en vivo píxel-perfecto puntero Y teclado) +uix.timers.schedulepara 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 superponedata-fieldy 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 dos1emanotadosliteral:; 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 endocs/audit-new-10-july/.
Lo que queda — S4 CERRADO; siguiente = decisiones + S9
Follow-ups no bloqueantes (registrados)
task_d66356de— TimeRangePicker no propagadata-sizea 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-heighta 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 dealpha|words|palabras|chronosdebe 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 escropper.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; usarpreview_eval/preview_inspect). Limitación conocida: no se puede forzarpointer: coarseen 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).