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/scripts/theming-sentinel-exceptions.ts

136 lines
7.9 KiB

uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4 Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba más dura que la del autor), sonda x2 por componente para fijar el suelo de ruido. 34 hipótesis · 26 refutadas · 8 reales. Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs; command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 · listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano» de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación; eidos-lint 0 invalid. Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command 8.091 y carousel 2.842 valores, 0 diffs): 1. command: el re-point de `--command-radius` dentro del Dialog era una declaración muerta con comentario falso — la misma regla pone el radio a 0 y el input lee `--command-input-radius`, nunca este token (medido: `--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px` movía la paleta inline y no la del dialog). Retirado; comentarios y README reescritos con lo medido. 2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo mientras la horizontal leía `active-indicator-scale` — el token alcanzaba media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora lo leen las dos. 3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap` INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es la prueba. Canal de valor de soma, como --gp-current-gradient. Censo carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto (5.190 · 2.102). 4. table: `striped-row-bg` no alcanza NADA en la demo publicada — `:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel → PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`); adjudicado en el ledger mientras tanto. El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas medidas, y la cuarta era de la sonda: - el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el token de reposo leía muerto (era el «falso negativo sin causa» de §13); - el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de `{c}-root` no lo recibían; - `::before`/`::after` eran invisibles (el aro de buffering, el spinner); - la no-determinación de feed no era una animación sin localizar: era la demo aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma `commit-settle` anima box-shadow sobre el nodo medido. Con la espera de asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas. Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y que carousel convirtió en patrón — un estilo inline de otra capa es invisible para todo análisis estático): `npm run theming:sentinel -- <c> <url>` (scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en todos los nodos del componente, pseudos, pase de hover, settle) + ledger scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 · gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46 excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró; y dos muertos nuevos los produjeron los propios arreglos (el blur apaga focus-input-border; el settle desmonta el spinner de feed) — adjudicados con su porqué. Doctrina en recipe-contract §4. También: tres cifras de especificidad de next-features §12 recontadas (la banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0); y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el velo en la celda), el comentario de listbox que mandaba pisar el privado `--_listbox-max-height` apunta ahora al público, y quedan registrados en §13 los dos `header-z` con literal '2' y el spinner de media-player a 720ms mientras el gemelo de feed lleva tokens. Guards: censo global 43 % intacto · audit --only command+carousel PASS · eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs 0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en HEAD y no se tocan). Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el arquetipo en fila+celda, y que soma lea el gap de un token. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
/**
* theming-sentinel-exceptions — the written adjudications R-5.4 requires.
*
* A public token the sentinel reports as "no effect" is EITHER a lie (retire
* it) OR its silence has a measured reason that lives here, one line per
* token: the part is conditional and the demo does not mount it, the state
* needs forcing, the consumer is a pseudo-element or a composed component the
* instrument cannot read, the value sits behind a media query. "Forced →
* reaches" means the adjudication PROVED the token alive by mounting what it
* needs; an instrument-limit entry names the limit (they are also registered
* in next-features §13).
*
* An entry whose token starts moving again is reported as STALE by the guard —
* prune it (a stale exception is the same debt as a stale allowlist row).
*
* All entries below were measured during the F2-A adversarial review
* (2026-08-21) unless dated otherwise.
*/
export const SENTINEL_EXCEPTIONS: Record<string, Record<string, string>> = {
command: {
'focus-input-border':
'consumed only under :focus-visible, which the guard blurs away ON PURPOSE (the click-focus poisoning fix); focused by hand → reaches (rgb(9,9,9))',
'loading-height': 'the loading bar is conditional and the demo does not mount it',
'loading-fg': 'the loading bar is conditional and the demo does not mount it',
'viewport-padding': 'the non-ScrollArea viewport variant is not mounted in the demo',
'empty-padding-block': 'the empty state is conditional and not mounted at measurement',
'empty-fg': 'the empty state is conditional and not mounted at measurement'
},
table: {
'header-z':
'consumed only under [data-sticky-header], which the demo does not set; forced → reaches (2 → 4321)',
'row-detail-fg':
'detail rows are closed (display:none) in the demo initial state; forced data-state=open → reaches (rgb(1,2,3))',
'row-detail-padding-block':
'detail rows are closed (display:none) in the demo initial state; forced data-state=open → reaches (12 → 1234)'
},
'media-player': {
'accent-strong': 'consumed by the live indicator, which only paints under [data-live]',
track:
'forwarded into the composed Slider — paints on [data-slider-*] nodes, outside this component attribute space',
'buffered-bg':
'forwarded into the composed Slider (SecondaryRange) — outside this component attribute space',
'captions-bg': 'captions are conditional and the demo video carries no track',
'captions-fg': 'captions are conditional and the demo video carries no track',
'captions-radius': 'captions are conditional and the demo video carries no track',
'captions-padding-block': 'captions are conditional and the demo video carries no track',
'captions-padding-inline': 'captions are conditional and the demo video carries no track',
'captions-line-height': 'captions are conditional and the demo video carries no track',
'volume-vertical-length': 'the volume float is interaction-mounted; not open at measurement',
'volume-float-padding-block':
'the volume float is interaction-mounted; not open at measurement',
'volume-float-padding-inline':
'the volume float is interaction-mounted; not open at measurement',
'rate-button-min-width': 'the rate control is conditional and the demo does not mount it',
'audio-title-padding-block': 'audio variant — the video demo does not mount the audio title',
'audio-title-padding-inline': 'audio variant — the video demo does not mount the audio title'
},
'tree-grid': {
'header-z':
'consumed only under [data-sticky-header], which the demo does not set; forced → reaches (2 → 4321)',
'disabled-row-fg': 'no disabled row in the demo; forced data-disabled → reaches (rgb(1,2,3))'
},
'gradient-picker': {
'chip-radius':
'the swatch is a CLASS hook (.gradient-picker-trigger-swatch) outside the attribute-filtered node set; direct read → reaches (§13 class-hook debt)',
'chip-border':
'the swatch is a CLASS hook outside the attribute-filtered node set; direct read → reaches (§13 class-hook debt)',
'content-width-sm':
"sized by data-picker-size (picker-shell's axis, not data-size); forced → reaches (288 → 512)",
'content-width-lg':
"sized by data-picker-size (picker-shell's axis, not data-size); forced → reaches (352 → 512)",
'stoplist-max-block':
"consumer node lives in the composed ScrollArea's attribute space (--scroll-area-auto-max-block on the viewport); direct read → reaches (132 → 1234)",
'stoplist-scrollbar-size':
'the design scrollbar only mounts on overflow; the demo list is short',
'stoplist-scrollbar-inset':
"consumer node lives in the composed ScrollArea's attribute space; direct read → reaches (12 → 1234)",
'presets-panel-width':
"the presets popover needs a second click the guard's open step does not perform; forced → reaches (240 → 1234)",
'presets-gap': 'presets popover not mounted by the open step; forced → reaches (8 → 1234)',
'presets-min-column':
'presets popover not mounted by the open step; forced → reaches (66px columns → 1234)',
'preset-height': 'presets popover not mounted by the open step; forced → reaches (32 → 1234)',
'preset-radius': 'presets popover not mounted by the open step; forced → reaches (6 → 1234)',
'preset-border': 'presets popover not mounted by the open step; forced → reaches (rgb(1,2,3))',
'hover-preset-border':
'presets popover not mounted by the open step; forced + real hover → reaches (rgb(1,2,3))',
'selected-preset-border':
'presets popover not mounted by the open step; forced data-selected → reaches (rgb(1,2,3))',
'selected-preset-outline-offset':
'presets popover not mounted by the open step; forced data-selected → reaches (2 → 1234)'
},
listbox: {
'invalid-border': 'no invalid listbox in the demo; forced data-invalid → reaches (rgb(1,2,3))'
},
carousel: {
'vertical-block-size':
'vertical orientation not mounted in the demo; forced → reaches (256 → 1234)'
},
feed: {
'sentinel-spinner-size':
'the spinner only exists while [data-busy], and the guard WAITS for the busy window to close (the settle fix); measured live during the busy window (::before, 12 → 1234)',
'sentinel-spinner-width':
'the spinner only exists while [data-busy]; measured live during the busy window (::before border)',
'sentinel-spinner-gap':
'the spinner only exists while [data-busy]; measured live during the busy window (::before margin)',
'sentinel-spinner-duration':
'the spinner only exists while [data-busy]; measured live during the busy window (animation-duration 0.7s → 11.5s)',
'article-title-font-size-5':
'the demo mounts heading levels 3–4 only; forced aria-level=5 → reaches (14 → 1234)',
'article-title-font-size-6':
'the demo mounts heading levels 3–4 only; forced aria-level=6 → reaches (12 → 1234)',
'sentinel-spinner-reduced-duration':
'behind prefers-reduced-motion; emulated reduce context → reaches (4s → 11.5s)'
uix(grid-list): temable — 0 % → 85 %, y una selección que nunca pintó 38 claves nuevas en el bloque `grid-list` de `recipes/base.ts` (que ya existía con los dos forwards de paleta: se FUSIONA, no se añade un segundo). Alcance del censo 0 % → 85 % (22 de 26 puntuables); global 45 % → 46 %, sin contrato 49 → 48. El eje `size` se estampa en el PROVIDER —el wrapper de eidos no tiene parte `root`—, así que los tres nombres resueltos van SIN `parts`: molde `command`, no `table`/`tree-grid`. Fuera los cuatro bloques `[data-size]` del CSS; los emite el TSC. Altura de fila 1:1 con el bundle, `row-padding-inline` con ritmo propio, y la tipografía un paso por debajo de md en adelante — verbatim, como table y tree-grid. LO QUE LA MEDICIÓN CAMBIÓ (la §4 generada tenía un error de doctrina y dos defectos que sólo aparecieron midiendo; el §5 Veredicto se escribió con la sonda delante, porque estaba vacío): 1. La selección de fila NUNCA HA PINTADO. La receta seleccionaba `[data-grid-list-row][data-selected]`, un atributo que ni el morfo declara ni soma estampa (estampa `data-state='selected'` + `aria-selected`): la regla no casaba jamás y su acento `--_grid-list-palette-element` no llegó nunca al píxel — una fila seleccionada muestra el velo NEUTRO del arquetipo, indistinguible del hover (capturado). Retirada la declaración muerta y su forward huérfano: 0 diffs, que es la prueba. Repararlo mueve píxel y choca con §12.5 (el arquetipo fija también `color`) → §13, espera firma. El acento del checkbox (`_palette-solid`) sí vive y se conserva. 2. NO se acuña `hover-row-bg` aunque la propuesta lo pedía. La fila es `archetype: 'item'`: el velo del sistema la pinta a especificidad plena y el plano de la receta pierde — medido, el hover pinta DOS VECES sobre el MISMO nodo (a diferencia de table/tree-grid, donde velo y plano caen en nodos distintos). Sería un token que no puede ganar; mismo criterio que listbox.highlighted → §12.7. Y fila Y celda llevan ambas `item`, así que bajo el puntero se apilan tres capas. 3. «Consume la capa compartida `menu-indicator`» es FALSO. Sale de `SHARED_LAYERS` (`theming-census.ts:432`), pero esa capa no tiene un solo selector de grid-list, la receta no la importa y soma no renderiza indicator: el checkbox ESPEJA el visual pintándolo por su cuenta. Entrada desviada del censo → §13 (listbox / menubar / navigation-menu están en la misma entrada y tampoco aparecen en el fichero). Nombres, sobre la propuesta: `selection-checkbox-{width,height}` son UN knob → `selection-checkbox-size`; `on-selection-checkbox-bg` → `checked-selection-checkbox-fg` (es la tinta del glifo, y `on-` es prefijo reservado); `border` partido en `border-width` + color (molde `command.input-border*`), que el checkbox comparte; `padding` uniforme se queda `padding` (precedente `command.viewport-padding`); `max-block` entra al contrato (molde `command.viewport-max-block`). Artefactos y gates: - Sonda antes/después = 0 diffs en 6.090 valores × 7 estados. Determinismo verificado: dos corridas del mismo código, 0 diffs. - R-5.4: 37/38 tokens mueven un computed. `invalid-border` adjudicado EN EL LEDGER con su razón medida (la demo arranca con su control en off; activado a mano alcanza: oklch(0.9555 0.0207 13.86) → rgb(1,2,3)). - censo --only 85 % · component:audit PASS (R-5.3 incluida) · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos (el único es el conocido skin-media-player) · rtl:check 0 · docs:check 0 · check por fichero limpio (72 globales, ninguno mío). - README con su «Talla y tema» y tab `Tokens` en la demo (38 claves, leídas en vivo). El tab `Recipe` documentaba la regla retirada: corregido. Las fichas de calendar / carousel / command / month-grid / range-calendar / table / year-grid entran porque `--report` regenera el informe entero: sólo actualizan NÚMEROS DE LÍNEA de commits ya hechos que no lo regeneraron. Cero cambios de alcance. Las otras 161, que sólo cambiaban la fecha, se revirtieron. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
},
uix(tree-view): temable — 0 % → 92 %, y el velo que tiñe la carpeta entera 46 claves en el bloque `tree-view` de `recipes/base.ts` (fusionadas con el forward de paleta). Censo 0 % → 92 %, cero globales. Global 46 %, sin contrato 47 → 46. Molde del hermano `tree-grid` allí donde el problema es el mismo. LA PROPUESTA GENERADA FALLABA EN EL NOMBRE DE CASI TODO LO QUE IMPORTA: el clasificador toma el PRIMER selector de cada regla como si fuera la parte pintada, y aquí ese primero es el root o el branch-control cuando el nodo real es otro. 1. `root-width: 1px` / `root-bg` NO son del root: son la GUÍA de indentación (el `::before` del branch, una línea vertical). → `guide-width` + `guide-fg`, literalmente los nombres de tree-grid. Un `root-bg` que tiñe una línea es la clase de nombre que miente. 2. `branch-control-padding-inline-{k}` ⚠ fundía DOS ejes que se SUMAN en el mismo calc: el ritmo de la fila y el PASO DE PROFUNDIDAD (`--tree-depth × indent + padding`). Fundidos, tematizar la sangría habría movido el padding. → `row-padding-inline-{k}` + `indent-{k}`. 3. El prefijo `branch-control-` es erróneo: la regla reza `[data-tree-view-branch-control], [data-tree-view-item]` — las DOS filas. El CSS ya llamaba `row` a sus privados. → `row-*`, como tree-grid y como la lección de table. Y fuera el prefijo `root-` del chasis: el wrapper ES el componente. 4. `row-padding-block` ⚠ no eran dos valores en pugna sino cinco por talla: xs colapsa a `0`, las otras cuatro `--space-1`. 5. `branch-indicator-width` + `-height` son UN knob (`1em`) → `branch-indicator-size`. Bundle: la altura de fila casa 1:1; padding e indent llevan ritmo propio; la tipografía un paso por debajo desde lg — verbatim, como table y tree-grid. Los resueltos con `parts: ['root']` (el `data-size` va en `[data-tree-view-root]`, wrapper de eidos, no parte del morfo). Los `transparent` de outline/ghost y el `padding: 0` de ghost son identidad de variante y siguen literales. `hover-row-bg` SÍ se acuña, al revés que en grid-list, y por medición: la misma regla pinta dos nodos con arquetipo distinto, y `branch-control` NO lleva archetype — ahí el plano de la receta es la única pintura (velo medido ausente) y el token es toda la superficie de tema del hover. Tener un consumidor legítimo es lo que lo distingue del caso grid-list. EL DEFECTO QUE LA MEDICIÓN DESTAPÓ (preexistente, NO se toca aquí → next-features §12.8): al pasar el ratón por la fila de una carpeta abierta se tiñe LA CARPETA ENTERA, hijos incluidos. `archetype: 'item'` está declarado en el `<li>` branch (`morfo/components/tree-view.ts:103`), que contiene el control Y todo el `branch-content`, mientras la fila que el usuario señala es el `branch-control` de dentro: el nodo velado mide 336 px frente a los 36 px de la fila — medido y capturado. Un branch anidado acumula además el velo de sus ancestros, así que sus filas se ven más oscuras que las hermanas. Mover el arquetipo es morfo y mueve píxel en toda la demo. Es la TERCERA variante de la misma familia: table lo tiene en fila Y celda, grid-list en fila Y celda sobre el mismo nodo, y tree-view en un ANCESTRO del nodo señalado. Artefactos y gates: - Sonda antes/después = 0 diffs en 8.062 valores × 7 estados. - R-5.4: 45/46; `disabled-row-fg` adjudicado en el ledger (la demo monta CERO filas deshabilitadas, contadas; forzada alcanza oklch(0.61 0 0) → rgb(1,2,3)). - censo --only 92 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos (el conocido skin-media-player) · rtl:check 0 · docs:check 0 · check por fichero limpio (72 globales, ninguno mío). - README con su «Talla y tema» y tab `Tokens` en la demo (46 claves, en vivo). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
'tree-view': {
'disabled-row-fg':
'no disabled row in the demo (0 mounted, counted); forced data-disabled → reaches (oklch(0.61 0 0) → rgb(1,2,3))'
},
uix(textarea): temable — 0 % → 80 %, y el contador que casi pierde su 0.85 37 claves en el bloque `textarea` de `recipes/base.ts` (fusionadas con el forward de paleta que ya estaba). Censo 0 % → 80 %, con **cero globales y cero literales de valor**: los 16 privados leen ya su público. Global 46 %, sin contrato 48 → 47. LO QUE LA MEDICIÓN CAMBIÓ. La §4 generada proponía 35 tokens; cuatro eran colisiones y uno habría movido el default: 1. `count-font-size-{k}` × 5 BORRABA el factor 0.85. El CSS calcula `calc(var(--_textarea-font-size) * 0.85)` y la propuesta ponía el tipo del input crudo en las cinco tallas: el contador habría crecido un 18 %. D-TH.5 lo prohíbe. Queda en UN token con el `calc` sobre el público del input — la escala se escribe una vez y la talla la resuelve el input. Pide `scope: 'host'`: emitido en `:root` su dependencia no existe, y el contrato de scope de la receta lo caza (lo cazó). 2. `input-fg` ⚠ eran DOS knobs (texto y placeholder) → `input-fg` + `input-placeholder-fg`. Igual `count-fg` → `count-fg` + `overflow-count-fg`. 3. `input-border` ⚠ NO eran dos knobs sino UNA variable con su swap de paleta, y el nombre estaba mal: es el borde de FOCO → `focus-input-border`. El de reposo es otro token, que la propuesta ni listó por viajar en el atajo. 4. `ghost-input-border` se RETIRA: la regla ghost lee ese mismo conmutador — sería un valor con dos nombres. Bundle, medido: la tipografía casa 1:1 en las cinco (lee `--size-{k}-font-size`); el spacing NO — `padding-inline` casa salvo en xs (8px vs 6px) y `padding-block` sólo en xs. Verbatim y documentado: un campo multi-línea respira más, y el spacing queda fuera del guard del bundle. Resueltos sin `parts` (el `data-size` va en `[data-textarea]` y el input hereda); fuera los cuatro `[data-size]`. DOS ARREGLOS DEL INSTRUMENTO, los dos por medición y no por sospecha: - **El guard medía con el PUNTERO encima.** `reopen()` corre antes de CADA token y hace clic en `[data-{c}-input]` cuando el componente no tiene parte `content`; el `blur()` de la revisión adversarial quitaba el foco pero no el puntero, así que `:hover` casaba toda la corrida y toda regla de hover pisaba a sus vecinas. Costaba TRES falsos negativos aquí. Con `mouse.move(0,0)` tras cada blur, `input-border` revive solo (31 → 32). - **`::placeholder` SÍ se lee con `getComputedStyle`.** La nota de §13 que decía lo contrario nunca se comprobó; medido, el color centinela vuelve tal cual. Entra en el snapshot (32 → 33) y deja STALE la entrada `command.input-placeholder-fg`, que el guard señaló y se ha borrado. Corridos los DIEZ componentes con ledger tras los dos arreglos: ningún otro cambia, un único STALE, el previsto. Y un hallazgo de píxel que NO se toca aquí (→ next-features §13): el borde de foco sólo se ve con Tab. Las tres reglas de `border-color` del input están ordenadas al revés de lo que significan — hover (0,4,0) > foco (0,3,0) > invalid (0,2,0) — y hacer clic deja el puntero encima por definición, así que gana el hover; un campo inválido pierde su borde rojo al enfocarlo o al pasar el ratón. El anillo de foco del sistema sí se ve siempre, así que no es fallo de accesibilidad. Arreglarlo mueve píxel. El 20 % que falta son las dos declaraciones que consumen `--_textarea-border-focus`, privado a propósito: es el conmutador de una variable con dos fuentes (el público y el forward THM-2), y aplanarlo exigiría duplicar la regla por color. Mismo techo que `listbox` paga por consumir bien su capa. Mi propio veredicto predecía ~100 % y la medición lo corrigió a 80 %. Artefactos y gates: - Sonda antes/después = 0 diffs en 1.247 valores × 8 estados (el 0.85 intacto, que era el riesgo). Determinismo verificado: dos corridas, 0 diffs. - R-5.4: 33/37; los 4 mudos adjudicados en el ledger con su medición (foco, invalid y las dos del contador rebasado — estados que la demo no monta). - censo --only 80 % · component:audit PASS · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos (el conocido skin-media-player) · rtl:check 0 · docs:check 0 · check por fichero limpio (72 globales, ninguno mío). - README con su «Talla y tema» y tab `Tokens` en la demo (37 claves; el panel muestra el contador computando `calc(calc(1rem * 1) * 0.85)`). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
textarea: {
'focus-input-border':
'consumed only under [data-focused], which the guard blurs away ON PURPOSE (the click-focus poisoning fix); focused by hand with the pointer parked → reaches (rgb(4,5,6))',
'invalid-input-border':
'consumed only under [data-invalid]; the demo boots valid. Forced by hand 2026-08-21 → reaches (rgb(7,8,9))',
'overflow-count-fg':
'the count only carries [data-overflow] past maxLength (280 chars); forced → reaches (rgb(13,14,15))',
'overflow-count-font-weight':
'the count only carries [data-overflow] past maxLength (280 chars); forced → reaches (font-weight 333)'
},
uix(grid-list): temable — 0 % → 85 %, y una selección que nunca pintó 38 claves nuevas en el bloque `grid-list` de `recipes/base.ts` (que ya existía con los dos forwards de paleta: se FUSIONA, no se añade un segundo). Alcance del censo 0 % → 85 % (22 de 26 puntuables); global 45 % → 46 %, sin contrato 49 → 48. El eje `size` se estampa en el PROVIDER —el wrapper de eidos no tiene parte `root`—, así que los tres nombres resueltos van SIN `parts`: molde `command`, no `table`/`tree-grid`. Fuera los cuatro bloques `[data-size]` del CSS; los emite el TSC. Altura de fila 1:1 con el bundle, `row-padding-inline` con ritmo propio, y la tipografía un paso por debajo de md en adelante — verbatim, como table y tree-grid. LO QUE LA MEDICIÓN CAMBIÓ (la §4 generada tenía un error de doctrina y dos defectos que sólo aparecieron midiendo; el §5 Veredicto se escribió con la sonda delante, porque estaba vacío): 1. La selección de fila NUNCA HA PINTADO. La receta seleccionaba `[data-grid-list-row][data-selected]`, un atributo que ni el morfo declara ni soma estampa (estampa `data-state='selected'` + `aria-selected`): la regla no casaba jamás y su acento `--_grid-list-palette-element` no llegó nunca al píxel — una fila seleccionada muestra el velo NEUTRO del arquetipo, indistinguible del hover (capturado). Retirada la declaración muerta y su forward huérfano: 0 diffs, que es la prueba. Repararlo mueve píxel y choca con §12.5 (el arquetipo fija también `color`) → §13, espera firma. El acento del checkbox (`_palette-solid`) sí vive y se conserva. 2. NO se acuña `hover-row-bg` aunque la propuesta lo pedía. La fila es `archetype: 'item'`: el velo del sistema la pinta a especificidad plena y el plano de la receta pierde — medido, el hover pinta DOS VECES sobre el MISMO nodo (a diferencia de table/tree-grid, donde velo y plano caen en nodos distintos). Sería un token que no puede ganar; mismo criterio que listbox.highlighted → §12.7. Y fila Y celda llevan ambas `item`, así que bajo el puntero se apilan tres capas. 3. «Consume la capa compartida `menu-indicator`» es FALSO. Sale de `SHARED_LAYERS` (`theming-census.ts:432`), pero esa capa no tiene un solo selector de grid-list, la receta no la importa y soma no renderiza indicator: el checkbox ESPEJA el visual pintándolo por su cuenta. Entrada desviada del censo → §13 (listbox / menubar / navigation-menu están en la misma entrada y tampoco aparecen en el fichero). Nombres, sobre la propuesta: `selection-checkbox-{width,height}` son UN knob → `selection-checkbox-size`; `on-selection-checkbox-bg` → `checked-selection-checkbox-fg` (es la tinta del glifo, y `on-` es prefijo reservado); `border` partido en `border-width` + color (molde `command.input-border*`), que el checkbox comparte; `padding` uniforme se queda `padding` (precedente `command.viewport-padding`); `max-block` entra al contrato (molde `command.viewport-max-block`). Artefactos y gates: - Sonda antes/después = 0 diffs en 6.090 valores × 7 estados. Determinismo verificado: dos corridas del mismo código, 0 diffs. - R-5.4: 37/38 tokens mueven un computed. `invalid-border` adjudicado EN EL LEDGER con su razón medida (la demo arranca con su control en off; activado a mano alcanza: oklch(0.9555 0.0207 13.86) → rgb(1,2,3)). - censo --only 85 % · component:audit PASS (R-5.3 incluida) · eidos-lint invalid 0, class-hooks 0 · suite eidos sin rojos nuevos (el único es el conocido skin-media-player) · rtl:check 0 · docs:check 0 · check por fichero limpio (72 globales, ninguno mío). - README con su «Talla y tema» y tab `Tokens` en la demo (38 claves, leídas en vivo). El tab `Recipe` documentaba la regla retirada: corregido. Las fichas de calendar / carousel / command / month-grid / range-calendar / table / year-grid entran porque `--report` regenera el informe entero: sólo actualizan NÚMEROS DE LÍNEA de commits ya hechos que no lo regeneraron. Cero cambios de alcance. Las otras 161, que sólo cambiaban la fecha, se revirtieron. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
'grid-list': {
'invalid-border':
'consumed only under [data-invalid]; the demo boots with its invalid control off, so the rule never matches at measurement. Toggled by hand 2026-08-21 → reaches (oklch(0.9555 0.0207 13.86) → rgb(1,2,3))'
uix(theming): revisión adversarial de F2-A — 8 hallazgos de 34, y nace R-5.4 Pase escéptico del bloque (§7.7, molde Sidebar) con medición propia: worktree con SOLO el CSS revertido a la base del bloque (DOM de demo constante — prueba más dura que la del autor), sonda x2 por componente para fijar el suelo de ruido. 34 hipótesis · 26 refutadas · 8 reales. Lo que NO se pudo romper: el «default idéntico» aguanta en los ocho (0 diffs; command 8.091 · table 13.050 · media-player 3.277 · gradient-picker 609 · listbox 2.813 · carousel 2.842; los 3 de tree-grid y los 5 de feed salen idénticos corriendo DOS veces el mismo código → instrumento); 0 tokens huérfanos de 336; el bundle ES 1:1 con los primitivos; el «verificado a mano» de gradient-picker era verdad (15/16 alcanzan al montar); sin doble animación; eidos-lint 0 invalid. Los 4 de código, arreglados con diff de computed VACÍO (re-medido: command 8.091 y carousel 2.842 valores, 0 diffs): 1. command: el re-point de `--command-radius` dentro del Dialog era una declaración muerta con comentario falso — la misma regla pone el radio a 0 y el input lee `--command-input-radius`, nunca este token (medido: `--dialog-content-radius: 9999px` no movía NADA; `--command-radius: 77px` movía la paleta inline y no la del dialog). Retirado; comentarios y README reescritos con lo medido. 2. carousel: la regla vertical del indicador activo llevaba el `2.25` a pelo mientras la horizontal leía `active-indicator-scale` — el token alcanzaba media superficie (scale:6 → horizontal 18→48px, vertical 18→18px). Ahora lo leen las dos. 3. carousel: el trío `item-gap*` no podía ganar NUNCA — soma estampa `gap` INLINE desde la prop (lo necesita para el flex-basis; reglas casadas por CDP: la de la receta y encima INLINE gap:0rem). Retirados los 3 tokens y las 2 declaraciones muertas (la base y el gap:0 de ghost): 0 diffs, que es la prueba. Canal de valor de soma, como --gp-current-gradient. Censo carousel 35 knobs · 23 públicos · 77 % · 27 claves; global 43 % intacto (5.190 · 2.102). 4. table: `striped-row-bg` no alcanza NADA en la demo publicada — `:nth-of-type(even)` cuenta los <tr> de RowDetail y las filas de datos quedan impares (medido tr a tr: diez inmunes). Arreglarlo mueve píxel → PENDIENTE DE FIRMA (candidato `:nth-child(even of [data-table-row])`); adjudicado en el ledger mientras tanto. El instrumento cargaba 22 falsos negativos de 26 «no effect», con tres causas medidas, y la cuarta era de la sonda: - el paso de abrir hacía CLIC en el input, y un clic de ratón sobre un input de texto SÍ casa `:focus-visible` — la regla de foco pintaba el borde y el token de reposo leía muerto (era el «falso negativo sin causa» de §13); - el override se escribía solo en `[data-{c}]`, y las partes que cuelgan de `{c}-root` no lo recibían; - `::before`/`::after` eran invisibles (el aro de buffering, el spinner); - la no-determinación de feed no era una animación sin localizar: era la demo aún CARGANDO — el auto load-more mantiene [data-busy] ~3 s y la firma `commit-settle` anima box-shadow sobre el nodo medido. Con la espera de asentado: 0 diffs y 0 nodos ausentes sobre 6.264 valores, dos corridas. Con eso NACE EL GUARD R-5.4 (la deuda que §13 pedía desde gradient-picker, y que carousel convirtió en patrón — un estilo inline de otra capa es invisible para todo análisis estático): `npm run theming:sentinel -- <c> <url>` (scripts/theming-sentinel.ts, promovido de `__`; blur tras abrir, override en todos los nodos del componente, pseudos, pase de hover, settle) + ledger scripts/theming-sentinel-exceptions.ts con UNA razón medida por token — muerto sin adjudicar = exit 1, excepción STALE = aviso. Los ocho componentes en verde: command 50/57 · table 41/45 · media-player 46/61 · tree-grid 45/47 · gradient-picker 9/25 · listbox 20/21 · carousel 26/27 · feed 43/50, con 46 excepciones adjudicadas. El guard ya me corrigió a mí: cinco entradas mías salieron STALE (los control-height-* de media-player SÍ alcanzan) y las borró; y dos muertos nuevos los produjeron los propios arreglos (el blur apaga focus-input-border; el settle desmonta el spinner de feed) — adjudicados con su porqué. Doctrina en recipe-contract §4. También: tres cifras de especificidad de next-features §12 recontadas (la banda de tree-grid es (0,8,0); la tinta seleccionada del arquetipo es (0,4,0); y el `item` de table vive en la fila Y EN LA CELDA — elementsFromPoint pone el velo en la celda), el comentario de listbox que mandaba pisar el privado `--_listbox-max-height` apunta ahora al público, y quedan registrados en §13 los dos `header-z` con literal '2' y el spinner de media-player a 720ms mientras el gemelo de feed lleva tokens. Guards: censo global 43 % intacto · audit --only command+carousel PASS · eidos-lint 0 invalid (command 16/12, carousel 29/9, listbox 12/7) · vitest eidos 434/435 (el rojo es el conocido skin-media-player) · rtl 0/180 · docs 0/813 · check 0 errores en tocados (72 globales de otras sesiones) · prettier limpio en lo nuevo (los desvíos de command.css/carousel.css ya estaban en HEAD y no se tocan). Pendiente de firma (CONTINUE §«PENDIENTE DE FIRMA»): el striped inerte, el arquetipo en fila+celda, y que soma lea el gap de un token. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
}
};

Powered by TurnKey Linux.