# Auditoría de componentes — acumulador de hallazgos que escalan al sistema
Registro vivo. Cada ficha (`{kebab}.md`) aporta sus `S-n`; aquí se
consolidan des-duplicados para el **checkpoint único post-barrido** (los
fixes — locales y de sistema — se ejecutan después de auditar todo el
catálogo). Formato: origen (fichas) · hallazgo · propuesta.
| # | Origen | Hallazgo de sistema | Propuesta |
|---|---|---|---|
| SYS-1 | button | **Hooks de selector como clases** (`.eidos-button-*`) conviviendo con data-attrs — las clases escapan a eidos-lint; segunda gramática de hooks | Norma de catálogo: hooks SIEMPRE `data-{c}-{kebab}`; + guard (lint de clases con estilos en CSS de componentes). El barrido censa qué componentes lo hacen |
| SYS-2 | button | **Política de tests**: cobertura heterogénea (button 0 tests; date-field 8KB ✓) | Decisión: suites por componente en la fase de fixes vs batch de testing posterior. Cada ficha registra su cobertura para dimensionar |
| SYS-3 | button | **Criterio de pack sema**: ¿cuándo un componente merece pack vs default de familia? (button sin pack = default contact; 38 packs sesgados a fields/pickers) | Canonizar el criterio por escrito (CANON/sema doctrine): default-de-familia legítimo para contacto genérico; pack donde el patrón añade significado |
| SYS-4 | button · date-field | **Nivel canónico del README**: la máquina exige eidos (E-2.3); button solo soma; date-field ambos | Ratificar: eidos = puerta del consumidor (API visual + tokens), soma = contrato headless; documentar en component-guide |
| SYS-5 | date-field | **Doctrina §32 vs segment-fields**: "los campos quedan en box-shadow" pero date-field usa outline flush con razón sólida (flicker en increment + forced-colors). Afecta a date/time/color-field + ranges | Decisión doctrinal: matizar §32 (text-fields = dos anillos box-shadow · segment-fields = outline flush, razón canonizada) — recomendada; el barrido censa la familia completa |
| SYS-6 | date-field (≡ mandato B.1) | **Composición Field**: soma participa (merge) pero el DOM no envuelve `[data-field][data-size]`; label propio; alturas `height-{k}` duplicadas por componente | Ya mandatado en `next-features.md` — el barrido acumula la lista de piezas por componente |
| SYS-7 | spin-field · number/css-field · color-swatch | **Clasificación "capa compartida"/átomo pasivo sin escribir**: spin-field/list-surface/field-segment-state (capas) y color-swatch (átomo eidos-native sin `## Passive justification`) — vs la doctrina "morfo-first even leaf". Sin criterio formal ni doc de capa | Definir formalmente CAPA y ÁTOMO PASIVO (markers, README de capa, justificación formal, cómo los clasifica la máquina); documentar en component-guide |
| SYS-8 | calendar · range-calendar · month/year-grid · drp/dp (≡ mandato calendar-surface) | **La familia calendar vive de préstamo informal** (79+65+65+38+4 tokens cross-component); tras B.2, las marcas holiday/event solo pintan en calendar; month/year-grid ni declaran el privado de acento | Ya mandatado (next-features): capa `calendar-surface` y/o arquetipo de celda-día; las fichas de la familia listan las piezas por componente |
| SYS-9 | gradient-picker · gradient-builder (+ntp) | **Patrón "iniciativa a medias"**: componentes embarcados sin cerrar el paquete de estándares (expediente pre-flight F-1.x, APG, tests) — gradient-builder es el caso más agudo | Fase de fixes: cerrar por PAQUETES de iniciativa (gradient-* junto; natural-time-picker integral) — y valorar guard de embarque ("no se embarca sin expediente") |
| SYS-10 | field (re-audit) | **Enums de estado muertos**: el morfo de field declara `data-state` con enum de 5 valores × 3 partes y CERO consumidores CSS en TODO el catálogo (grep exhaustivo); loading no pinta nada. Contrato emitido que nadie honra = peso muerto y promesa falsa del contrato | Veredicto por enum: consumirlo (materializar loading/invalid vía el enum) o podarlo del morfo. El barrido censa más enums muertos en las familias restantes |
| SYS-11 | date-range-field · time-range-field · pickers (re-audit) | **El canon de delegación EXISTE y los compuestos no lo usan uniformemente**: `SemaExpressionMode = 'pack'\|'family-default'\|'delegated'\|'none'` está documentado en `morfo/types.ts` (decisión de autor 2026-05-26; `'delegated'` = "expression lives in children's packs"). date-picker/date-range-picker LO DECLARAN (`expression: 'delegated'` + evento propio solo para el gesto que el hijo no posee: commit-reset) — la regla practicada es exactamente la correcta. Pero date-range-field/time-range-field (compuestos equivalentes) NO declaran expression alguna, y la máquina (A-3.1) no usa `'delegated'` como marcador de exoneración | (a) Fix de una línea en los field-ranges: `expression: 'delegated'`; (b) afinar A-3.1: interactivo + 0 eventos + sin `'delegated'` = gap (caza pin-input y natural-time-picker, exonera a los delegados); (c) párrafo en CANON/sema citando la decisión 2026-05-26 y el patrón date-picker como ejemplo |
## Censos transversales (rellenándose con el barrido)
- **readonly/invalid sin materializar (R-1.3/R-1.4)**: search/password/mask/time-range-field, date-picker, range-calendar, listbox, tree-grid, grid-list (R-1.3 ×9) · time-range-field + natural-time-picker (R-1.4 ×2) → resolver como TRATAMIENTO ÚNICO (composición Field / regla de familia), no 11 parches.
- **Focus (SYS-5)**: outline es EL modelo de facto en todo el catálogo (fields, pickers, overlays, controls); box-shadow queda 1 en field.css → veredicto (a) matizar §32.
- **Duplicación de alturas (SYS-6)**: date/time/color/search/password/mask-field (6).
- **Packs sema (SYS-3) — censo CORREGIDO por la re-auditoría (pickers/calendar)**: trío FIELDS roto (date ✓ / time ✗ / color-field ✗) PERO los pickers de media TODOS con pack ✓ (color-picker, image-picker, gradient-picker, gradient-builder) · **command RETIRADO de la lista** (family-default razonado con libro in-place: cap.22 §8 anti-"celebrate before time", precedente Button — tercer default legítimo documentado con field-langs y button) · sin pack con semántica rica CONFIRMADOS: **range-calendar (el mejor candidato: start affirm → range FULFILL → reset neutral ya declarados)**, month/year-grid, listbox, clipboard, drag-drop, media-player, onion-menu/menu-dial, carousel, table · **tercera categoría nueva: deuda DECLARADA** (Picker genérico :18-19 — fijar plazo a los "yet" en el veredicto) · pendiente re-verificar al llegar a sus familias: listbox/clipboard/drag-drop/etc.
- ~~Demo (D-7.4 chip drift · D-1.2 plantilla · D-1.5/D-4.3/D-3.1 cableado)~~ — **FUERA DEL ALCANCE de esta auditoría** (corrección de alcance 2026-07-07: solo las capas del componente). Los datos siguen en tmp/component-audit.md como backlog de demos aparte; no computan en fichas ni en el checkpoint.
- **APG ausente (A-1.4)**: natural-time-picker, gradient-picker, gradient-builder, card (variante interactiva), drag-drop, media-player, virtual-list, metrics → y **regla nueva necesaria**: cómo satisfacer "sin patrón APG oficial" (media-player, drag-drop) — ¿`apg: 'none — rationale'`? **Actualización 2026-08-25**: la cara gemela —el `apg` PRESENTE pero MENTIROSO— tiene ya su primer miembro resuelto (`tags-input` F-1: se implementó el layout grid que citaba, en vez de corregir la cita) y dos miembros vivos medidos: `search-field` F-1 (`apg: combobox` sin popup) y **`tag-group`**, que declara el mismo `apg: grid` que `tags-input` y renderiza `role=row` SIN ninguna celda (`morfo/components/tag-group.ts:64` `:137``:163` — cero `gridcell` declarados) más un `Label` colgando del `grid` que no es `row`. La regla que falta es UNA para las dos caras: qué se hace cuando no hay patrón, y qué se hace cuando el declarado no describe lo implementado.
- **Gramática de eventos (A-3.6/A-3.7)**: media-player ×4 nombres fuera de `{familia}-{verbo}` · float-panel 28 mutaciones/6 eventos (el mayor infra-declarado).
- **Interactivo con 0 eventos (A-3.1) — censo FINAL tras chequeos de delegación**: **pin-input = el único caso desnudo** (0 eventos + comentario :7-9 que promete un "commit-fill" imposible: sema ni está en scope — contradicción in-file). EXONERADOS: date-range-field/time-range-field (delegación real a los singles embebidos; les falta solo declararla — `expression: 'delegated'`) · natural-time-picker (header :4-19 documenta la composición entera; su hueco transaccional es deuda del Picker genérico) · **Picker genérico = tercera categoría: deuda DECLARADA** (:18-19 "candidate commit-* events for a later sema pass" — Accept/Cancel/Clear sin contrato, reconocido; UN fix ahí repara ntp + los 5 pickers de la migración deferValue). Afinar A-3.1: leer expression/scope/header antes de flaguear; añadir el Picker genérico al universo del script.
- **WIP usuario (re-visitar fichas tras su pass)**: number-field, css-field, slider, tabs, timeline.
- **Candidato nº1 a pass integral**: natural-time-picker (8 reglas + 3 gaps de capa).
- **Focus (SYS-5)**: familia fields = outline prácticamente entera (field.css conserva 1 box-shadow — el remanente del modelo §32); o0 en los que delegan (number/css/range) ✓. La doctrina "campos en box-shadow" está muerta en la práctica → refuerza propuesta (a): canonizar outline y matizar §32.
- **Duplicación de alturas (SYS-6)**: date, time, color, search, password, mask-field (6) duplican `height-{k}` = size-bundle que field/spin-field ya exponen.
- **R-1.3/R-1.4 readonly/invalid sin materializar**: search, password, mask, time-range (readonly ×4; invalid ×1) — patrón de familia a resolver por composición Field, no 4 parches.
- **Packs sema — trío roto (SYS-3)**: date-field ✓ tuneado vs time-field/color-field ✗ crudos (y sus ranges heredan la asimetría). field/date-range/time-range/field-langs sin pack (evaluar by-design vs gap en el veredicto SYS-3).
- **READMEs (SYS-4)**: faltan eidos → button, password-field, time-range-field, textarea; falta soma → field-langs; capa sin doc → spin-field.
- **Reflow write-then-read (doctrina D13, censo re-audit)**: **textarea CONFIRMADO** (`measureAutosize()` con lectura layout SÍNCRONA tras escritura en oninput :313 / clear :238 / mount :290; cero `dom.measure`/raf en el fichero — un forced-reflow POR TECLA) · contraste correcto: editable autoResize por `ch` sin medir DOM (by-design ✓) · candidatos a chequear en sus familias: scroll-area, cropper, splitter, float-panel, virtual-list/grid, carousel.
- **`role='application'` sin razón documentada (re-audit pickers/calendar)**: calendar :51 · range-calendar :64 · month-grid :47 · year-grid :46 — decisión a11y pesada (desactiva el cursor virtual del lector) heredada ×4 sin una línea de porqué, en morfos que documentan hasta 3 razones de archetype. Decisión ÚNICA de familia (react-aria la usa; bits-ui no — debate APG real que merece resolverse por escrito).
- **ARIA inválido `aria-selected` sobre `role='button'`**: calendar Day :340-344 · range-calendar Day :317 (el Cell gridcell ya la lleva legítimamente en ambos); month/year-grid NO lo tienen (estructura Cell-directo — la referencia interna del fix).
- **`v.literal` con texto humano (no localizable)**: date-range-picker :160 'Select month range' + :248 'Select year range' (calendar usa commonRef ✓) — regla de máquina candidata: literal con espacios = sospechoso.
- **Familia handle (manipulación continua) — censo (pickers + controls)**: **knob = ciclo COMPLETO pick/drag/drop + set/reset** (la referencia) · color-picker (pick+drag) · gradient-builder (pick+drag) · cropper (drag+resize+zoom) · image-picker (rotate) · slider pendiente (WIP usuario). Pregunta al veredicto: ¿el `drop` de knob debe declararse en los demás (el settle del gesto) o es opcional por componente?
- **Modelos de intent en toggles binarios (controls)**: checkbox = 2 eventos direccionales estáticos (check affirm / uncheck neutral) vs switch/toggle/toggle-group = 1 evento `fromProp:'intent'` default neutral — dos respuestas razonadas a la misma pregunta; documentar la distinción (marcar-hecho ≈ direccional vs conmutar-modo ≈ parametrizable) con el censo de des-selección: colección-unselect=affirm ×3 · binario-uncheck=neutral · reset/cancel=neutral ×5.
- **Nombre↔verbo desajustado**: cropper `commit-crop` con `verb: 'apply'` (:64-67) — A-3.6 no lo cazó (4º agujero de regla).
- **Intent de des-selección — doctrina de facto CONSISTENTE**: `commit-unselect` = **affirm**×3 (calendar, select, combobox) vs deshacer/abandonar = **neutral** (commit-reset date-field/date-picker/color-picker/range-calendar; commit-cancel editable) — no es drift: es regla no escrita → documentarla en CANON (el veredicto de calendar F-5 pasa de "corregir" a "canonizar").
- **Agujeros de regla del script detectados por la re-auditoría**: A-3.1 no cazó pin-input (0 eventos real) · A-1.4 no cazó image-picker (apg=0 con PASS limpio) · vocabulary-check da OK a gradient-picker (expression 'delegated' contradicha por pack+eventos propios — regla :37-41 no cruza coherencia) · Picker genérico FUERA del universo del informe → afinar las 4 reglas en la fase de fixes.
- Pendientes de censar: letter-spacing bundle (~34, Fase 1) · named styles en controles · `data-depth` Tier-A · borrowers calendar-familia · más enums muertos (SYS-10) · delegación vs 0-eventos en compuestos restantes (SYS-11).
## Estado de la RE-AUDITORÍA (2026-07-07)
El barrido inicial de 138 fichas quedó como andamiaje (hallazgos de máquina +
metadatos válidos; análisis por capas ausente — ver la corrección de alcance).
La re-auditoría re-lee capa a capa con evidencia `file:line` por dimensión y