# CONTINUE — eje Theming «theme-reach» — **CERRADO 2026-08-25** ## EMPIEZA AQUÍ **EL EJE ESTÁ CERRADO** (gate de F3 rediseñado y en verde el 2026-08-25; sección §«EL CIERRE, EJECUTADO» abajo). Lo que vigila el estado desde hoy no es este documento sino los guards: `theming-reach-floor.test.ts` (newDebt=0 · STALE=0 · reach ≥ 73 % · ≥65 al 100 %), `component-audit` R-5.1/5.2/5.3 en `error`, y el centinela R-5.4. La deuda restante vive NOMBRADA clave a clave en `scripts/theming-census-debt.ts` (1154 entradas que sólo pueden menguar). Trabajo nuevo de theming se abre como entrada nueva de §13/next-features, no heredando de aquí. Las DOS firmas que el cierre dejó pendientes están **EJECUTADAS**: la de los 318 privados no-derivados (§«FIRMA EJECUTADA — los 318» abajo) y la del idioma `var(--{c}-x, fallback)` sin contrato (§«FIRMA EJECUTADA — la ley del espacio cerrado»). Heredada de la segunda queda la re-clasificación de los 117 nombres `--palabras-*` que el censo puntúa `public` siendo canal de VALOR, más DOS deudas nuevas de eje propio que ella misma nombró: el codemod de los 14 canales públicos a `--_{c}-*` — **EJECUTADO 2026-08-26 (14 de 14: 13 en el codemod + el 14.º por firma propia, ver §«FIRMA EJECUTADA — el indicador de navigation-menu»)** — y el cableado `EidosConfig.motion` → CSS (las dos, con su lista, en `next-features.md`). **Lo que sigue pendiente en este carril: el cableado de motion · la re-clasificación de `palabras` · la `timeline` §5 pre-B′.** **El eje ya no tiene cola.** Los 16 componentes que nunca habían pasado están cerrados o adjudicados, la deuda de artefactos está saldada, y **§12.9 y la firma B′ quedaron FIRMADAS Y EJECUTADAS** — las dos decisiones más caras pendientes. Global **73 %** (68 % antes de la clase `structural`, 69 % antes de `bridge`/`channel`), **65 componentes al 100 %**. ## HANDOFF 2026-08-25 (noche) — POR AQUÍ MAÑANA **Las CINCO firmas del eje están EJECUTADAS y pusheadas** (`2daa683fa` file-upload · `df3a4d054` form/compuesto · `2ce43db56` tags-input aria · `1f8ce293b` avatar · `466b24f34` chip/suelo §55). Después cayeron los expedientes de §13: `d5a27b87e` (árbol ARIA de tags-input, cierra F-1) · `3bf7930ba` (el velo no muere por un atajo + pin de chronos, §56) · `318aac207` (la talla de form LLEGA, doctrina anchura-vs-densidad). ### Lo PRIMERO mañana: dos firmas de INSTRUMENTO, en este orden 1. ~~**«La mitad gratis»**~~ — **✅ FIRMADA Y EJECUTADA 2026-08-25** (`047464389`; ver §«FIRMA EJECUTADA — la mitad gratis» justo abajo). Expediente original: scratchpad de la sesión `6314e22b…/scratchpad/bprime/exped/va/informe.md` (1.019 líneas). 2. ~~**La GRANDE: cuatro cegueras + TRES BARRIDOS escalonados.**~~ — **✅ FIRMADA Y EJECUTADA 2026-08-25** (`6392d6003` S1 · `b4dd5a906` S2 · `b9cef9a43` S3; ver §«FIRMA EJECUTADA — la GRANDE» abajo). Se ejecutó exactamente con el plan de VA: tres barridos escalonados, sin fusionar S2 y S3, y la atribución quedó limpia. ### FIRMA EJECUTADA (2026-08-26) — el codemod de los 14 canales (13 de 14) **Qué se ejecutó**: los nombres públicos-con-forma que soma o el envoltorio escriben POR INSTANCIA pasan a privados `--_{c}-*` — el destino que la firma de los 318 ya había firmado (clase `channel`) y que el registro `PENDING_PRIVATE_RENAME` sólo contaba. **Trece renombrados, sus trece entradas del registro RETIRADAS con acta**; el registro queda en **DOS** (no en una): la de motion, que era la prevista, y una PARADA. **El método, y es la mitad del resultado**: barrido `git ls-files` **de cada nombre por el árbol trackeado entero** (94 ocurrencias en 36 ficheros), y flip **ATÓMICO por nombre** — escritor y TODOS los lectores en la misma edición. Nada de grepear los propios patrones: el barrido destapó lectores que ninguna lista traía (el comentario del morfo de `knob`, las dos páginas de demo, nueve menciones en `PLAN-background.md`). **✅ RESUELTO — `--navigation-menu-indicator-h`, con (a) FIRMADA Y EJECUTADA (2026-08-26, tarde).** Estuvo PARADO porque no era un canal suelto: el provider escribe **CUATRO hermanas** en un mismo literal, el README de soma las enseñaba las cuatro bajo `## CSS Variables` como forma controlada por el consumidor (con dos ejemplos leyendo `-h`), y **`-w` era clave DECLARADA del contrato** — la única razón por la que el guard veía a `-h` sola. Ver §«FIRMA EJECUTADA — el indicador de navigation-menu» abajo. **El registro queda en UNA** (motion). **⚠ LA TRAMPA DEL CENSO NO MORDIÓ, y la predicción estaba MAL por un orden de magnitud.** Se esperaba que ~15 knobs pasaran de `public` a `channel` y que el suelo pudiera rozar el redondeo. Medido: **UNA sola clave** se reclasifica —`color-swatch.background`— porque el censo cuenta **knobs de APARIENCIA**, y las otras doce viven en declaraciones de GEOMETRÍA (`translate`, `rotate`, `inline-size`, `grid-template-columns`, `animation-duration`) o en declaraciones que **conservan un público hermano** y siguen puntuando `public` (el `conic-gradient` de `knob` lee `--knob-track-bg`; el panel de `menubar` lee `--menubar-panel-min-width` como fallback). Números: `public` 3074 → **3073**, `channel` 36 → **37**, denominador 4228 → 4227, reach **73 %**, `atHundred` **65**, ledger **1154 · 0 NEW · 0 STALE**. **El suelo NO se toca** — no hubo nada que ajustar ni que fingir. **Neutralidad, medida en dos planos.** Estática: sonda estándar antes/después sobre los 7 componentes, **0 diffs reales**; el único diff (`emoji-picker`, un `background-image` de velo en el trigger, bloque `open`) se **reprodujo 2/2 sobre código idéntico** — ruido del instrumento. ⚠ `color-swatch` **no tiene ruta de demo** (404) y la sonda devuelve **0 nodos**: su «0 diffs» es un guard que no inspecciona nada y NO cuenta como prueba; se midió donde de verdad monta. Dinámica (donde estos canales viven y la sonda no llega), 7/7 por CDP: `background` puntero →`_x −0.7/0.8`, `_y −0.6/0.7`, `_px 15 %/90 %`, `_py 20 %/85 %`, translate `−28px −24px` → `32px 28px` (= x × depth 40px, exacto) y el foco del spotlight `at 15 % 20 %` → `at 90 % 85 %`; el quinto canal (`--_background-progress`) es la rama `@supports not(view())` que Chrome nunca corre, verificada forzando el gate: `0.379 → 1` al scrollear · `knob` accionado por teclado, `_angle −27deg → 0deg`, `_progress 0.4 → 0.5`, el indicador rota igual y la parada del arco `108deg → 135deg` (= progress × sweep) · `color-swatch` tres chips, `#7c3aed/#06b6d4/#f59e0b` → `rgb(124,58,237)` / `rgb(6,182,212)` / `rgb(245,158,11)` · `emoji-picker` privado 9 → 9 tracks, y moverlo a 6 y a 12 da 6 y 12 tracks, **mientras fijar el nombre VIEJO a 3 no mueve nada** (control negativo) · `menubar` panel anclado, `_anchorWidth 886px` = barra 886 = panel 886 · `navigation-menu` (el PARADO) sin regresión, `-h` sigue pública en 36px = altura del trigger activo · `text-gradient` inline `8s` → `animation-duration: 8s` en el hijo `[data-text-gradient-fill]`. **En los siete, el nombre VIEJO computa vacío.** **Guard mutado por sus dos caras**: reintroducir una entrada retirada → **STALE nombrándola**; devolver un nombre público viejo a una receta → **`missing` nombrándolo**. Suites de los tocados 18/18, `component:audit` **162 PASS / 4 NEEDS-WORK** idéntico, `docs:check` **0/0**, `--names` **0 desviadas**, `npm run check` **0 errores atribuibles** (verificado POR FICHERO). **Docs: se ANOTARON, no se reescribieron** — fichas medidas, README de `color-swatch`, `PLAN-background.md` (una anotación fechada cubre sus nueve) y `STUMBLES.md` §7. El nombre nuevo sí se volcó donde el texto describe código VIVO (READMEs de componente y las dos demos). Queda anotada la fila GENERADA `audit/theming/background.md:72`, que la regenerará el `--report` pendiente. **Hallazgo lateral, ajeno**: el control `columns` de la demo de `emoji-picker` es un `` DESNUDO y `slider.svelte` renderiza sólo su provider — un `div[data-slider]` **vacío**, sin raíl ni pulgar. No se puede accionar. ### FIRMA EJECUTADA (2026-08-26) — el indicador de navigation-menu **Qué se firmó**: la opción **(a)** del PARADO. Las CUATRO medidas del trigger activo pasan a privadas — `--_navigation-menu-indicator-{x,y,w,h}`, flip ATÓMICO escritor + todos los lectores, con barrido `git ls-files` por nombre —, **`indicator-w` se RETIRA del contrato** (44 → 43 filas) y la sección `## CSS Variables` del README de soma se reescribe al camino de la casa: el consumidor estiliza **la PARTE** (`[data-navigation-menu-indicator]` y su `data-state`) con los tres pomos de forma, no las medidas. **Lo que se RECHAZÓ, y por qué importa**: (b) declarar `-x/-y/-h` para casar con el README bendeciría como superficie de tema cuatro medidas por instancia — justo lo que la clase `channel` de la firma de los 318 existe para negar. Y se rechazó una especie nueva, **`output`** (tercera clase entre público y privado): abre excepciones sobre una clase barata con frontera de PROSA, patrón ya rechazado dos veces. **`-w` era un token-que-miente, MEDIDO** (CDP, transiciones CONGELADAS — en esta parte `inline-size` va transicionada y una lectura inmediata devuelve el valor VIEJO; el probe informaba «no se movió» de TODO hasta congelarlas): con el subrayado pintado, escribirlo en la raíz del componente —lo que hace el centinela— deja `inline-size` en **107px**, y en `:root` igual; **sólo una regla `!important` de autor llega** (1234px), porque soma escribe INLINE en el elemento. La única ventana donde la declaración asomaba es el indicador montado **SIN rect todavía** (`isOpen` true, `triggerRect` aún null; o `forceMount`): ahí `inline-size` lee el `0px` que daba esta clave y un write en el host lo mueve a 1234px. Es decir, llegaba **sólo donde no pintaba nada**. ⚠ El indicador está montado CONDICIONALMENTE (`{#if state.isOpen || forceMount}`): con la barra cerrada hay **0 nodos** en la página. **Números**: `public` 3073 → **3072**, `channel` 37 → **38**, denominador 4227 → 4226, reach **73 %** y `atHundred` **65** intactos, `--names` 4567 → **4566** (0 desviadas), ledger **1154 · 0 new · 0 stale**. Centinela `navigation-menu` **43/44 → 42/43**, misma única adjudicación (`disabled-trigger-fg`): el total baja porque la clave sale del contrato, no porque nada deje de llegar — **el fichero de excepciones no se toca**. `component:audit` **162 PASS / 4 NEEDS-WORK** idéntico. **Dinámica, que es la que vale aquí** (la sonda estándar es ciega a estos canales): Products `w=107px h=36px` = rect del trigger, Solutions `w=108.5625px h=36px`, `inline-size` las sigue (107 → 108.562) y `left` **0px → 111px** — el subrayado DESLIZA — con `translateY(36px)` estable. **Control negativo**: los nombres viejos computan **VACÍO** en el indicador, y fijarlos en la raíz a 777px/333px no mueve nada. **Control positivo**: los tres pomos del contrato siguen llegando (`block-size` 2 → 9px, `background` → `rgb(1,2,3)`). **Guard**: `PENDING_PRIVATE_RENAME` queda en **UNA** entrada (motion), con acta en el propio registro. Mutado por sus dos caras: reintroducir la entrada retirada → **STALE nombrándola**; devolver `--navigation-menu-indicator-w` a la receta → **`missing` nombrándolo**. **⚠ Trampa del barrido**: el grep del nombre LITERAL es CIEGO a la forma con llaves `--…-indicator-{x,y,w,h}`, que escondía tres menciones más (el comentario de `navigation-menu.svelte` de eidos y dos filas de la demo). Hay que barrer también la familia. **Hueco FLAGGED, no acuñado**: el ejemplo viejo de *píldora / fondo de trigger* no tiene traducción a pomos — la receta clava el `block-size` al grosor. Queda en §13 de `next-features.md`, sin inventar un eje de forma. **Abre expediente**: §14 de `next-features.md` — unificar `tabs` bajo la misma adjudicación (`--indicator-{x,y,w,h}` SIN prefijo, escritos por la capa compartida `MeasuredIndicator`, 2 entradas `global` en el ledger). **EJECUTADA el mismo día**; ver la firma inmediatamente debajo. ### FIRMA EJECUTADA (2026-08-26) — §14, MeasuredIndicator con nombre POSEÍDO **Qué se firmó**: la geometría que una capa COMPARTIDA publica es **canal** y aterriza en el **namespace del ANFITRIÓN** —`--_{c}-indicator-{x,y,w,h}`—, no en uno de capa. Tercera aplicación de la doctrina (`navigation-menu` fue la segunda). **La capa es la PLUMA, no la dueña**: el rect es un hecho de cada instancia del host. Un solo nombre de capa habría repetido el defecto un piso más abajo — una medida por instancia en un espacio que nadie posee. **Cómo llega el nombre**: `MeasuredIndicatorOpts` gana **un** campo, `component: string`, y los dos hosts —los únicos, `git grep "new MeasuredIndicator"`— pasan `tabsMorfo.kebab` / `radioGroupMorfo.kebab`, **nunca un literal**: el canal queda atado a la declaración de morfo que lo posee. **Cableado del CSS compartido** (`lib/sliding-indicator.css`, que no puede deletrear el nombre del host): cada receta declara su alias local explícito —`--_indicator-x: var(--_radio-group-indicator-x)`— y el compartido lee el alias. Forma del puente THM-2, la misma que `calendar-surface.css` usa para `--_calendar-surface-accent`: contrato EN el artefacto. `tabs` no consume la capa (tiene bloque propio) y lee el nombre poseído directo. **Números**: `tabs` **97 % → 100 %** (global 2 → 0, canal 0 → 2; 77 knobs y 79 claves de contrato INTACTOS — ni una acuñada ni retirada). Catálogo `atHundred` **65 → 66**, global 763 → 761, canal 38 → 41, reach global **73 % intacto**, `--names` 4566 · 0 desviadas. Ledger: las **2 entradas de `tabs` retiradas** (la clave entera desaparece), **1154 → 1152 · 0 NEW · 0 STALE**, con acta en la cabecera de `theming-census-debt.ts`. `radio-group` no mueve una cifra. **⚠ La trampa de clasificación, prevista y resuelta**: la regla de canal miraba el privado que el knob lee DIRECTAMENTE con cero declaraciones — una línea-alias es un privado DECLARADO cuya única fuente es el canal, así que la esquivaba y caía a residuo `private` no-derivado, `newDebt` ROJO con la razón equivocada. El tercer paso del censo resuelve ahora el canal **TRANSITIVAMENTE** (molde de `derivesFromPublic`). **Mutación de rigor**: un alias hacia un privado que SÍ está declarado NO clasifica canal — `refs.length > 0` es la línea que lo impone. Y el ORDEN de pasos es carga estructural: el segundo (deriva de un público) corre antes, y por eso `--_tooltip-max-width` sigue siendo público. **⚠ Un knob AJENO se reclasificó, con acta**: `tooltip.css:27` pasó de `exception` a `channel`. **No es regresión**: el comentario firmado de esa declaración ya decía «per-instance VALUE CHANNEL» con esas palabras — faltaba el mecanismo, no el criterio, que es literalmente lo que el cuarto paso del censo dice de sí mismo. `tooltip` no mueve su alcance. Acta en su ficha, §2-quater. **⚠ La sonda estándar es CIEGA a esta clase de firma**: lee valores computados, no nombres de var, así que un flip de nombre correcto le sale idéntico por construcción. Sus **0 diffs en 2528 valores × 10 estados** prueban lo CIRCUNDANTE, no el flip. Quien prueba el flip es la dinámica, y hay que CONGELAR transiciones o `inline-size` devuelve el valor viejo: `tabs` desliza (`translate 0 → 183.719px`, `inline-size 99.906 → 71.359px`, indicador exacto sobre el trigger activo), `radio-group` sólo manifiesta su indicador en la variante **`segmented`** y desliza igual (`4px 32px → 4px 60px`). Los cuatro nombres viejos computan **cadena vacía** en ambos; control negativo en `:root` a cero; control positivo probando además la CADENA del alias. **Hueco FLAGGED, no acuñado**: `--indicator-duration` / `--indicator-ease` siguen bare, sin dueño y sin entrada de contrato — la misma fuga de espacio, una especie más allá (son ranuras de FORMA, no canal). Su puerta es el contrato, no ésta. ### FIRMA EJECUTADA (2026-08-26) — la ley del espacio cerrado **Qué se firmó**: el espacio de nombres público es **CERRADO sobre el contrato** — un `--{c}-*` existe **si y sólo si** `base.ts` lo declara, no hay tercer estado. Corolarios: el fallback es dispositivo de seguridad de VALOR, no escapatoria de contrato; declarada la clave, el fallback inline sobre el nombre público PROPIO muere (el default vive en UN sitio); el guard de fantasmas pasa al «si y sólo si» — un `--{c}-*` propio fuera de contrato es rojo, con o sin fallback. El vocabulario AJENO (préstamo de otro componente) y el de sistema conservan sus reglas: el guard filtra por prefijo propio y no los ve. **Lo que el barrido previo encontró — y por qué importa**: no eran dos componentes. El catálogo tenía **25 nombres propios con fallback fuera de contrato en 10 componentes** (27 sitios), y se parten en DOS CLASES: - **11 knobs de tema de verdad** → declarados: `mockup` ×9, `text-scramble` ×2. - **14 CANALES DE VALOR** que soma o el envoltorio escriben inline por instancia → **NO se declaran** (declararlos revertiría la firma medida del 2026-08-23 que retiró `--color-swatch-fill` del contrato) **ni se renombran aquí** (es codemod de otro eje). Van a un REGISTRO nombrado y fechado dentro del propio test, `PENDING_PRIVATE_RENAME`, con razón y destino por entrada. \+ `--motion-stagger-each-default`, que no es canal (nadie lo escribe): su default pertenece a `EidosConfig.motion`. **15 entradas.** El registro es el patrón ledger de la casa: **no bendice, cuenta**, y **sólo puede menguar** — una entrada que deja de describir un consumo (renombrada, declarada, muerta) se reporta **STALE** y sigue roja hasta borrar la línea. **La mentira que la ley mató, en concreto**: `--mockup-shadow` cargaba DOS defaults bajo un nombre — `var(--shadow-4)` en el marco, `var(--shadow-5)` en el bisel del teléfono — así que un tema que lo moviera no podía saber cuál de los dos tocaba. Se acuñó `--mockup-phone-shadow`: superficie distinta, nombre distinto. El TSC no podía expresarlo de otro modo (sus ejes de scope son cerrados y `data-chrome` no es uno). **Neutra en píxel, medida dos veces**: el diff de `generated/` son esas 11 líneas con su default verbatim y NADA más; y el A/B en navegador — cada token nuevo forzado a `initial` con las declaraciones viejas restauradas inline — dio computed idéntico en los tres mockups de `/blocks/feature-split` (ambos cromos; el bisel conserva `shadow-5` y el marco `shadow-4`, que era justo lo que la acuñación protegía) y en `text-scramble`. ⚠ `mockup` **no tiene ruta de demo propia**: se mide donde de verdad monta, en `/blocks/*`. **Números**: `no contract entry` **18 → 16**; todo lo demás QUIETO — reach 73 %, 65 al 100 %, ledger 1154 · 0 NEW · 0 STALE, audit **162 PASS / 4 NEEDS-WORK** idéntico, `--names` 0 desviadas, `docs:check` 0/0. El suelo NO sube: la ley cerraba un hueco de CONTRATO, no de alcance (esas declaraciones ya puntuaban `public` — lo que faltaba era declarar el NOMBRE). **Muta-prueba de tres caras**: `var(--mockup-inventado, red)` (propio, CON fallback) → **rojo nombrando la clave** · el mismo inyectado con un nombre AJENO y fallback → **verde** · una entrada del registro que deja de describir un consumo → **rojo STALE nombrándola**. **Efecto lateral que hay que saber**: el crudo `var(--primitive-neutral-12)` migró verbatim de `mockup.css:73` a `base.ts` como default de `mockup.phone-bezel`. Sigue siendo deuda R-4.6 — pero la regla escanea CSS de componente y ya no lo ve, así que la fila de `mockup` perdió ese error **sin que nadie lo arreglara**. Queda anotado en la propia clave y en `next-features.md`; `mockup` sigue NEEDS-WORK por su E-2.3 (README ausente). ### FIRMA EJECUTADA (2026-08-26) — los 318 privados no-derivados **Qué se firmó**: la «clasificación de los 318», en tres piezas — `e812d3ffd` (F1: el censo aprende a MEDIR puente y canal) · `a74aeec7b` (F2: el residuo adjudicado clave a clave) · este commit (F3: el suelo sube y la prosa se salda). Cierra el agujero que la cabecera del ledger nombraba: la tercera clase no-alcanzada ya no vive sólo bajo el `reachPct` grueso. **La aritmética, sin resto**: 318 = **132 puente** + **36 canal** + **84 anotados** + **66 al ledger**. Las dos primeras las decide la MEDIDA (el puente contra la salida real de `renderRecipePaletteForward`, no contra la forma del nombre; el canal contra quién escribe el privado — nadie lo declara, lo pone soma o el envoltorio por instancia); las otras dos son actos: la válvula nueva `/* private: */` sobre la declaración (clase `exception`, la de siempre, no un tier nuevo) y una entrada de ledger con `private` como `DebtClass` de pleno derecho, con `newDebt` y STALE simétricos. **Los cuatro números que quedan vigentes**: reach **73 %** (3074/4228 — el numerador NO se movió, cayó el denominador 4480 → 4228) · **65 componentes al 100 %** · ledger **1154** claves (763 global + 325 literal + 66 private) · **162 PASS** en `component:audit`, idéntico. **Las cuatro contradicciones con ficha que la medida destapó** (F2 las dejó señaladas; ninguna se resolvió a ojo): - `metrics` — su §5 firmado decía que el conmutador del icono derivaba ENTERO de públicos. Cierto para `track`/`text`, **falso** para `solid`/`contrast`, que leen roles crudos. Resuelto POR MEDIDA: 3 anotados, 2 al ledger. - `timeline` — su §5 es **pre-B′** y se respetó tal cual (10 knobs, 5 notas). Queda SEÑALADO para reabrir si la escalera de paleta de B′ pesa más que aquel veredicto. - `proof-of-human` — 17 knobs adjudicados por DOS notas, **sin §5 propia** que lo dijera: la base del alias es verbatim la que el forward declara para ese slot (medido dos veces). El alias `--_proof-of-human-accent{,-soft}` es **borrable a coste cero de píxel** — leer el puente directo clasificaría `bridge` sin anotación; registrado como trabajo futuro en §13. - `listbox` — sus 6 knobs (5 notas) dicen «adopto la capa `list-surface`», y son **reversibles** el día que §13 le dé receta propia a esa capa (diez componentes de golpe). ### FIRMA EJECUTADA (2026-08-25) — «la mitad gratis»: cegueras 4 y 5, coste de ledger CERO **Qué se firmó** (`047464389`): las dos piezas del expediente VA que NO compartían el coste caro — el codemod ciego a la IIFE con sus dos hermanos, y los cinco huecos de la sonda más el sexto propio (el pase de FOCO prometido e inexistente). Tres ficheros, **ni una entrada del ledger**. Ejecutada por cuatro agentes (tres constructores + uno ADVERSARIAL con mandato de refutar), con bases capturadas ANTES de editar. **Los números**: centinela `label` 1/2 y `switch` 27/52 **byte a byte idénticos** a las bases pre-firma; sonda de `card` **0 diffs en sus 7 bloques viejos**; `editable` estrena bloque `open` (25 filas, 6 con `data-editing`) y dos corridas sobre código idéntico dan **0 diffs en TODOS los bloques**; `menubar` abre por la entrada del centinela (6 nodos → 7, con el panel) y `chat-message` 24 filas × 2 corridas = 0 diffs; codemod 145/145 bloques, avatar `depth 3` con **97** claves (86 públicas + 11 privadas), laboratorio sobre copias (duplicado inyectado DETECTADO, renombrado = 1 línea); importar el centinela: 0,85 s sin navegador. **Las decisiones que deja escritas**: - `COMPONENT_OVERRIDES` es **UNA tabla**: la sonda la importa y `OPEN_TRIGGER` se poda de sus copias literales. La guarda de entrypoint lleva `realpathSync` — hallazgo del adversarial: sin el realpath muere a través de un junction (exit 0 sin inspeccionar nada), y este repo usa worktrees con junctions. - La vía de carga del codemod **SE QUEDA en tsx**: «el censo corre con node pelado» era FALSO (todo `src/uix/morfo` importa sin extensión). - `prepareWith` en la sonda sólo corre sin fila en `DEMO_VARIANTS` (re-clicar APAGA los checkboxes que `prepare()` ya encendió) — y eso deja a la vista la deuda de `search-field` (§13). - El no-determinismo de `chat-message` quedó ACOTADO al bloque `rest` de la sonda (13 vs 16 nodos, chips sin cuajar al medir) — dato para la GRANDE. **Lo que quedó fuera, con su registro en §13**: el barrido de variantes de la sonda (ensanche diferido por el propio expediente) · el clear-trigger de `search-field` en el pase `open` · la asimetría de escenario de los seis con `prepareWith` sin fila · el cortocircuito `alreadyOpen` que la sonda no tiene · y **TRES lectores independientes** de la estructura de `base.ts` (codemod, censo, centinela — la próxima forma nueva se enseña tres veces). El `catch` del `prepareWith` del CENTINELA sigue MUDO **a propósito**: es la ceguera 6, S1 de la GRANDE. ### FIRMA EJECUTADA (2026-08-25) — «la GRANDE»: el guard deja de estar ciego, en tres barridos **Qué se firmó** (`6392d6003` · `b4dd5a906` · `b9cef9a43`): las cegueras 6+1+3+2 del expediente VA, UNA firma, TRES barridos del ledger ENTERO (91 componentes cada uno), ejecutada con el mismo esquema de agentes que «la mitad gratis» (tres constructores en serie + adversarial con mandato de refutar: **12/12 claims confirmados**). - **S1** — el `prepareWith` GRITA (lo que cae en su catch es un control que estaba y falló — la fuente de las muertes fantasma) y el STALE ve los PATRONES (`reasonFor`, mensaje que distingue «retira la exacta» de «ESTRECHA el patrón»). Barrido: 91/91 verdes, 40,8 min, 0 avisos. Cosecha: los dos patrones `PLANE_SUPERSEDED` de `toast` (18 claves), rancios desde la noche de §12.9, RETIRADOS con 3/3 de reproducción. - **S2** — el chooser tipa la sonda por el VALOR por defecto leído de `base.ts`, no por el nombre (357 claves cambian de sonda; 320 de la clase A «vivo por accidente» IACVT). MONÓTONO medido: 91/91, sólo `avatar` +1 y `stepper` +1, sus dos exactas retiradas. Ni `%` ni enteros se clasifican (tipar el `0` habría matado en falso 7 claves vivas). - **S3** — tono+estado: tono en el pase de hover · tono MEDIAL `(^|-)` (las 16 de `tag-group`) · hover para claves de tono muertas (las 21 de `file-upload`) · seis ejes de estado como DATO, valores del morfo/receta/DOM real. Barrido: 91/91, 43,8 min, exactamente los 9 previstos, **+140 claves (catálogo 2776 → 2918, 78 % → 82 % de claves vivas)**. **130/132 `TONE_UNREACHED` reviven; las 2 que no eran `PALETTE_FLOOR`** (el tono HOST por defecto — test de dos caras en checkbox y radio-group, firma idéntica en los ocho componentes). **El ledger después**: 10 patrones retirados + 2 estrechados + 7 exactas retiradas + la constante `TONE_UNREACHED` RETIRADA (la muerte que su docstring pedía). Tier de patrones **28 → 16, 15 de los 16 son el único hecho `PALETTE_FLOOR`**, y el adversarial verificó que los 16 cubren SOLO claves muertas — cero zombis — y que ninguna clave muerta quedó sin razón (659 muertas, 0 sin adjudicar). **Dos correcciones al expediente, reproducidas dos veces antes de tocar**: las `-text` de `tags-input` SÍ reviven (la causa del arquetipo sólo tapa el ítem RESALTADO; la escena no tiene ninguno, y el token pinta además dos nodos hermanos fuera de esa regla) · `tag-group.hover-item-fg` la callaba su `data-state='selected'` nativo — el nodo es un `` que ninguna regla de arquetipo toca. **Deuda nueva registrada en §13** (adversarial, ninguna bloquea): la asimetría del estampado (`data-color` en TODOS los nodos vs sólo el proveedor en producción — medido que NO es la causa de ninguna revivida) · el ternario falsy de la restauración de atributos (un `attr=""` se borra en vez de restaurarse; hoy inocuo) · `checkbox.stroke-ease` con sonda de color (única de las 51 de easing) · el residuo del recorte del hover (`button.palette-element`, escrito en su propia razón). ### EL CIERRE, EJECUTADO (2026-08-25) — deuda B + clase `structural` + R-5 a `error` con LEDGER **✅ EJECUTADO** con el mismo esquema de agentes (tres constructores + un adversarial que confirmó 11 claims y refutó dos números de prosa). Cinco commits: `2c61946fb` (clase `structural`) · `ef47f3447` (deuda B) · `69d69d43c` (el ledger de deuda) · `1ba518fcc` (correcciones del adversarial). - **Deuda B saldada**: `proof-of-human` (20 claves derivadas) · `audio-player` (README nuevo; es un skin sobre media-player que consume sus 61 claves y añade 8; sin demo propia a propósito) · `palabras` (sección honesta SIN tabla: sin contrato en `base.ts`, y sus 117 nombres `--palabras-*` son la proyección del `scheme-style` del documento — canal de VALOR, otro eje; la clasificación del censo sobre él queda EN CUESTIÓN, §13). - **Clase `structural`**: los cinco 0 %-por-naturaleza (`aspect-ratio` · `text-blur` · `cascade` · `motion` · `date-picker`) salen del denominador con su razón EN el artefacto (forma `LAYER_VOCABULARY`). Reach 68 → 69 %, no-contract 23 → 18, el gate deja de ser inalcanzable por construcción. - **R-5 a `error` con LEDGER DE DEUDA — la firma que rediseñó F3**: la deuda real (1088 claves: 763 global + 325 literal, carriles WIP DENTRO) se registra UNA vez por clave en `scripts/theming-census-debt.ts` — deuda registrada, NO excepciones; la válvula sigue intacta y nunca ciega el ratchet. R-5.1/5.2 a `error` contra el ledger (R-5.3 ya lo estaba): deuda nueva = rojo NOMBRADO, entrada rancia = STALE hasta borrarla. Los techos burdos del suelo RETIRADOS (el ratchet es por clave); `atHundred` corrige su criterio (`public > 0`, 14 → 45). El gate de F3 queda redefinido honesto: **«censo 100 % ADJUDICADO»** — y está EN VERDE. - **Pendiente de TU firma, nombrado en §13 y en la cabecera del ledger**: ~~los **318 privados no-derivados**~~ — **✅ FIRMADA Y EJECUTADA 2026-08-26** (`e812d3ffd` · `a74aeec7b` + F3; ver §«FIRMA EJECUTADA — los 318» arriba) · ~~el idioma **`var(--{c}-x, fallback)` sin contrato**~~ — **✅ FIRMADA Y EJECUTADA 2026-08-26** (§«FIRMA EJECUTADA — la ley del espacio cerrado» arriba) · QUEDA la **re-clasificación de `palabras`** (117 nombres `--palabras-*` puntuados `public` que son canal de VALOR) y las DOS deudas de eje propio que la ley nombró (14 canales → `--_{c}-*` · cableado `EidosConfig.motion`), ambas detalladas en `next-features.md`. · Deuda menor registrada: las fichas de `docs/audit/theming/` esperan un `--report` supervisado post-`structural` (tarea aparte). ### FUERA del carril de theming (registrados HOY, no se ejecutan desde aquí) - **E1 — los botones del array de form COMPONEN el Button** (clase A-112): expediente completo de VC en `exped/vc/` + la corrección de E-talla: E2 ahorró el CONTEXTO pero no la LECTURA — E1 debe pasar `size` al Button que inyecte o es la regresión medida (26→36 px en xs). Y las partes son MUDAS (morfo sin evento; verbos canon: `commit-set-add`/`commit-remove`). - Lo abierto por el ARIA: `tag-group` filas SIN celdas (el «precedente» refutado midiendo) · `search-field` F-1 · la regla del censo de citas APG. - El párrafo anchura-vs-densidad querría vivir TAMBIÉN en `reference.md` junto a la norma tapada (dicho por E-talla, fuera de su alcance). ### Las leyes que dejó el día (sesión 2) - **Una interrupción del autor MATA a los agentes en vuelo** — informe.md a disco INCREMENTAL siempre; el disco sobrevive (V1 se recuperó íntegro). - **El supervisor MIRA las capturas antes de cada commit** (regla del autor). - **Las demos del sistema NO entran** ni como prueba central de una firma (reafirmada sobre la captura del velo; la prueba citable es el barrido de las 14 identidades del catálogo). - **F5 compartidas se RETIENEN y liberan EN SERIE** cuando varios ejecutores comparten `next-features`/`CONTINUE` — tres ejecutores hoy, cero pisadas. - La sonda estándar ganó DOS mentiras registradas (se pisa el `data-size` forzado sobre nodos compuestos · los `clamp()` fluidos no comparan sin declarar viewport) — están en §«Lo que el instrumento aprendió». Lo que queda de firma vieja NO cambia: la lista «Lo que espera TU FIRMA» de más abajo quedó VACÍA el 2026-08-25 y las entradas EJECUTADAS de hoy están intercaladas tras esta sección. ### FIRMA EJECUTADA (2026-08-25) — el velo del sistema no muere por un ATAJO **Qué se firmó** (changelog §56, reverso de §55 el mismo día): al bajar el sobre de trigger de `popover.css` al suelo, §55 lo dejó a **(0,0,0) — el mismo peldaño que `archetypes.css`**, que es quien pinta el velo de estado del sistema. Y el suelo declaraba su superficie con el ATAJO `background:`, que expande a `background-image: none` — **la propiedad exacta donde vive ese velo**. Resultado: el velo de hover de todo trigger desnudo dependía de qué hoja cayera después. No sólo por la regla de hover: el `:where()` deja también la de REPOSO empatada con la de hover del arquetipo, y ésa sola bastaba. La corrección son DOS PALABRAS — `background-color:` en `popover.css:60` y `:75`. **Los números**: **0 px** en el barrido de las **14 identidades del catálogo** que montan un `[data-popover-trigger]` (68 lecturas en reposo → 0 movidas, 68 en hover → 0 movidas, `rules split=2` en las 14) con control negativo diff 5 / 4; las dos sondas del eje a **0 diffs** (`popover` 448 valores / 8 estados, `chronos` 36 832 / 7); y **el velo sobrevive al orden invertido**, donde con el atajo moría (`linear-gradient(…8 %…)` → `none`). Cae con la firma el pin `chronos.css:417` (cinco declaraciones a (0,3,0) que ya no defendían nada): **0 diffs en 20 combinaciones `variant` × `size`**, control negativo 20/20 — §13 lo había adjudicado mal, al velo del `+N more` lo mata `button.css:69`/`:88`. Guarda §55 apartado **(f)** en `active-eidos-config.test.ts`, **4 mutaciones / 4 mordidas** (las dos primeras muerden la mitad positiva, las dos segundas —el atajo AÑADIDO junto al longhand— la negativa). **Lo que quedó fuera, con su número en `next-features.md` §13**: el residuo `transition` del MISMO empate (suelo `background, border-color` vs arquetipo `opacity, background-color`, las dos a (0,0,0) — hoy el `border-color` del hover de popover salta en vez de animarse), la decisión de producto «popover deja de declarar hover propio» (no es coste cero: 0.9821 → 0.931 **más** el velo hoy, sólo el velo después) y `calendar-select.css:14`, que **no es un pin** — retirarlo rompe el tipo en 3 de 4 tallas (12 / 14 / 20 → 16 px). **Fichas y prosa saneadas**: `chronos.md` (censo 202→198, propuesta 50→47, en bloques `` para que sobrevivan a `--report`), `calendar.md` (su ⚠ HALLAZGO «no determinista» lo cerró §55 y ya no apunta a §13), `emoji-picker.md` y los tres comentarios de código que seguían afirmando **(0,2,0)** del sobre (`emoji-picker.css`, `gradient-picker.css` —sólo su mitad base, la de estados sigue viva— y `lib/recipes/base.ts`). Se ANOTAN, no se reescriben: cada medida fue correcta con la cascada de su día. ### FIRMA EJECUTADA (2026-08-25) — el eje `size` de `form` LLEGA a sus acciones **Qué se firmó**: ceder el cromo de `submit`/`reset` al `Button` compuesto (firma del 2026-08-24) destapó el reverso. `form-submit.svelte:20` y `form-reset.svelte:15` traían su propio `size = 'md'` y **nada les pasaba la talla del formulario**, así que un `
` los renderizaba con `data-size="md"` —36 px de alto y 16 px de letra— **en las cinco tallas**; del eje sólo sobrevivía el `row-gap`. Quitar el default no arreglaba nada (el `Button` tiene el suyo): hacía falta el puente, y el precedente es literal. Nuevo `eidos/components/form/context.ts` calcado **1:1 de `toolbar/context.ts`** (`Symbol('form-eidos-ctx')` + getter de propiedad), `form.svelte` publica el `resolvedSize` que ya calculaba, y las dos acciones leen `size={size ?? form?.size}` — la prop explícita gana, y standalone cae en el `md` del propio `Button` sin re-declararlo. **Sólo eidos: cinco ficheros, cero morfo / soma / sema; el contrato de 64 claves y el ledger, intactos.** **Los números**: alto **−10 / −6 / 0 / +8 / +16** px y letra **−4 / −2 / 0 / +4 / +12** px, sobre `submit` y `reset` por igual; **`md` no mueve un solo valor**; 84 diffs en total y **cero** en los cuatro nodos del array, el widget y el resumen de errores. Sonda estándar antes/después **0 sobre 832 valores en 7 estados**; instrumento propio reproducible (dos pasadas sobre código idéntico ⇒ 0 diffs). `vitest src/uix/eidos` 443/444 (el rojo es el ajeno conocido `skin-media-player`), `check` 0 errores atribuidos a los cinco ficheros, `docs:check` 0/0. **La doctrina que hubo que adjudicar**: **VERBATIM, no la norma tapada en `md`**. La tapa de `reference.md` §«Container→part derivation» gobierna contenedores cuyo eje es ANCHURA (su primer consumidor es `Dialog.Close`); el de `form` es DENSIDAD declarada, y su propia receta ya había escrito los cinco peldaños distintos de la acción. Escrita en `next-features.md` §13 §«Anchura vs densidad», con el corolario de que a `alert-dialog` —mismo agujero, eje de anchura— le toca la TAPADA. **Lo que quedó fuera, con su entrada en §13**: `alert-dialog` (no medido), `Form.ErrorSummary` con un `data-size` que ninguna regla lee, la escalera de fuente `12·12·14·14·16` de la acción de `form` (que corrige E1 en su carril) y la cita colgada de `dialog/context.ts:9`. ### FIRMA B′ EJECUTADA (2026-08-24) — la cascada de paleta es una ESCALERA **Qué se firmó**: los tres escritores de `--{c}-palette-*` pasan a tres peldaños que **no empatan** — suelo `:where([data-{c}])` `(0,0,0)` < forward `[data-{c}]:where([data-color], [data-color-custom])` `(0,1,0)` < tono `[data-{c}][data-color='X']` `(0,2,0)`. Antes el forward genérico se emitía el ÚLTIMO empatado a `(0,2,0)` con los bloques por tono, así que **ganaba por orden de emisión** y 419 claves públicas de tono en 49 recetas no pintaban nunca. **Por qué B′ y no reordenar la emisión** (que es lo que §13 proponía): el orden es **contrato invisible** —no se lee en el artefacto, no lo verifica un guard sin recorrer la hoja entera, se rompe moviendo una línea—. La especificidad es **contrato EN el artefacto**. Y es la misma ley que §12.9 acababa de firmar para el plano de profundidad: **una doctrina aplicada dos veces**, no dos parches. **Los números**: neutra en píxel sobre **~297.000 valores computados** comparados antes/después (70.912 + 34.336 planos en dos lotes, 57.720 en el tercero, 134.464 con los tonos ESTAMPADOS en las 49 unidades) — **0 diffs reales**, y los 17 crudos probados ruido reproduciéndolos sobre código idéntico. **207 de 353 claves** de tono volvieron a mover un valor computado. Guarda por **mutación** en `active-eidos-config.test.ts:1761` (6 mutaciones, 6 mordidas; cierre estructural: toda declaración de paleta vive en uno de los tres peldaños; anti-vacío `> 40`). Contrato del forward **ensanchado de 2 a 49 recetas** — vigilaba sólo las de paleta pública y era ciego a las 47 privadas. Suite 35/36 (el rojo `skin-media-player` es AJENO y conocido). **Dónde vive todo**: doctrina en [`theming/changelog.md`](../theming/changelog.md) §53 · contrato en [`theming/reference.md`](../theming/reference.md) (bloque THM-2) · emisor `src/uix/eidos/lib/render-css.ts` (`isPaletteSlotToken` parte el bucket host — **sólo las ranuras de paleta bajan**, el chasis se queda a `(0,1,0)`) · guarda `active-eidos-config.test.ts` · ledger `scripts/theming-sentinel-exceptions.ts`. **Tres leyes que deja escritas, y las tres costaron una medida**: 1. **El silencio del guard NO es señal cuando la adjudicación es por PATRÓN.** `theming-sentinel.ts` detecta STALE sólo contra el ledger EXACTO (`k in ledger`), nunca contra `SENTINEL_PATTERN_EXCEPTIONS`. Las 207 claves resucitadas no dispararon ni un aviso: el estrechamiento hubo que hacerlo comparando a mano contra las 13 entradas. La única que el guard sí vio fue `editable.risk-border`, que era exacta. 2. **Un tono por defecto ESTAMPADO resuelve por el forward, no por el suelo.** El envoltorio estampa `data-color` en toda instancia, la default incluida, así que `