You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/process/CONTINUE-blocks.md

875 lines
56 KiB

uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
# CONTINUE — tier blocks (handoff, act. 2026-08-19 · A-111 cerrada)
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Estado**: F1 CERRADA (8/8) · F2 CERRADA (15/15) · F2b CERRADA ENTERA ·
**F3 ABIERTA — F3.1 `app-shell` CONSTRUIDO, VERIFICADO Y REHECHO**, con su fase
0 firmada (Q1–Q4) y el canon `SkipLink` nacido delante de él.
uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**A-111 ARREGLADA** (el landmark anónimo de `NavigationMenu`), con guard de
censo y párrafo de doctrina detrás.
**19 blocks vivos**: site-header · hero · feature-grid · feature-split · pricing ·
feat(blocks): contact CERRADO — la coordinacion entra en el contrato B El estado se le pregunta al ESQUEMA, no al Form. `form.isValid` con `validationBehaviour: 'progressive'` significa «aun no se ha encontrado nada mal»: un formulario vacio e intacto no tiene errores, asi que se declaraba valido y `incomplete` era INALCANZABLE al cargar — la seccion pedia resolver la verificacion con los tres campos vacios, justo el hueco que la doctrina existe para cerrar. Ahora la raiz valida los valores con `validateSync` de SIUM: sincrono y sin escribir errores (`form.validate()` habria encendido los tres campos en rojo en el primer frame). `state.test.ts` fija la maquina con 9 casos — primer test unitario del tier, porque `state.ts` es su primera logica pura: el orden de prioridad, que solo `ready` deja enviar, y que todo estado bloqueado tiene frase. Contrato B (architecture/blocks.md): seccion «Coordination» con las tres cosas que posee un block que coordina (estado, forma de sus datos, palabras), B-5 admite el esquema por defecto, B-7 enmendado (posee las palabras de SUS estados como idlangref con fallback ingles) y la convencion de servicios acotada: el traductor es el UNICO servicio sancionado. Dice tambien a quien NO aplica — los blocks de layout no coordinan nada. i18n por la via real: el arnes registra el namespace `blocks` en las DOS cadenas de arranque (galeria y previews, que duplican el boot) y la demo se lee en castellano en vez de caer al fallback ingles. Ademas: README y pestanas de doc rehechos al reparto nuevo, ficha F2.13 y bitacora en PLAN-blocks.md, y el control vivo que faltaba para un prop publico — `verification` con reto / sin reto, porque omitir el prop no es lo mismo que pasar un estado que nunca verifica. Verificado en navegador, arco completo y las dos ramas: sin reto vacio → un campo → tres campos (se desbloquea) → «Enviando…» → «Enviado»; con reto, con los tres campos llenos el boton sigue bloqueado y la razon pasa a «Resuelve la verificacion de arriba». `verifying` y `rejected` quedan cubiertos por test unitario, no por el reto en vivo: el provider de ProofOfHuman escribe `status` el mismo y el veredicto del app no se sostiene (hilo de canon abierto). Gates: blocks:check verde (14 blocks) · vitest 9/9 · docs:check 0 · svelte-check sin errores propios · prettier limpio en los ficheros propios. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
testimonials · faq · stats-band · cta · newsletter · site-footer · banner · team ·
contact · content-section · logo-cloud · article-grid · cookie-consent ·
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**app-shell**. Más la página compuesta `/blocks/landing`.
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**A-95 CERRADA** con `app-shell`: solape del aviso sobre la cabecera **0px** y
hit-test dentro de la cabecera, medido (antes: 49px).
## Por dónde entrar mañana
uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 1 · ~~A-111~~ — **CERRADA 2026-08-19**. Lo que dejó, y lo que abrió
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
El nombre del landmark vive ya en el `<nav>`. Medido con el árbol AX de Chrome:
`/blocks/app-shell/preview` → `navigation: ['Navegación principal', 'Menú de la
aplicación', 'Migas de pan']` (el `null`, fuera), y la demo del componente sin
label del consumidor → `'Principal'`, el default del morfo traducido sobre el
landmark. Detalle y método en `AUDIT-blocks-ledger.md` §A-111.
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Tres cosas que conviene saber al retomar:
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **La forma ejecutada corrige el paso 1 de la disposición**: la lista NO hereda
el nombre por `aria-labelledby`, se queda sin nombre. Los morfos hermanos con
`defaultElement: 'nav'` lo dijeron — `breadcrumb` y `nav-tree` declaran
`aria: []` en su lista. `navigation-menu` era el único fuera de esa forma.
- **Guard nuevo**: `src/uix/morfo/landmark-census.test.ts` — toda parte con
`defaultElement: 'nav'` declara un attr de nombre EN SU PARTE, probado en rojo
por mutación tres veces. Ámbito `nav` a propósito; **`aside` es el candidato
natural a ensanchar el censo** y no se hizo sin firma.
- **Y destapó A-116**: `palabras.breadcrumb` es la misma clase (un `nav` con
`aria: []`, sin nombre en soma ni en eidos). **Excepción firmada** en el censo
— palabras es el eje de otra sesión y su rama es compartida.
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️ La doctrina ganó el párrafo que no existía (`architecture/morfo.md` §Step 4,
«A landmark is named on ITS OWN element»). Antes de esto la regla no estaba
escrita en ningún sitio: grep de `landmark` en `morfo.md`, `canon/` y `guides/`
daba cero.
uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 2 · Las filas que dejó el `app-shell` (ledger, todas nuevas)
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| Fila | Qué | Estado |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| **A-112** | `Toolbar.Button` tipa contra el `ButtonProps` de SOMA, así que no acepta `variant`/`color`: un cluster no puede decir cuál es su acción principal. Dos salidas en la ficha, hay que elegir una | CONFIRMADO |
| **A-113** | La foundation emite los estilos semánticos y no los aplica a ningún elemento — Times New Roman en los 19 previews del tier | **ARREGLADO** en el reset del arnés; queda la pregunta de canon |
| **A-114** | `Sidebar.Inset` impone `overflow: auto`, y un ancestro con `overflow` se lleva el `position: sticky` de dentro | CONFIRMADO |
| **A-115** | No existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su ficha F5 pone como disparador | CONFIRMADO |
uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| **A-116** | `palabras.breadcrumb` declara `defaultElement: 'nav'` con `aria: []` y nadie la nombra: misma clase que A-111. **Excepción firmada** en el censo de landmarks, no se toca desde aquí | CONFIRMADO |
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### 3 · Y sigue pendiente lo que tú dejaste pedido
**«Repasar cada bloque»** — un repaso block a block. **No hay ficha escrita**:
su forma se acuerda antes de empezar (qué orden, qué se mira, y si lo que salga
va al ledger o al README de cada block). Pregunta antes de arrancar.
Y **F3 sigue**: el orden del plan es `app-shell` (HECHO) → `error-page` →
`user-menu` → `notifications` → `settings` → `auth` → `dashboard` → `wizard`
→ `data-table` y `kanban`. ⚠️ Recomendación registrada **sin firmar**: subir
`auth` al segundo puesto. Y ojo — `user-menu` (F3.6) y `notifications` (F3.7)
son justo las piezas que le faltan a la barra del shell, así que hacerlas
seguidas tiene un consumidor real esperando.
uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### Lo que dejó la sesión de A-111 (2026-08-19, un commit)
Siete ficheros del canon y tres de proceso. Nada del tier `blocks` se tocó: el
defecto vivía una capa más abajo, como las 8 de 12 de la fase 7.
- `morfo/components/navigation-menu.ts` — la pareja de nombre sube de `List` a
`Provider`; la `List` conserva sólo `aria-orientation`.
- `soma/components/navigation-menu/` — la fuente `ariaLabelledby` sube al nivel
del runtime; el wrapper deja de sacar `aria-label` de restProps (viaja con el
resto y gana el merge, A-85); fuera el opt `ariaLabel` y el reenvío de la
`List`; test del bag reescrito (nombre en el provider, `not.toHaveProperty`
en la lista, suppression por `aria-labelledby`).
- `morfo/landmark-census.test.ts` (nuevo) + `architecture/morfo.md` §Step 4.
- READMEs de soma y eidos del componente; ledger §A-111 y §A-116 nuevas.
**Gates**: 420/420 en morfo+sema+soma+eidos tocados · `component:audit --only
navigation-menu` PASS · `morfo:check` PASS (las 6 rojas —color-field, combobox,
fab, gradient-builder, menu-dial, palabras— son ajenas: el check valida
`data-*`, que esta sesión no toca) · `svelte-check` **72/62 antes y después** ·
`docs:check` 0/0 (640 docs) · prettier: los 4 avisos de ficheros tocados ya
fallaban en HEAD (verificado con `git show HEAD:… | prettier --check`), el
fichero nuevo va formateado.
⚠️ **Método que valió la pena**: el nombre se midió COMPUTADO, desde el árbol AX
de Chrome por CDP, nunca leyendo el atributo — un `aria-label` en el DOM prueba
el atributo, no el nombre. Y el guard se probó en rojo por mutación tres veces;
una de ellas (vaciar el catálogo) es la que impide que un censo sobre nada pase
en verde.
### Lo que dejó la sesión del `app-shell` (2026-08-19)
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Ocho commits, de `9fd54c80f` a `edf0639ee`. **Sin push.**
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Fase 0 firmada** en `PLAN-blocks.md` §F3.1 — Q1 el block NO cablea servicios
· Q2 dos modelos de scroll por prop · Q3 la cabecera dentro del inset · Q4
canon `SkipLink` + uno por región montada.
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **`SkipLink` (canon nuevo)** — eidos-native, 1 parte, 0 eventos, posee sus
palabras por ROL de landmark, peldaño de z propio (950).
- **LOS DOS ÁMBITOS, y es la corrección de fondo del día**: la barra lleva la
APLICACIÓN (su menú general, buscar, avisos, cuenta) y no se mueve; el RAÍL
lleva el CONTEXTO (este proyecto, esta tabla) y cambia entero al cambiar de
contexto. Yo había escrito que un menú en la barra sería «una segunda
navegación»: es al revés, dos navegaciones de ámbito distinto son lo correcto
(Atlassian `TopNav`+`SideNav`, Polaris `TopBar`+`Navigation`). El rastro va en
la cabecera de la PÁGINA, no en la barra.
- **Cuatro trampas de layout medidas**, escritas en el README del block:
`minHeight` es un suelo y no un techo · un grid que sólo declara filas tiene
una columna implícita `auto` que se encoge · `Box` declara
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`flex-grow/shrink/basis` y pisa al `flex` de quien lo envuelve · un ancestro
con `overflow` se lleva el `sticky` (A-114).
- ⚠️ **Dos averías del ARNÉS que este block destapó, las dos arregladas**: los
previews llevaban los 8px de margen del navegador (así que NINGÚN block se
enseñaba a sangre: `x: 8, w: 1264` a 1280, la página compuesta incluida) y no
anclaban la tipografía del tema (A-113). **Las medidas de anchura anteriores
al 2026-08-19 llevan el sesgo de los 8px.**
- **La demo se rehizo dos veces, y la lección vale para todo el tier**: primero
estaba escrita a mano (`<div style>`, `16rem` clavado, `font-size` en un
`<strong>`) y luego, ya sin literales, seguía sin usar los componentes que
SIGNIFICAN lo que mostraba. Ahora: `Metrics` para los KPI (con la valencia
desacoplada), `Feed` para bandeja y actividad (`role="feed"` + `article` +
`aria-posinset`), `Toolbar` para los clusters, `NavigationMenu` para el menú
de la aplicación, y la tipografía por los estilos SEMÁNTICOS del tema
(`Text style="label|caption|body"`, `Heading level` + `style`), nunca por un
tamaño elegido a ojo.
- **Lo que NO se ejecutó y sigue sobre la mesa**: la **app de referencia**
(`web/routes/blocks/app/`, `kind: 'page'`) — la primera raíz de composición en
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
modo **attach** del repo (`createActiveApp` → `attachActiveUix` → `<Uix>` →
`ActiveEidos` con sus fuentes → `createActivePrefsDomProjection` →
`setActiveApp`/`setBus`/`setPermsContext`). Hoy **ningún** shell del repo hace
docs(blocks): el shell dejó cinco filas, y una explica por qué nadie la había visto Handoff reescrito para mañana y las cinco filas que abrió el `app-shell` fichadas en el ledger (A-111…A-115). La puerta de entrada de mañana es la primera. **A-111 — `NavigationMenu` deja su landmark ANÓNIMO.** El `aria-label` del consumidor se reenvía al `<ul>` de la parte `List` y el `<nav>` se queda sin nombre; el morfo lo declara así a propósito («the root delegates its name to the list it wraps»). Pero un `<ul>` no es una región: quien navega por landmarks ve el `<nav>`, y lo ve anónimo. Con UNA navegación en la página es admisible —y por eso lleva tres semanas de tier sin salir—; con dos ámbitos incumple la APG, y un shell de aplicación monta dos por definición. Medido en el preview: `navigation: ['Navegación principal', null, 'Migas de pan']`. La ficha lleva la forma propuesta en cuatro pasos: mover el default de naming de la `List` al `Provider` y que la lista apunte al root con `aria-labelledby`; precedencia de clase «naming» (el consumidor gana si dice algo); un guard que falle si un componente con `defaultElement: 'nav'` no puede recibir nombre en su root; y re-medir el censo. Toca morfo + soma, así que va con el aviso de mirar antes si la sesión del `sidebar` sigue viva ahí. Las otras cuatro: **A-112** `Toolbar.Button` tipa contra el `ButtonProps` de soma y no acepta `variant`/`color` · **A-113** la foundation emite los estilos semánticos y no los aplica a ningún elemento —Times New Roman en los 19 previews—, ARREGLADA en el reset del arnés pero con la pregunta de canon abierta · **A-114** `Sidebar.Inset` impone `overflow: auto` y se lleva el `sticky` de dentro · **A-115** no existe `description-list` y el panel de detalle del shell es el «primer detail-view real» que su propia ficha F5 pone como disparador. El handoff recoge además la corrección de fondo del día (la barra y el raíl son dos ÁMBITOS, no la misma navegación en dos tamaños), las dos averías del arnés que este block destapó, y lo que NO se ejecutó: la app de referencia en modo attach, que sigue siendo el único sitio donde el ecosistema entero se demostraría cableado. docs:check 0/0 (639). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
nada de eso: los siete arrancan `createActiveUix` standalone.
- **En manos de otra sesión**: el `commit-select` del `Sidebar.MenuButton` (mudo
hoy, mientras `NavigationMenu.Link` sí emite para el mismo acto). No tocar
`sidebar` en morfo/sema/soma.
## ⚠️ LO PRIMERO: la fuente viva es el LEDGER, no el documento del 2026-08-01
feat(blocks): el guard vigila la frontera, y siete filas del ledger caen medidas FASE 5 DEL SANEAMIENTO — `blocks:check` deja de vigilar solo la forma del tier y pasa a vigilar su frontera, su documentacion y su catalogo. Tres reglas, cada una con su fixture negativo en el selfTest(): 1. Lista blanca de importaciones (B-4). La frontera dura 1 era prosa; ahora es codigo: $uix, los arts publicos, $libs/forms, svelte y los relativos del propio block. Los arts se DERIVAN de src/arts/*, no se listan a mano — una lista escrita se queda atras el dia que aterriza un art. El tier ya cumplia: cero violaciones al encenderla. 2. README completo (B-9) + declaracion de landmark (B-8). Salieron 7 de 15 sin ella; escritas leyendo la fuente de cada block, no la plantilla. 3. Ficha en el catalogo de demos (B-9), en los DOS sentidos: un block que el catalogo no publica es invisible para el rail, y un slug publicado sin block detras es un enlace muerto. De paso el escaner deja de leer los comentarios como codigo: los index.ts documentan su uso con un `// import { Cta } from '$blocks/cta'`, y una lista blanca que lee prosa habria empezado a acusar a los ejemplos. Verificado EN ROJO sobre el arbol real, no solo contra los fixtures: un zod y un $libs/days metidos en hero/types.ts salen con su linea exacta mientras el mismo import dentro de un comentario NO salta; el catalogo falla en las dos direcciones; y al romper isAllowedSpec a proposito el self-test aborta el guard en vez de dar verde. ARREGLOS DEL CONTRASTE DOCTRINAL — siete filas, cada una con medicion o gate: - A-88 team: `height="100%"` en el Stack del Member. El div que pinta Motion es un bloque pelado, asi que el Stack se quedaba a altura de contenido y el `margin-top:auto` de los enlaces repartia CERO. Medido: la desviacion entre filas de iconos pasa de 20px a 0, y el margen reparte 20,297px. - A-94/A-28 (feature-grid, team, testimonials): los tres declaraban su tipo como `= AutoGridProps` y ponian {...rest} ANTES de las props que fijan, asi que un consumidor podia escribir align="start" y no obtener nada. Cerrados con Pick<AutoGridProps, ...>, que conserva los tipos exactos del canon. - A-84 feature-grid: el eje `align` llega a las partes por contexto, como en team, en vez de que el typedoc instruya al app a repetirlo. Medido: con align=center el align-items computado es center en cabecera Y celdas. - A-19 faq: `marginX="auto"` en el Header — Box no centra solo. Medido: el Box de 768px resuelve margin-inline 248px/248px donde antes daba 0. - A-27 testimonials y A-86 pricing: el typedoc decia `soft` donde el codigo hace `outline`, y el ejemplo de la puerta de entrada no compilaba. - A-91 banner (fila nueva): el block hereda el eje intent/color que el canon declara fuera del sistema abierto en su propio typedoc, sin registrarlo. LEDGER — dos lecciones de instrumento escritas dentro, porque ambas produjeron hallazgos falsos publicados: 1. El dev server sirve codigo ANTERIOR a HEAD si reusa cache de Vite. Tres filas (A-36, A-69, A-85) se dieron por vivas estando arregladas. El delator fue aritmetico: las duraciones medidas eran EXACTAMENTE las que el comentario del arreglo cita como estado anterior. 2. Contar nodos WebAudio no es medir sonido: la sintesis crea dos osciladores por earcon, un sound pack de muestras cambia la aritmetica entera, y crear nodos no es sonar. El contador responde "hubo actividad" y nada mas. Y el error de metodo del que ambas son sintoma, tambien registrado: se fue a re-medir A-67 sin leer su ficha, que ya traia los gains del catalogo, el empate de applyDominance y la regla de CANON.md incumplida — mejor razonado que la nota que lo sustituia. Gates: blocks:check verde (15 blocks / 115 ficheros) · svelte-check 69 errores / 57 avisos = linea base exacta, ninguno en lo tocado · docs:check 0/0 · prettier limpio en todo lo del commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**`docs/process/AUDIT-blocks-ledger.md`** — filas con id estable desde `A-01`.
El documento del 2026-08-01 se conserva (sus reclamaciones y evidencias son
válidas y el ledger las indexa) pero **su clasificación NO vale**: tenía los
veredictos desemparejados de sus hallazgos por un join por POSICIÓN, y el journal
del workflow era de sesión. Se reprodujo en vivo al re-verificar — el journal
devuelve los resultados en un orden distinto al de entrada.
uix(navigation-menu): un <ul> no es una región, y por eso el landmark salía sin nombre El morfo declaraba el nombre por defecto de la navegación en la parte que pinta el <ul>, con la razón escrita al lado: «the root <nav> delegates its name to the list it wraps». La delegación no existe. El gesto que un lector de pantalla ofrece para saltar entre las áreas de una página llega al <nav>, y llegaba a un <nav> ANÓNIMO — con el nombre del consumidor puesto una capa más adentro, en un elemento que ninguna navegación por landmarks visita. Sobrevivió tres semanas de tier porque con UNA navegación en la página un landmark anónimo es admisible, y todas las demos del componente y todos los blocks de sitio montan una. Apareció en cuanto el app-shell montó dos ámbitos, que es lo que un shell hace por definición (A-111). La APG es explícita: si una página incluye más de un landmark de navegación, cada uno lleva su nombre. El arreglo NO es el que la ficha proponía. Su paso 1 quería que la lista heredase el nombre por aria-labelledby; el barrido de los morfos hermanos con defaultElement 'nav' dijo otra cosa: breadcrumb (<ol>) y nav-tree (<ul>) declaran aria: [] en su lista y nombran sólo el <nav>. navigation-menu era el único fuera de esa forma, así que la pareja de nombre —el aria-label con su suppression prop-falsy ariaLabelledby, y el aria-labelledby por propRef— sube entera a la parte Provider y la lista se queda con su aria-orientation. En soma, la fuente ariaLabelledby sube al nivel del runtime (la forma de breadcrumb) y el wrapper DEJA de sacar aria-label de restProps: viaja con el resto y gana el merge por política de naming, que es lo que A-85 dejó escrito y lo que este componente no aplicaba. Se van con ello el opt ariaLabel y el reenvío condicional que la List hacía a mano. Y como la regla no estaba escrita en ninguna doctrina —grep de «landmark» en morfo.md, canon/ y guides/ daba cero—, se escribe: architecture/morfo.md §Step 4 gana «A landmark is named on ITS OWN element», y nace el censo morfo/landmark-census.test.ts, que falla si una parte con defaultElement 'nav' no declara un attr de nombre EN SU PARTE. Probado en rojo por mutación tres veces: deshaciendo el arreglo (navigation-menu.provider), retirando la excepción (palabras.breadcrumb) y vaciando el catálogo, que es la mutación que impide que un censo sobre nada pase en verde. El ámbito es 'nav' a propósito: main, header y footer son únicos por página, y section y form sólo son landmark cuando ya tienen nombre. El guard destapó de paso un segundo caso de la misma clase: la parte Breadcrumb de palabras declara un <nav> con aria: [] y nadie la nombra, ni en soma ni en eidos. Queda como A-116 con EXCEPCIÓN FIRMADA por el autor: palabras es el eje de otra sesión y su rama es compartida. La tercera fila del censo obliga a retirar la excepción el día que esa parte declare un nombre. Verificado con el nombre COMPUTADO desde el árbol AX de Chrome por CDP, nunca leyendo el atributo (un aria-label en el DOM prueba el atributo, no el nombre), con servidor recién arrancado y esperando la puerta de hidratación honesta: /blocks/app-shell/preview navigation: ['Navegación principal', 'Menú de la aplicación', 'Migas de pan'] (antes: el 2.º null) /uix/components/navigation-menu (sin label del consumidor) el <nav> computa 'Principal' — el default del morfo, traducido, sobre el landmark; el <ul>, sin nombre Gates: 420/420 en morfo+sema+soma+eidos tocados · component:audit --only navigation-menu PASS · morfo:check PASS · svelte-check 72/62 antes y después · docs:check 0/0. Los avisos de prettier de los ficheros tocados ya fallaban en HEAD (comprobado con git show HEAD:… | prettier --check); el fichero nuevo va formateado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Estado del ledger (2026-08-19): **73 ARREGLADO · 27 CONFIRMADO · 13 REFUTADO ·
3 DATO** (116 filas: las 90 originales + A-91…A-116). Cero
feat(blocks): el guard vigila la frontera, y siete filas del ledger caen medidas FASE 5 DEL SANEAMIENTO — `blocks:check` deja de vigilar solo la forma del tier y pasa a vigilar su frontera, su documentacion y su catalogo. Tres reglas, cada una con su fixture negativo en el selfTest(): 1. Lista blanca de importaciones (B-4). La frontera dura 1 era prosa; ahora es codigo: $uix, los arts publicos, $libs/forms, svelte y los relativos del propio block. Los arts se DERIVAN de src/arts/*, no se listan a mano — una lista escrita se queda atras el dia que aterriza un art. El tier ya cumplia: cero violaciones al encenderla. 2. README completo (B-9) + declaracion de landmark (B-8). Salieron 7 de 15 sin ella; escritas leyendo la fuente de cada block, no la plantilla. 3. Ficha en el catalogo de demos (B-9), en los DOS sentidos: un block que el catalogo no publica es invisible para el rail, y un slug publicado sin block detras es un enlace muerto. De paso el escaner deja de leer los comentarios como codigo: los index.ts documentan su uso con un `// import { Cta } from '$blocks/cta'`, y una lista blanca que lee prosa habria empezado a acusar a los ejemplos. Verificado EN ROJO sobre el arbol real, no solo contra los fixtures: un zod y un $libs/days metidos en hero/types.ts salen con su linea exacta mientras el mismo import dentro de un comentario NO salta; el catalogo falla en las dos direcciones; y al romper isAllowedSpec a proposito el self-test aborta el guard en vez de dar verde. ARREGLOS DEL CONTRASTE DOCTRINAL — siete filas, cada una con medicion o gate: - A-88 team: `height="100%"` en el Stack del Member. El div que pinta Motion es un bloque pelado, asi que el Stack se quedaba a altura de contenido y el `margin-top:auto` de los enlaces repartia CERO. Medido: la desviacion entre filas de iconos pasa de 20px a 0, y el margen reparte 20,297px. - A-94/A-28 (feature-grid, team, testimonials): los tres declaraban su tipo como `= AutoGridProps` y ponian {...rest} ANTES de las props que fijan, asi que un consumidor podia escribir align="start" y no obtener nada. Cerrados con Pick<AutoGridProps, ...>, que conserva los tipos exactos del canon. - A-84 feature-grid: el eje `align` llega a las partes por contexto, como en team, en vez de que el typedoc instruya al app a repetirlo. Medido: con align=center el align-items computado es center en cabecera Y celdas. - A-19 faq: `marginX="auto"` en el Header — Box no centra solo. Medido: el Box de 768px resuelve margin-inline 248px/248px donde antes daba 0. - A-27 testimonials y A-86 pricing: el typedoc decia `soft` donde el codigo hace `outline`, y el ejemplo de la puerta de entrada no compilaba. - A-91 banner (fila nueva): el block hereda el eje intent/color que el canon declara fuera del sistema abierto en su propio typedoc, sin registrarlo. LEDGER — dos lecciones de instrumento escritas dentro, porque ambas produjeron hallazgos falsos publicados: 1. El dev server sirve codigo ANTERIOR a HEAD si reusa cache de Vite. Tres filas (A-36, A-69, A-85) se dieron por vivas estando arregladas. El delator fue aritmetico: las duraciones medidas eran EXACTAMENTE las que el comentario del arreglo cita como estado anterior. 2. Contar nodos WebAudio no es medir sonido: la sintesis crea dos osciladores por earcon, un sound pack de muestras cambia la aritmetica entera, y crear nodos no es sonar. El contador responde "hubo actividad" y nada mas. Y el error de metodo del que ambas son sintoma, tambien registrado: se fue a re-medir A-67 sin leer su ficha, que ya traia los gains del catalogo, el empate de applyDominance y la regla de CANON.md incumplida — mejor razonado que la nota que lo sustituia. Gates: blocks:check verde (15 blocks / 115 ficheros) · svelte-check 69 errores / 57 avisos = linea base exacta, ninguno en lo tocado · docs:check 0/0 · prettier limpio en todo lo del commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
pendientes: todas están medidas. La tasa real de refutación fue del **13%**, no
del 28%.
**La regla que hay que respetar al escribir en él: unión por `id`, SIEMPRE.**
Ningún proceso vuelve a casar dos listas por posición. Un verificador que no
devuelve su id no escribe fila.
## El hallazgo grande de la re-verificación
**De las 12 ALTA de percepción, 8 tenían la causa raíz en el CANON, no en los
blocks.** Los blocks componen bien; lo que estaba roto era el arco perceptivo del
canon. Todos arreglados ya (ver abajo), pero la lección se queda: cuando una
auditoría de un tier acusa al tier, comprueba en qué capa vive el defecto.
## Lo hecho en la sesión del 2026-08-06 (commit `866089a40`)
**Canon** — `Link` (la prop `color` era inerte en `subtle`/`plain`, el hover
clavaba primary, el `:active` quedaba tapado) · `Card` (prometía `BoxProps` sin
aplicarlos: `height="100%"` era un atributo inerte; ahora el tipo dice la verdad y
el eje de tamaño va por `buildSizeStyle`, helper compartido) · `Form.Submit` y
`Form.Reset` (componen el `Button` del canon, así que la acción principal de un
formulario recupera el `contact-activate` en el gesto; y el `aria-label` genérico
deja de pisar el texto propio — WCAG 2.5.3 para todo consumidor, verificado con el
AX tree de Chrome) · `Field` (dejaba de duplicar `commit-submit` dentro de un
`Form`) · `NavigationMenu` (el `commit-select` se mueve al `Link`, el despliegue
habla como `emerge-open/close` en vez de fingir una selección por hover, y el pack
casa por fin con la parte que recibe el estampado — antes sonaba a la ganancia
base, 10× lo diseñado) · `Badge` (el ✕ compone `IconButton`; la altura del chip
pasa a ser la del control) · **la fundación**: `[data-on]` arrastra la propiedad
`color`, no solo las variables.
**Blocks** — hero 1.61:1 → 6.61:1 · contact separa `incomplete` de `invalid` (el
camino de error por campo era inalcanzable por construcción) y su frase llega a la
AT · site-header ya no congela la página al cruzar el breakpoint · site-footer
emite su commit · pricing no se vacía · cta llega a sangre de verdad · newsletter
COORDINA.
**Doctrina** — la frontera dura 1 nombra `$libs/forms`; el contrato B admite un
**segundo servicio, el anunciador** (`uix.announce`): un block que posee las
palabras de sus estados tiene que poder decirlas.
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Fase 7 — contraste doctrinal de los 15 — **CERRADA 15/15**
feat(blocks): el guard vigila la frontera, y siete filas del ledger caen medidas FASE 5 DEL SANEAMIENTO — `blocks:check` deja de vigilar solo la forma del tier y pasa a vigilar su frontera, su documentacion y su catalogo. Tres reglas, cada una con su fixture negativo en el selfTest(): 1. Lista blanca de importaciones (B-4). La frontera dura 1 era prosa; ahora es codigo: $uix, los arts publicos, $libs/forms, svelte y los relativos del propio block. Los arts se DERIVAN de src/arts/*, no se listan a mano — una lista escrita se queda atras el dia que aterriza un art. El tier ya cumplia: cero violaciones al encenderla. 2. README completo (B-9) + declaracion de landmark (B-8). Salieron 7 de 15 sin ella; escritas leyendo la fuente de cada block, no la plantilla. 3. Ficha en el catalogo de demos (B-9), en los DOS sentidos: un block que el catalogo no publica es invisible para el rail, y un slug publicado sin block detras es un enlace muerto. De paso el escaner deja de leer los comentarios como codigo: los index.ts documentan su uso con un `// import { Cta } from '$blocks/cta'`, y una lista blanca que lee prosa habria empezado a acusar a los ejemplos. Verificado EN ROJO sobre el arbol real, no solo contra los fixtures: un zod y un $libs/days metidos en hero/types.ts salen con su linea exacta mientras el mismo import dentro de un comentario NO salta; el catalogo falla en las dos direcciones; y al romper isAllowedSpec a proposito el self-test aborta el guard en vez de dar verde. ARREGLOS DEL CONTRASTE DOCTRINAL — siete filas, cada una con medicion o gate: - A-88 team: `height="100%"` en el Stack del Member. El div que pinta Motion es un bloque pelado, asi que el Stack se quedaba a altura de contenido y el `margin-top:auto` de los enlaces repartia CERO. Medido: la desviacion entre filas de iconos pasa de 20px a 0, y el margen reparte 20,297px. - A-94/A-28 (feature-grid, team, testimonials): los tres declaraban su tipo como `= AutoGridProps` y ponian {...rest} ANTES de las props que fijan, asi que un consumidor podia escribir align="start" y no obtener nada. Cerrados con Pick<AutoGridProps, ...>, que conserva los tipos exactos del canon. - A-84 feature-grid: el eje `align` llega a las partes por contexto, como en team, en vez de que el typedoc instruya al app a repetirlo. Medido: con align=center el align-items computado es center en cabecera Y celdas. - A-19 faq: `marginX="auto"` en el Header — Box no centra solo. Medido: el Box de 768px resuelve margin-inline 248px/248px donde antes daba 0. - A-27 testimonials y A-86 pricing: el typedoc decia `soft` donde el codigo hace `outline`, y el ejemplo de la puerta de entrada no compilaba. - A-91 banner (fila nueva): el block hereda el eje intent/color que el canon declara fuera del sistema abierto en su propio typedoc, sin registrarlo. LEDGER — dos lecciones de instrumento escritas dentro, porque ambas produjeron hallazgos falsos publicados: 1. El dev server sirve codigo ANTERIOR a HEAD si reusa cache de Vite. Tres filas (A-36, A-69, A-85) se dieron por vivas estando arregladas. El delator fue aritmetico: las duraciones medidas eran EXACTAMENTE las que el comentario del arreglo cita como estado anterior. 2. Contar nodos WebAudio no es medir sonido: la sintesis crea dos osciladores por earcon, un sound pack de muestras cambia la aritmetica entera, y crear nodos no es sonar. El contador responde "hubo actividad" y nada mas. Y el error de metodo del que ambas son sintoma, tambien registrado: se fue a re-medir A-67 sin leer su ficha, que ya traia los gains del catalogo, el empate de applyDominance y la regla de CANON.md incumplida — mejor razonado que la nota que lo sustituia. Gates: blocks:check verde (15 blocks / 115 ficheros) · svelte-check 69 errores / 57 avisos = linea base exacta, ninguno en lo tocado · docs:check 0/0 · prettier limpio en todo lo del commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Encargo del usuario: contrastar cada block con la documentación del sistema **a
nivel de cada componente que compone y en conjunto**, siguiendo la guía de
creación de blocks y **con la composición como estrategia válida**, comprobando
las directrices de eidos, sema, morfo y soma — más **motion**, que faltaba en la
rejilla y detectó él preguntando si había leído su doctrina. No la había leído;
el primer veredicto sobre coreografía salió sin ella y hubo que retirarlo.
**Detalle completo, rejilla de siete ejes y fichas: `AUDIT-blocks-ledger.md`
§Fase 7.** Aquí sólo el estado y cómo seguir.
### ⚠️ Lo primero: el instrumento mentía
Las mediciones en navegador del 2026-08-09 se hicieron contra un dev server con
caché de Vite **anterior a arreglos ya commiteados**. Al re-medir con servidor
limpio cayeron **A-36, A-69 y A-85**. El delator fue aritmético: las duraciones
medidas (7867/3567 ms, ratio 2.21) eran EXACTAMENTE las que el comentario del
arreglo cita como estado anterior. **Servidor recién arrancado antes de medir**,
y si un número reproduce el «antes» documentado con demasiada exactitud,
sospechar del instrumento antes que del código.
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### Estado: los 15 con la rejilla completa
feat(blocks): el guard vigila la frontera, y siete filas del ledger caen medidas FASE 5 DEL SANEAMIENTO — `blocks:check` deja de vigilar solo la forma del tier y pasa a vigilar su frontera, su documentacion y su catalogo. Tres reglas, cada una con su fixture negativo en el selfTest(): 1. Lista blanca de importaciones (B-4). La frontera dura 1 era prosa; ahora es codigo: $uix, los arts publicos, $libs/forms, svelte y los relativos del propio block. Los arts se DERIVAN de src/arts/*, no se listan a mano — una lista escrita se queda atras el dia que aterriza un art. El tier ya cumplia: cero violaciones al encenderla. 2. README completo (B-9) + declaracion de landmark (B-8). Salieron 7 de 15 sin ella; escritas leyendo la fuente de cada block, no la plantilla. 3. Ficha en el catalogo de demos (B-9), en los DOS sentidos: un block que el catalogo no publica es invisible para el rail, y un slug publicado sin block detras es un enlace muerto. De paso el escaner deja de leer los comentarios como codigo: los index.ts documentan su uso con un `// import { Cta } from '$blocks/cta'`, y una lista blanca que lee prosa habria empezado a acusar a los ejemplos. Verificado EN ROJO sobre el arbol real, no solo contra los fixtures: un zod y un $libs/days metidos en hero/types.ts salen con su linea exacta mientras el mismo import dentro de un comentario NO salta; el catalogo falla en las dos direcciones; y al romper isAllowedSpec a proposito el self-test aborta el guard en vez de dar verde. ARREGLOS DEL CONTRASTE DOCTRINAL — siete filas, cada una con medicion o gate: - A-88 team: `height="100%"` en el Stack del Member. El div que pinta Motion es un bloque pelado, asi que el Stack se quedaba a altura de contenido y el `margin-top:auto` de los enlaces repartia CERO. Medido: la desviacion entre filas de iconos pasa de 20px a 0, y el margen reparte 20,297px. - A-94/A-28 (feature-grid, team, testimonials): los tres declaraban su tipo como `= AutoGridProps` y ponian {...rest} ANTES de las props que fijan, asi que un consumidor podia escribir align="start" y no obtener nada. Cerrados con Pick<AutoGridProps, ...>, que conserva los tipos exactos del canon. - A-84 feature-grid: el eje `align` llega a las partes por contexto, como en team, en vez de que el typedoc instruya al app a repetirlo. Medido: con align=center el align-items computado es center en cabecera Y celdas. - A-19 faq: `marginX="auto"` en el Header — Box no centra solo. Medido: el Box de 768px resuelve margin-inline 248px/248px donde antes daba 0. - A-27 testimonials y A-86 pricing: el typedoc decia `soft` donde el codigo hace `outline`, y el ejemplo de la puerta de entrada no compilaba. - A-91 banner (fila nueva): el block hereda el eje intent/color que el canon declara fuera del sistema abierto en su propio typedoc, sin registrarlo. LEDGER — dos lecciones de instrumento escritas dentro, porque ambas produjeron hallazgos falsos publicados: 1. El dev server sirve codigo ANTERIOR a HEAD si reusa cache de Vite. Tres filas (A-36, A-69, A-85) se dieron por vivas estando arregladas. El delator fue aritmetico: las duraciones medidas eran EXACTAMENTE las que el comentario del arreglo cita como estado anterior. 2. Contar nodos WebAudio no es medir sonido: la sintesis crea dos osciladores por earcon, un sound pack de muestras cambia la aritmetica entera, y crear nodos no es sonar. El contador responde "hubo actividad" y nada mas. Y el error de metodo del que ambas son sintoma, tambien registrado: se fue a re-medir A-67 sin leer su ficha, que ya traia los gains del catalogo, el empate de applyDominance y la regla de CANON.md incumplida — mejor razonado que la nota que lo sustituia. Gates: blocks:check verde (15 blocks / 115 ficheros) · svelte-check 69 errores / 57 avisos = linea base exacta, ninguno en lo tocado · docs:check 0/0 · prettier limpio en todo lo del commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Ninguno de los 15 tiene un defecto de composición.** Componen canon y lo
componen bien; todo lo que salió vive una capa más abajo (canon) o en las FICHAS
del propio ledger. Ese es el resultado de la fase, y conviene no perderlo: la
auditoría original acusaba al tier.
feat(blocks): el guard vigila la frontera, y siete filas del ledger caen medidas FASE 5 DEL SANEAMIENTO — `blocks:check` deja de vigilar solo la forma del tier y pasa a vigilar su frontera, su documentacion y su catalogo. Tres reglas, cada una con su fixture negativo en el selfTest(): 1. Lista blanca de importaciones (B-4). La frontera dura 1 era prosa; ahora es codigo: $uix, los arts publicos, $libs/forms, svelte y los relativos del propio block. Los arts se DERIVAN de src/arts/*, no se listan a mano — una lista escrita se queda atras el dia que aterriza un art. El tier ya cumplia: cero violaciones al encenderla. 2. README completo (B-9) + declaracion de landmark (B-8). Salieron 7 de 15 sin ella; escritas leyendo la fuente de cada block, no la plantilla. 3. Ficha en el catalogo de demos (B-9), en los DOS sentidos: un block que el catalogo no publica es invisible para el rail, y un slug publicado sin block detras es un enlace muerto. De paso el escaner deja de leer los comentarios como codigo: los index.ts documentan su uso con un `// import { Cta } from '$blocks/cta'`, y una lista blanca que lee prosa habria empezado a acusar a los ejemplos. Verificado EN ROJO sobre el arbol real, no solo contra los fixtures: un zod y un $libs/days metidos en hero/types.ts salen con su linea exacta mientras el mismo import dentro de un comentario NO salta; el catalogo falla en las dos direcciones; y al romper isAllowedSpec a proposito el self-test aborta el guard en vez de dar verde. ARREGLOS DEL CONTRASTE DOCTRINAL — siete filas, cada una con medicion o gate: - A-88 team: `height="100%"` en el Stack del Member. El div que pinta Motion es un bloque pelado, asi que el Stack se quedaba a altura de contenido y el `margin-top:auto` de los enlaces repartia CERO. Medido: la desviacion entre filas de iconos pasa de 20px a 0, y el margen reparte 20,297px. - A-94/A-28 (feature-grid, team, testimonials): los tres declaraban su tipo como `= AutoGridProps` y ponian {...rest} ANTES de las props que fijan, asi que un consumidor podia escribir align="start" y no obtener nada. Cerrados con Pick<AutoGridProps, ...>, que conserva los tipos exactos del canon. - A-84 feature-grid: el eje `align` llega a las partes por contexto, como en team, en vez de que el typedoc instruya al app a repetirlo. Medido: con align=center el align-items computado es center en cabecera Y celdas. - A-19 faq: `marginX="auto"` en el Header — Box no centra solo. Medido: el Box de 768px resuelve margin-inline 248px/248px donde antes daba 0. - A-27 testimonials y A-86 pricing: el typedoc decia `soft` donde el codigo hace `outline`, y el ejemplo de la puerta de entrada no compilaba. - A-91 banner (fila nueva): el block hereda el eje intent/color que el canon declara fuera del sistema abierto en su propio typedoc, sin registrarlo. LEDGER — dos lecciones de instrumento escritas dentro, porque ambas produjeron hallazgos falsos publicados: 1. El dev server sirve codigo ANTERIOR a HEAD si reusa cache de Vite. Tres filas (A-36, A-69, A-85) se dieron por vivas estando arregladas. El delator fue aritmetico: las duraciones medidas eran EXACTAMENTE las que el comentario del arreglo cita como estado anterior. 2. Contar nodos WebAudio no es medir sonido: la sintesis crea dos osciladores por earcon, un sound pack de muestras cambia la aritmetica entera, y crear nodos no es sonar. El contador responde "hubo actividad" y nada mas. Y el error de metodo del que ambas son sintoma, tambien registrado: se fue a re-medir A-67 sin leer su ficha, que ya traia los gains del catalogo, el empate de applyDominance y la regla de CANON.md incumplida — mejor razonado que la nota que lo sustituia. Gates: blocks:check verde (15 blocks / 115 ficheros) · svelte-check 69 errores / 57 avisos = linea base exacta, ninguno en lo tocado · docs:check 0/0 · prettier limpio en todo lo del commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️ Cómo se llegó aquí importa, porque me equivoqué en el camino: durante días
declaré «conformes» siete blocks de los que sólo había medido UN eje (dónde cae
el `{...rest}` y quién estampa `data-stagger`). Un barrido no es la rejilla.
Se corrigió en el ledger y en este handoff cuando él preguntó «¿ya has
terminado?». Lo que el contraste produjo:
feat(blocks): el guard vigila la frontera, y siete filas del ledger caen medidas FASE 5 DEL SANEAMIENTO — `blocks:check` deja de vigilar solo la forma del tier y pasa a vigilar su frontera, su documentacion y su catalogo. Tres reglas, cada una con su fixture negativo en el selfTest(): 1. Lista blanca de importaciones (B-4). La frontera dura 1 era prosa; ahora es codigo: $uix, los arts publicos, $libs/forms, svelte y los relativos del propio block. Los arts se DERIVAN de src/arts/*, no se listan a mano — una lista escrita se queda atras el dia que aterriza un art. El tier ya cumplia: cero violaciones al encenderla. 2. README completo (B-9) + declaracion de landmark (B-8). Salieron 7 de 15 sin ella; escritas leyendo la fuente de cada block, no la plantilla. 3. Ficha en el catalogo de demos (B-9), en los DOS sentidos: un block que el catalogo no publica es invisible para el rail, y un slug publicado sin block detras es un enlace muerto. De paso el escaner deja de leer los comentarios como codigo: los index.ts documentan su uso con un `// import { Cta } from '$blocks/cta'`, y una lista blanca que lee prosa habria empezado a acusar a los ejemplos. Verificado EN ROJO sobre el arbol real, no solo contra los fixtures: un zod y un $libs/days metidos en hero/types.ts salen con su linea exacta mientras el mismo import dentro de un comentario NO salta; el catalogo falla en las dos direcciones; y al romper isAllowedSpec a proposito el self-test aborta el guard en vez de dar verde. ARREGLOS DEL CONTRASTE DOCTRINAL — siete filas, cada una con medicion o gate: - A-88 team: `height="100%"` en el Stack del Member. El div que pinta Motion es un bloque pelado, asi que el Stack se quedaba a altura de contenido y el `margin-top:auto` de los enlaces repartia CERO. Medido: la desviacion entre filas de iconos pasa de 20px a 0, y el margen reparte 20,297px. - A-94/A-28 (feature-grid, team, testimonials): los tres declaraban su tipo como `= AutoGridProps` y ponian {...rest} ANTES de las props que fijan, asi que un consumidor podia escribir align="start" y no obtener nada. Cerrados con Pick<AutoGridProps, ...>, que conserva los tipos exactos del canon. - A-84 feature-grid: el eje `align` llega a las partes por contexto, como en team, en vez de que el typedoc instruya al app a repetirlo. Medido: con align=center el align-items computado es center en cabecera Y celdas. - A-19 faq: `marginX="auto"` en el Header — Box no centra solo. Medido: el Box de 768px resuelve margin-inline 248px/248px donde antes daba 0. - A-27 testimonials y A-86 pricing: el typedoc decia `soft` donde el codigo hace `outline`, y el ejemplo de la puerta de entrada no compilaba. - A-91 banner (fila nueva): el block hereda el eje intent/color que el canon declara fuera del sistema abierto en su propio typedoc, sin registrarlo. LEDGER — dos lecciones de instrumento escritas dentro, porque ambas produjeron hallazgos falsos publicados: 1. El dev server sirve codigo ANTERIOR a HEAD si reusa cache de Vite. Tres filas (A-36, A-69, A-85) se dieron por vivas estando arregladas. El delator fue aritmetico: las duraciones medidas eran EXACTAMENTE las que el comentario del arreglo cita como estado anterior. 2. Contar nodos WebAudio no es medir sonido: la sintesis crea dos osciladores por earcon, un sound pack de muestras cambia la aritmetica entera, y crear nodos no es sonar. El contador responde "hubo actividad" y nada mas. Y el error de metodo del que ambas son sintoma, tambien registrado: se fue a re-medir A-67 sin leer su ficha, que ya traia los gains del catalogo, el empate de applyDominance y la regla de CANON.md incumplida — mejor razonado que la nota que lo sustituia. Gates: blocks:check verde (15 blocks / 115 ficheros) · svelte-check 69 errores / 57 avisos = linea base exacta, ninguno en lo tocado · docs:check 0/0 · prettier limpio en todo lo del commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Cinco disposiciones corregidas** — A-55 (mecanismo falso: el desvío lo causa
el ancho que resta el `Close`, no unos márgenes auto que miden `0px`), A-09 (su
arreglo apagaría la detección live), A-68 (no es arreglable desde el block sin
romper B-6), A-60 (correcta, y con el camino que nombra el propio `AutoGrid`),
A-61 (su segunda mitad ya la cerró `uix.announce`).
- **Tres filas nuevas** — A-91 (`banner` hereda el eje `intent`/`color` sin
registrarlo), A-92 (una restricción del modelo de cascada que vive en un
comentario de `pricing` y falta en §D.13 de la doctrina de motion), A-93
(`Motion` no expone su momento «visto», que es lo que desbloquearía A-68).
⚠️ Al retomar: **la composición es estrategia válida** (norma del usuario). Un
block que sólo coloca canon no es defectuoso por serlo; sólo lo es si al componer
se salta un contrato o reinventa un primitivo. Y el eje motion se contrasta con
§D.11 (la cascada ES `[data-stagger]` + preset + regla de fundación — modelo
CERRADO, no un atajo), §D.13(1) hijos directos, §D.13(2) ENTER-ONLY, y §2
KNOWN-FRAGILE (firma y stagger sobre UN mismo nodo se pisan).
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Lo hecho en las sesiones del 2026-08-16/17 (commits `4caf1100a`, `d02021aee`)
### 1 · El eje de tamaño dice de QUIÉN es (`4caf1100a`)
`size` significaba dos cosas en el tier: el aire de la `Section` en trece blocks
y la altura de la tira en `banner` — misma prop, distinta escala (`BannerSize`
no tiene `xl`). Renombrado: `size`→**`sectionSize`** (13), `container`→
**`containerSize`** (14), `minColumnWidth`→**`minChildWidth`** en `site-footer`.
`size` queda libre y sólo lo usa `banner`, donde SÍ es el tamaño del block.
**La regla vive ya en `architecture/blocks.md` §Conventions**: un block que
reenvía el eje de tamaño de una pieza interna lo nombra `{pieza}Size`, y un eje
que el canon ya nombra se reenvía CON SU NOMBRE.
Método que funcionó y conviene repetir: **renombrar los TIPOS primero** y dejar
que `svelte-check` señale cada consumidor. Cazó los cinco call sites que
quedaban. ⚠️ Y cazó un error mío: el primer patrón era demasiado ancho y renombró
`size` en siete sub-partes donde ese `size` es el del `Card` o el `Text` que
envuelven. Revertidas antes de seguir.
### 2 · Dos animadores que no se hablaban y un cluster que no envolvía (`d02021aee`)
**A-99 + A-98 — `Group` no aplicaba NINGUNO de los dos defaults que su README
promete** (`align: center`, `wrap: wrap`): nunca se los pasaba a `Flex`, que cae
a `nowrap`+`stretch`. De ahí que las acciones de `hero` no apilaran a 375px.
Arreglado en `group.svelte` con el mecanismo que ya usaba para `direction`, y con
`attached` invirtiendo a `nowrap` (el recipe cuadra radios y solapa bordes
asumiendo UNA línea). El censo decidió la forma: **`ButtonGroup` es el único
`Group` en columna de todo el ecosistema**, así que su `align="stretch"` vive en
su call site y no como default condicional. Medido: `hero` pasa a 2 líneas y la
acción secundaria de 124px truncados a 156,9px.
**A-68 + A-93 — los contadores corrían detrás de `opacity: 0`.** `CountUp` trae
su propio IO (threshold 0) y `Motion` usa otro (0.1 / −10%); un IO no mira la
opacidad. `Motion` publica ya su momento visto por contexto
(`motion/context.ts`, calcado de `cascade/context.ts`) y `stats-band-value` lo
pasa a `startWhen`. Medido en la ventana que discrimina (banda a 6px dentro del
viewport): contadores a 0/0/0 en la llegada y tras 2,6 s, donde antes acababan
en 12.121/330/47. Al revelarse, la primera cifra al **0%** — antes 97,8%. **A-69
intacta**: aterrizaje a 1781 ms, dispersión 0.
⚠️ **Residuo documentado**: las cifras que el stagger revela después llegan al
16,8% y **35,4%**. Estimé «≤10%» y me equivoqué — el muelle es sobreamortiguado
y cubre mucho recorrido al principio. Es el precio del aterrizaje conjunto que
A-69 firmó; no baja sin reabrirla.
### 3 · Tres errores de método de estas sesiones (no los repitas)
1. **Medir un default en una demo que lo pisa no es medir un default.** Escribí
en la ficha de A-99 que «el `align` sí se cumple, luego el recipe carga». El
`center` salía del control de la propia demo, que lo pasa explícito.
2. **El panel del navegador oculto suspende el IntersectionObserver**, no sólo
el rAF. Una primera medición de A-68 dio «contadores congelados» y era la
suspensión, no el arreglo: con el panel oculto el IO de `CountUp` tampoco
dispara, así que el resultado no distinguía una cosa de la otra. La vía
fiable es **Playwright headless** (como las fichas originales), resolviendo
`playwright` desde el `package.json` del repo si la sonda vive en el scratchpad.
3. **`Motion` es `once: true`.** Empujar la banda bajo el pliegue DESPUÉS de
cargar no sirve: su observador ya disparó. El espaciador tiene que existir en
el primer pintado (`addInitScript` con una hoja de estilo).
feat(blocks): el guard vigila la frontera, y siete filas del ledger caen medidas FASE 5 DEL SANEAMIENTO — `blocks:check` deja de vigilar solo la forma del tier y pasa a vigilar su frontera, su documentacion y su catalogo. Tres reglas, cada una con su fixture negativo en el selfTest(): 1. Lista blanca de importaciones (B-4). La frontera dura 1 era prosa; ahora es codigo: $uix, los arts publicos, $libs/forms, svelte y los relativos del propio block. Los arts se DERIVAN de src/arts/*, no se listan a mano — una lista escrita se queda atras el dia que aterriza un art. El tier ya cumplia: cero violaciones al encenderla. 2. README completo (B-9) + declaracion de landmark (B-8). Salieron 7 de 15 sin ella; escritas leyendo la fuente de cada block, no la plantilla. 3. Ficha en el catalogo de demos (B-9), en los DOS sentidos: un block que el catalogo no publica es invisible para el rail, y un slug publicado sin block detras es un enlace muerto. De paso el escaner deja de leer los comentarios como codigo: los index.ts documentan su uso con un `// import { Cta } from '$blocks/cta'`, y una lista blanca que lee prosa habria empezado a acusar a los ejemplos. Verificado EN ROJO sobre el arbol real, no solo contra los fixtures: un zod y un $libs/days metidos en hero/types.ts salen con su linea exacta mientras el mismo import dentro de un comentario NO salta; el catalogo falla en las dos direcciones; y al romper isAllowedSpec a proposito el self-test aborta el guard en vez de dar verde. ARREGLOS DEL CONTRASTE DOCTRINAL — siete filas, cada una con medicion o gate: - A-88 team: `height="100%"` en el Stack del Member. El div que pinta Motion es un bloque pelado, asi que el Stack se quedaba a altura de contenido y el `margin-top:auto` de los enlaces repartia CERO. Medido: la desviacion entre filas de iconos pasa de 20px a 0, y el margen reparte 20,297px. - A-94/A-28 (feature-grid, team, testimonials): los tres declaraban su tipo como `= AutoGridProps` y ponian {...rest} ANTES de las props que fijan, asi que un consumidor podia escribir align="start" y no obtener nada. Cerrados con Pick<AutoGridProps, ...>, que conserva los tipos exactos del canon. - A-84 feature-grid: el eje `align` llega a las partes por contexto, como en team, en vez de que el typedoc instruya al app a repetirlo. Medido: con align=center el align-items computado es center en cabecera Y celdas. - A-19 faq: `marginX="auto"` en el Header — Box no centra solo. Medido: el Box de 768px resuelve margin-inline 248px/248px donde antes daba 0. - A-27 testimonials y A-86 pricing: el typedoc decia `soft` donde el codigo hace `outline`, y el ejemplo de la puerta de entrada no compilaba. - A-91 banner (fila nueva): el block hereda el eje intent/color que el canon declara fuera del sistema abierto en su propio typedoc, sin registrarlo. LEDGER — dos lecciones de instrumento escritas dentro, porque ambas produjeron hallazgos falsos publicados: 1. El dev server sirve codigo ANTERIOR a HEAD si reusa cache de Vite. Tres filas (A-36, A-69, A-85) se dieron por vivas estando arregladas. El delator fue aritmetico: las duraciones medidas eran EXACTAMENTE las que el comentario del arreglo cita como estado anterior. 2. Contar nodos WebAudio no es medir sonido: la sintesis crea dos osciladores por earcon, un sound pack de muestras cambia la aritmetica entera, y crear nodos no es sonar. El contador responde "hubo actividad" y nada mas. Y el error de metodo del que ambas son sintoma, tambien registrado: se fue a re-medir A-67 sin leer su ficha, que ya traia los gains del catalogo, el empate de applyDominance y la regla de CANON.md incumplida — mejor razonado que la nota que lo sustituia. Gates: blocks:check verde (15 blocks / 115 ficheros) · svelte-check 69 errores / 57 avisos = linea base exacta, ninguno en lo tocado · docs:check 0/0 · prettier limpio en todo lo del commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Lo hecho en la sesión del 2026-08-09 — fase 5, el guard endurecido
`blocks:check` deja de vigilar sólo la forma del tier y pasa a vigilar su
frontera, su documentación y su catálogo. Tres reglas, cada una con fixture
negativo en el `selfTest()`:
1. **Lista blanca de importaciones (B-4)** — la frontera dura 1 era prosa; ahora
es código. Permitido: `$uix`, los arts públicos, `$libs/forms`, `svelte` /
`svelte/elements` y los relativos del propio block. **Los arts se DERIVAN de
`src/arts/*`**, no se listan a mano — una lista escrita se queda atrás el día
que aterriza un art (y este proyecto ya pagó dos veces esa lección). El tier
ya cumplía: cero violaciones al encenderla. Cierra la disposición de A-05.
2. **README completo (B-9) + declaración de landmark (B-8)** — las cuatro
secciones de la plantilla y un párrafo `**Landmark + headings**`. Al
encenderla salieron **7 de 15** sin declaración: los tres de A-14 más
`banner`, `content-section`, `cta`, `newsletter` y `site-footer`, que
nombraban «landmark» en una celda de tabla pero no declaraban nada. Escritas
leyendo la fuente de cada uno. **A-14 → ARREGLADO.**
3. **Ficha en `_lib/catalog.ts` (B-9)** — el árbol y el catálogo tienen que
coincidir en los DOS sentidos: un block que el catálogo no publica es
invisible para el raíl, y un slug publicado sin block detrás es un enlace
muerto.
De paso, **el escáner deja de leer los comentarios como código**: los `index.ts`
documentan su uso con un `// import { Cta } from '$blocks/cta'`, y una lista
blanca que lee prosa habría empezado a acusar a los ejemplos. (No era teórico:
esos 15 comentarios ya entraban en el escaneo de B-10 y sólo se salvaban porque
cada ejemplo cita su propio block.)
**Verificado en ROJO sobre el árbol real, no sólo contra los fixtures** — que es
la única prueba de que una regla nueva no es decorativa: un `zod` y un
`$libs/days` metidos en `hero/types.ts` salen con su línea exacta mientras el
mismo import dentro de un comentario NO salta; el catálogo falla en las dos
direcciones (`shipped: false` sobre un block vivo, slug fantasma); y al romper
`isAllowedSpec` a propósito el self-test aborta el guard en vez de dar verde.
## Qué queda, por orden
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Las 19 filas CONFIRMADO vivas**, agrupadas por lo que hace falta para cerrarlas.
Cada una lleva mecanismo y evidencia en su ficha del ledger — **léela antes de
re-medirla** (perdí una sesión re-midiendo A-67 sin leer la suya, que ya tenía el
análisis completo).
### a) Bloqueadas por decisión TUYA — no las toco sin tu firma
| Fila | Qué hay que decidir |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **A-67** `faq` | Dos earcons simultáneos al cambiar de pregunta. Puerta ya elegida en la ficha: un nuance `emerge-collapse-swap` (morfo + provider + pack). **Cae en el eje de sema**, así que se ejecuta en una sesión suya, no aquí. |
| **A-47** `cta` (ALTA) | Anillo de foco. Por doctrina es **un eje de configuración**: se endurece con un VALOR en `color.focus.ring`, «never a per-component CSS change» — que es justo lo que hacía el intento revertido en `e468e764b`. |
| **A-09** `stats-band` | Su disposición APAGARÍA la detección live: el contrato exige `value` para detectarla. El defecto real es el anuncio crudo en `metrics-value.svelte:40`, que es canon. |
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### b) ~~Bloqueada por una pieza que no existe~~ — CERRADA 2026-08-19
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- ~~**A-95** `banner`~~ **ARREGLADA**: la pieza era `app-shell` (F3.1) y ya
existe. Solape 0px y hit-test dentro de la cabecera, medido. Lo que sigue
siendo cierto: un `affix="top"` FUERA de un shell sigue tapando una cabecera
pegada — es el apilamiento firmado, y el README de `banner` es donde se dice.
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### c) Las 5 que dejó la página compuesta (F2b-D, 2026-08-18)
Todas medidas, todas CONFIRMADO, ninguna tocada — salen de componer 14 blocks en
un documento y de construir `cookie-consent`:
| Fila | Qué |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **A-106** `Button` (canon) | Acepta `ref` en su tipo y NUNCA lo reenvía: `bind:ref` tipa bien y no ata nada. **Forma exacta de A-94.** |
| **A-107** `Switch` (canon) | El morfo no tiene parte de etiqueta: la etiqueta visible es hermana y no es diana de clic. Todos los consumidores del repo repiten el mismo apaño. |
| **A-108** `Dialog` (canon) | Devuelve el foco al nodo que lo tenía al abrir; si el disparador se desmontó, acaba en el `body` — y la trampa sigue armada un frame más. |
| **A-109** `Banner` (canon) | DOS landmarks `banner` en toda página con cabecera; el `role` se estampa DESPUÉS de los rest props. |
| **A-110** `feature-split` | Único block de sección sin `.Header`: sus filas emiten `h2` y la sección se queda sin nombre. |
### d) Las 15 restantes — trabajo normal
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`A-11` site-header · `A-29` pricing+testimonials · `A-48` banner · `A-53` hero ·
`A-55` banner · `A-60` site-footer · `A-61` contact · `A-62` team · `A-65`
pricing · `A-71` site-footer · `A-74` feature-split · `A-75` pricing · `A-79`
site-footer (SOSP) · `A-92` pricing · `A-96` banner.
⚠️ Dos avisos sobre este grupo: **A-55 no es un defecto visible** (20,5px = 1,6%
del ancho; él lo ve centrado y tiene razón), y **A-65/A-75 son el mismo patrón**
— re-emitir sobre un control que ya emite.
### e) La ola F2b — CERRADA ENTERA 2026-08-18
docs(blocks): la variedad se firma antes de construirla — F2b en cuatro tramos El usuario señaló que el dossier de referencias nos dejaba muy por debajo en variedad. El contraste fila a fila de su §P1 contra los 15 blocks dio 6 filas hechas y 4 resueltas por composición: lo que quedaba pendiente eran DECISIONES de julio, no medidas. Ninguna de las ocho variantes era un hallazgo nuevo — todas estaban ya en el README de su block esperando una firma. Pero ocho variantes no cierran la brecha que se ve, que es de CARDINALIDAD, y el método para esa ya estaba escrito en el dossier (P6.1: demostrar la equivalencia variante-a-variante en vez de competir en número de dumps). La primera versión de la sección no lo trajo y se reescribió entera el mismo día. F2b queda con cuatro tramos: A las variantes de suelo, B la matriz de equivalencia por block —el entregable central, con su plantilla y el guard encendido al final para no dejar 18 READMEs en rojo durante la ola—, C el catálogo que se reabre y D la página compuesta. La regla de forma gana el término que faltaba y que más trabajo hace: una variante alcanzable componiendo es una RECETA demostrada, cero código. Sin él cada fila de las referencias parece pedir un layout nuevo y el tier engorda por imitación. Tres decisiones de catálogo: logo-cloud vuelve (se difirió sobre una premisa que las refs desmienten, y su valor propio es la tinta monocroma derivada de tokens, que nadie más puede dar); blog entra por la misma puerta que team; cookie-consent entra con doctrina propia, porque la ley europea vive en el TIPO — rechazar al mismo nivel que aceptar, no esenciales apagadas por construcción. onboarding NO entra: es un wizard con otro nombre, y duplicar función es la inflación que este modelo existe para evitar. Y el cierre de F2 deja de mentir: cerrada EN UNIDADES. La página compuesta que exigía nunca se construyó, así que el claim de que los blocks ensamblan sin fricción se declara sin demostrar en vez de darse por probado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**La fuente es `PLAN-blocks.md` §F2b** — no dupliques aquí sus tablas. Cuatro
blocks(pricing): un plan solo no se sostenía — la fila necesitaba un tope Segunda fila de la ola F2b, y la que existía para comprobar una sospecha. El README llevaba desde julio diciendo que el plan único «ya lo cubre el layout», diferido por eso. La ficha exigía medirlo antes de darlo por gratis, y no lo cubría. La causa está en la lista de pistas, no en cuántos planes hay: la fila es repeat(auto-fill, minmax(17rem, 1fr)), y auto-fill RESERVA toda pista que quepa, la ocupe alguien o no. Medido a 1280 sobre 992px de fila, un plan solo daba una tarjeta de 315px pegada al borde inicial con 677px de vacío al lado; fijar columns a 1 solo cambiaba eso por una tarjeta de 992px, que es un cartel. Meterlo en un Container sm tampoco: a 640px vuelven a caber dos pistas. Lo que faltaba era un tope sobre la FILA, y la parte no lo dejaba pasar: sus props están cerradas a propósito desde A-94, porque el envoltorio esparce el resto antes de las props que fija y un width del consumidor tipaba y se descartaba en silencio. Así que se abre nombrando: maxWidth entra en el tipo y viaja explícito al AutoGrid, que es exactamente lo que A-94 dejó dicho — el tipo dice lo que la parte honra. El marginX auto va con él sin condición: sin tope la fila ya llena la medida y auto no resuelve a nada. El número lo pone la app. Un block que horneara uno estaría decidiendo cuánto mide un plan; la demo pasa 28rem para uno y 44rem para dos, que es lo que las referencias le dan a cada arreglo, y gana un control vivo de recuento que también viaja en la URL de la vista previa. Medido después: un plan 448px centrado, dos planes 704px en dos pistas de 340 centradas, y tres planes 992px idénticos a antes — el tope es opt-in y no toca el caso que ya existía. A 375 es inerte, porque allí una sola pista ya toma el ancho. Queda anotada la lección en el README y en el handoff, porque no es de este block: una fila «diferida» puede ser una medición equivocada y no un aplazamiento. Nadie había mirado pricing con menos de tres planes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
tramos, en orden: **A** variantes de suelo (~~V4 hero `form`~~ ✅ · ~~V8
blocks(faq): la lista estática, y un tipo que deja de prometer lo que no da La brecha del dossier para este block, y la mayoría del formato: seis de siete en Tailwind Plus no son acordeón, sino una rejilla de preguntas y respuestas siempre abiertas. El eje vive en la LISTA, no en la raíz. Primero porque la lista es lo único que cambia —la cabecera se lee igual—, y segundo porque esa colocación es la que permite que el tipo diga la verdad: pasa a ser una unión discriminada. Bajo acordeón atraviesa toda la superficie del Accordion del canon; bajo lista no se ofrece ninguna de esas props, porque una rejilla estática no tiene estado abierto que enlazar, nada que colapsar ni modo simple o múltiple. Ofrecer una superficie y descartarla en silencio es justo lo que A-94 dejó dicho que no se hace, y aquí es donde iba a morder después. El ítem lee la disposición del contexto: no puede discriminar sobre la unión de la lista sin obligar a la app a repetir el arreglo en cada pregunta. Su value y su disabled quedan documentados como del acordeón, la misma convención que el fondo del hero y la media del cta. Y bajo lista la pregunta es un encabezado de verdad, porque ahí ES el encabezado de su respuesta; bajo acordeón el canon la mete dentro del disparador y esa semántica es suya, así que el block no inventa una segunda. Medido a 1280: en acordeón, cinco disparadores, ningún encabezado, medida de setecientos sesenta y ocho y respuestas ocultas hasta pulsar; en lista, ningún disparador, cinco encabezados, tres pistas de trescientos nueve, medida de mil veinticuatro y todas las respuestas visibles sin tocar nada. A 375 cae a una columna conservando ambas cosas. El acordeón queda idéntico. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
single-price~~ ✅ · ~~V5 cta split~~ ✅ · ~~V2 testimonials spotlight~~ ✅ ·
blocks(pricing): la tabla de comparación, y las palabras que una marca no dice La brecha recurrente del dossier en pricing, y la última fila del primer tramo de la ola. Es una PARTE y no un hermano porque tiene que obedecer al periodo de la sección, y sólo una parte puede leer ese contexto: B-10 le prohíbe a un hermano importar el block que lo posee. Vivir dentro de la sección es además lo que permite que la app meta el precio en una celda y cambie con el conmutador, sin que esta página cablee nada. La app construye la tabla y el block la compone. B-5 admite datos justo donde el canon compuesto ya es data-driven, y la tabla del canon lo es: exige la instancia que devuelve createTable. Así que la parte no inventa un formato de matriz propio ni traduce nada de ida y vuelta, que es el acoplamiento que esa regla existe para evitar. Las tarjetas y la tabla conviven, como en las referencias, alimentadas por el mismo array de planes. Dos cosas que el plan había esbozado y que construirlas demostró equivocadas, y quedan escritas en vez de calladas. No hay un Record de ejes visuales por plan: acentuar una columna es componer canon, que es justo lo que ya permite el snippet de cabecera, y ese Record habría sido una segunda fuente de lo que la app declara en su plan. Y el block no fija la columna: el motor es del app, y meter mano ahí sería el block decidiendo cómo se comporta la tabla de otro. Lo que sí posee es lo que la app no puede: el nombre accesible de la tabla y las palabras que una marca de visto o de guion no dice en voz alta. Ese glifo lleva todo el significado de la celda y es silencio para un lector de pantalla, así que va oculto y la frase viaja en su etiqueta, desde un mapa exhaustivo con respaldo en inglés y su test en las dos direcciones. Y absorbe el cast del canon siendo genérico: la tabla tipa su ranura sin parámetro mientras el motor sí lo devuelve, así que todo consumidor castea, empezando por la demo del propio componente. Aquí se castea una vez a la entrada y se deshace a la salida, para que el snippet de celda devuelva la fila con la forma del app. Medido a 1280 y 375: ocho filas por cuatro columnas, tabla nombrada, marcas que se anuncian, y en móvil la tabla desplaza con la columna de características quieta y la última columna alcanzable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
~~V3 faq-lista~~ ✅ · ~~V1 `Pricing.Compare`~~ ✅ — **TRAMO A CERRADO 6/6 el
blocks(tramo B): las quince matrices, y el guard que ya las exige El entregable central de la ola queda cerrado. Cada block declara ahora, en su propio README, qué composición nuestra alcanza cada variante que shippean las referencias, con la receta exacta, dónde se ha visto y en qué estado queda. Y la regla que gobierna la tabla no admite promesas: una receta que no se ha visto en el navegador no entra. El saldo es lo que la ola buscaba desde que se abrió la pregunta. Unas noventa y cinco filas cubiertas con receta y prueba. Cuatro superaciones con nombre, que ninguna referencia puede expresar porque shippean markup estático: el plan actual que no se puede elegir, las dos secciones que explican por qué un envío está bloqueado, y las cifras que cuentan respetando la preferencia de movimiento. Una veintena de gaps, cada uno con su nombre: la mitad son recetas que existen y no se han enseñado, que es trabajo de demo, y la otra mitad candidatos de canon que ya conocíamos. Y ocho «no se ofrece» con su motivo escrito, que es una postura del sistema y no un agujero — un carrusel en la apertura es movimiento automático sin control de pausa, un mapa es una dependencia externa, filtrar preguntas es estado de datos del app. La primera tabla justificó el tramo entero. El hero declaraba desde julio que el mockup de móvil estaba hecho, y la demo sólo había enseñado el cromo de navegador. El primitivo ofrece tres. Se añadió el control, se midió, y sólo entonces se escribió la fila: una receta declarada no es una receta demostrada, y separarlas es exactamente para lo que este tramo existía. El guard exige ya la sección, encendido al final como mandaba el plan —hacerlo antes habría dejado quince readmes en rojo toda la ola— y con su fixture negativo. Cambiar la regla hizo caer tres fixtures antiguos, que es el self-test haciendo su trabajo, y se actualizaron. Probado en rojo sobre el árbol real: quitándole la sección a team sale su línea exacta, y restaurada vuelve a verde. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
2026-08-17; entra por el tramo B**) · **B** ✅ **CERRADO 2026-08-17** (15 matrices + guard encendido y probado en rojo) — la matriz de
docs(blocks): la variedad se firma antes de construirla — F2b en cuatro tramos El usuario señaló que el dossier de referencias nos dejaba muy por debajo en variedad. El contraste fila a fila de su §P1 contra los 15 blocks dio 6 filas hechas y 4 resueltas por composición: lo que quedaba pendiente eran DECISIONES de julio, no medidas. Ninguna de las ocho variantes era un hallazgo nuevo — todas estaban ya en el README de su block esperando una firma. Pero ocho variantes no cierran la brecha que se ve, que es de CARDINALIDAD, y el método para esa ya estaba escrito en el dossier (P6.1: demostrar la equivalencia variante-a-variante en vez de competir en número de dumps). La primera versión de la sección no lo trajo y se reescribió entera el mismo día. F2b queda con cuatro tramos: A las variantes de suelo, B la matriz de equivalencia por block —el entregable central, con su plantilla y el guard encendido al final para no dejar 18 READMEs en rojo durante la ola—, C el catálogo que se reabre y D la página compuesta. La regla de forma gana el término que faltaba y que más trabajo hace: una variante alcanzable componiendo es una RECETA demostrada, cero código. Sin él cada fila de las referencias parece pedir un layout nuevo y el tier engorda por imitación. Tres decisiones de catálogo: logo-cloud vuelve (se difirió sobre una premisa que las refs desmienten, y su valor propio es la tinta monocroma derivada de tokens, que nadie más puede dar); blog entra por la misma puerta que team; cookie-consent entra con doctrina propia, porque la ley europea vive en el TIPO — rechazar al mismo nivel que aceptar, no esenciales apagadas por construcción. onboarding NO entra: es un wizard con otro nombre, y duplicar función es la inflación que este modelo existe para evitar. Y el cierre de F2 deja de mentir: cerrada EN UNIDADES. La página compuesta que exigía nunca se construyó, así que el claim de que los blocks ensamblan sin fricción se declara sin demostrar en vez de darse por probado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
equivalencia variante-a-variante en el README de cada block, con recetas
demostradas en demo (el entregable central: responde a la brecha de
blocks(cookie-consent): la ley europea como tipo, y las dos salidas al mismo peso Cierra el tramo C de F2b. El único block cuya fase 0 fue jurídica antes que visual: las referencias shippean el aviso como markup, y el markup no puede impedir las tres cosas que lo vuelven ilegal — un rechazo debilitado, categorías premarcadas, y cerrar tratado como consentir. Aquí son el tipo y el constructor. `essential: true` hace inescribible una UI que ofrezca apagarlo; `initialConsent()` no admite semilla, así que una primera pregunta no puede llegar marcada; `onDecision` es obligatoria, así que un aviso que no informa de vuelta no se puede montar. Las cinco reglas están numeradas en consent.ts y afirmadas por 8 tests, porque son justo lo que un refactor rompe en silencio mientras todo sigue pintando bien. Desviación de la ficha, y a favor: UNA llamada requerida `onDecision(consent, via)` en vez de `onAcceptAll` + `onRejectAll`. Con dos callbacks el consumidor podía pasar un no-op a «rechazar»; aquí el camino de rechazo lo renderiza el block y el API no expone knob para degradarlo. Medido: las dos acciones tienen idéntico relleno, tinta, borde, tamaño, peso y alto — 5.96:1 en claro, 8.79:1 en oscuro. Tres cosas se arreglaron por mirar, no por deducir. La barra era un `Card` outline y midió 1.00:1 contra la página: se disolvía en ella, así que va al plano `overlay` del sistema, el mismo que estampa cada superficie flotante del canon. A 375 las tres acciones envolvían con «rechazar» en una fila y «aceptar» en la siguiente, leyéndose como dos botones ajenos justo donde la pareja más importa: ahora son un `Group`, y el markup lo dice. Y el panel devolvía el foco a un nodo muerto — se devuelve aquí, un frame después de que la trampa se desarme, con un pestillo para que el asentamiento del montaje no le robe el foco a nadie al cargar. Tres gaps de canon salieron al componerlo, todos en el README: `Button` acepta `ref` y no lo reenvía (forma de A-94), `Switch` no tiene parte de etiqueta, y el `Dialog` restaura el foco a un nodo muerto cuando su disparador se desmontó. El instrumento mintió antes que el código, otra vez: el pane del navegador no compone frames, así que la animación de salida no termina y un diálogo cerrado sigue pintado — el foco medido allí era ficción. Y `fillStyle` no normaliza oklch, así que todo color leído del estilo computado se volvió negro y dio 1.11:1 sobre texto perfectamente legible. Las cifras de esta ficha se miden por píxel, en Chrome real. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
cardinalidad sin competir en dumps) · **C** ✅ **CERRADO 2026-08-18** (~~`logo-cloud`~~ ✅ con el eje `data-ink` en la fundación · ~~`blog`~~ ✅ como **`article-grid`** — el nombre se decidió en su fase 0 — · ~~`cookie-consent`~~ ✅ con su fase 0 legal: las 5 reglas son el TIPO y 8 tests, y **una sola llamada requerida `onDecision(consent, via)` en vez de las dos de la ficha** — es MÁS fuerte, porque el camino de rechazo lo renderiza el block y no el consumidor, que con dos callbacks podía pasar un no-op) **C** tres blocks nuevos — `logo-cloud`
docs(blocks): la variedad se firma antes de construirla — F2b en cuatro tramos El usuario señaló que el dossier de referencias nos dejaba muy por debajo en variedad. El contraste fila a fila de su §P1 contra los 15 blocks dio 6 filas hechas y 4 resueltas por composición: lo que quedaba pendiente eran DECISIONES de julio, no medidas. Ninguna de las ocho variantes era un hallazgo nuevo — todas estaban ya en el README de su block esperando una firma. Pero ocho variantes no cierran la brecha que se ve, que es de CARDINALIDAD, y el método para esa ya estaba escrito en el dossier (P6.1: demostrar la equivalencia variante-a-variante en vez de competir en número de dumps). La primera versión de la sección no lo trajo y se reescribió entera el mismo día. F2b queda con cuatro tramos: A las variantes de suelo, B la matriz de equivalencia por block —el entregable central, con su plantilla y el guard encendido al final para no dejar 18 READMEs en rojo durante la ola—, C el catálogo que se reabre y D la página compuesta. La regla de forma gana el término que faltaba y que más trabajo hace: una variante alcanzable componiendo es una RECETA demostrada, cero código. Sin él cada fila de las referencias parece pedir un layout nuevo y el tier engorda por imitación. Tres decisiones de catálogo: logo-cloud vuelve (se difirió sobre una premisa que las refs desmienten, y su valor propio es la tinta monocroma derivada de tokens, que nadie más puede dar); blog entra por la misma puerta que team; cookie-consent entra con doctrina propia, porque la ley europea vive en el TIPO — rechazar al mismo nivel que aceptar, no esenciales apagadas por construcción. onboarding NO entra: es un wizard con otro nombre, y duplicar función es la inflación que este modelo existe para evitar. Y el cierre de F2 deja de mentir: cerrada EN UNIDADES. La página compuesta que exigía nunca se construyó, así que el claim de que los blocks ensamblan sin fricción se declara sin demostrar en vez de darse por probado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
(reabierto: las refs lo shippean estático), `blog`, `cookie-consent` (fase 0
legal profunda; la ley vive en el TIPO) — y `onboarding` NO entra (receta de
blocks(landing): las piezas se prueban juntas, y ahí sale lo que ninguna enseñaba sola Cierra el tramo D y con él F2b entera. Una landing verosímil con 14 de los 18 blocks, a sangre y sin marco de demo, porque el claim del tier —que sus blocks ensamblan sin fricción— es indemostrable block a block: el outline de encabezados sólo existe cruzando secciones, dos landmarks sólo chocan cuando hay dos, y una costura vertical sólo aparece cuando algo se pone debajo. Lo que dice la medida: un h1 y 22 encabezados sin un solo salto de nivel; ningún landmark repetido sin nombre; 0px de hueco entre secciones vecinas —el aire es siempre el padding de cada Section, costuras de 112 a 192px—; cuatro de las cinco cascadas esperando a que su sección entre en viewport; un solo commit-submit en el formulario; setenta tabulaciones sin una trampa de foco y un drawer que a 375px devuelve el foco a su disparador. A-95 vuelve confirmado, ahora con cifras: con affix="top" la tira y la cabecera solapan 49px —la altura entera de la cabecera— y el hit-test en su centro cae en la tira, así que la navegación es inalcanzable. La pieza que falta sigue siendo app-shell. La página compone la tira en flujo, que es lo correcto, y deja el escenario del defecto detrás de ?banner=affix para poder medirlo en vez de citarlo. Un defecto arreglado, y era de los que importan: Newsletter.Reason medía 2,33:1 sobre el panel mientras la nota a su lado medía 8,5:1. Es la frase que explica por qué la acción está bloqueada —la que la doctrina de coordinación obliga a tener— y no se podía leer: la doctrina cumplida en la estructura y derrotada en la percepción. El block ya tenía el mecanismo y ya lo había escrito para su nota («más callado por TAMAÑO, no por tinta»); su razón no lo seguía. Ahora 8,83:1 sobre el panel, y muted fuera de él. Dos gaps nuevos, ninguno tocado aquí: los DOS landmarks banner —el canon estampa role="banner" DESPUÉS de sus rest props, así que nombrar ambos es todo lo que puede hacer la app, y esta página lo hace— y feature-split sin parte .Header, el único block de sección que no la tiene: sin ella emite tres h2 hermanos y la sección se queda sin nombre. El catálogo aprendió a publicar páginas: kind: 'page' en BlockEntry y el guard lo salta en las dos direcciones, con self-test propio probado por mutación. Y una lección de instrumento que costó un susto: una captura fullPage no hace scroll, así que toda cascada bajo el pliegue se queda en opacidad 0 y la imagen sale EN BLANCO. La primera medida dijo «la landing está vacía». Saltar de una vez al final del documento tampoco vale: las secciones pasan de debajo a encima en un frame y el observador nunca las ve entrar. Se recorre en pasos. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
`wizard`) · **D** ✅ **CERRADO 2026-08-18** — `web/routes/blocks/landing/`, 14 de 18 blocks a sangre, medidas en su propio README. **F2b QUEDA CERRADA ENTERA.** Lo que dejó: A-95 re-confirmado con cifras (solape 49px = la cabecera entera; falta `app-shell` F3.1) · `Newsletter.Reason` arreglado (2,33 → 8,83:1 sobre el panel: la frase del bloqueo no se leía) · dos gaps nuevos (los DOS landmarks `banner` del canon · `feature-split` sin `.Header`, el único block de sección sin ella) · el catálogo aprendió `kind: 'page'` con guard probado por mutación. ⚠️ **medir una página con motion de viewport**: `fullPage` no hace scroll y sale EN BLANCO, y saltar al final tampoco dispara el observador — se recorre en pasos.
docs(blocks): la variedad se firma antes de construirla — F2b en cuatro tramos El usuario señaló que el dossier de referencias nos dejaba muy por debajo en variedad. El contraste fila a fila de su §P1 contra los 15 blocks dio 6 filas hechas y 4 resueltas por composición: lo que quedaba pendiente eran DECISIONES de julio, no medidas. Ninguna de las ocho variantes era un hallazgo nuevo — todas estaban ya en el README de su block esperando una firma. Pero ocho variantes no cierran la brecha que se ve, que es de CARDINALIDAD, y el método para esa ya estaba escrito en el dossier (P6.1: demostrar la equivalencia variante-a-variante en vez de competir en número de dumps). La primera versión de la sección no lo trajo y se reescribió entera el mismo día. F2b queda con cuatro tramos: A las variantes de suelo, B la matriz de equivalencia por block —el entregable central, con su plantilla y el guard encendido al final para no dejar 18 READMEs en rojo durante la ola—, C el catálogo que se reabre y D la página compuesta. La regla de forma gana el término que faltaba y que más trabajo hace: una variante alcanzable componiendo es una RECETA demostrada, cero código. Sin él cada fila de las referencias parece pedir un layout nuevo y el tier engorda por imitación. Tres decisiones de catálogo: logo-cloud vuelve (se difirió sobre una premisa que las refs desmienten, y su valor propio es la tinta monocroma derivada de tokens, que nadie más puede dar); blog entra por la misma puerta que team; cookie-consent entra con doctrina propia, porque la ley europea vive en el TIPO — rechazar al mismo nivel que aceptar, no esenciales apagadas por construcción. onboarding NO entra: es un wizard con otro nombre, y duplicar función es la inflación que este modelo existe para evitar. Y el cierre de F2 deja de mentir: cerrada EN UNIDADES. La página compuesta que exigía nunca se construyó, así que el claim de que los blocks ensamblan sin fricción se declara sin demostrar en vez de darse por probado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Las 4 filas que la sección «Deuda a decisión tuya» de este handoff listaba
llevan ahí su firma (V1 parte, no hermano · V2/V3 `layout` · V4 slot). V6/V7
(stats-band split-with-image y timeline) salieron a F5: el dossier declara ese
block «Paridad OK».
⚠️ **Lo que dejó V4 y sirve para las que vienen**:
- **Dos gaps de canon** (README del hero §«Found while composing»):
`Form.Submit` no reenvía al `Button` ni `intent` ni eje de anchura — el botón
no llena su celda cuando la fila colapsa, y `newsletter` mide lo mismo, así
que es del canon, no del block. El `justify` de `Grid` es `justify-content`,
no `justify-items`: no se arregla desde fuera. La demo usa `style`, que sí se
reenvía.
- **El contexto de inversión mordió por segunda vez**: bajo `background`, un
`Text` sin `color` explícito mide **1.62:1**; con `on-solid`, 10:1. Bajo
`background` la tinta se pone explícita SIEMPRE.
- **La sonda de contraste**: mide sobre PÍXELES PINTADOS, nunca parseando
colores. Dos sondas dieron cifras seguras y falsas antes (un parser rgb sobre
un sistema que emite `oklch`, y `canvas.fillStyle`, que tampoco normaliza
oklch aquí → medía NEGRO contra todo: 20.46:1 en claro y 1.11:1 en oscuro,
ficción las dos). Control de sanidad: la etiqueta del submit tiene que salir
a **5.18:1**, la cifra que el repo ya documenta para `primary`. Vive en
`scratchpad/v4-final.mjs`.
- **El preview cambia de tema por `?mode=dark`**, no por `prefers-color-scheme`
ni tocando `data-theme` a mano (el boot es el dueño; forzar el atributo NO
repinta y da dos medidas idénticas que parecen «no hay diferencia»).
blocks(pricing): un plan solo no se sostenía — la fila necesitaba un tope Segunda fila de la ola F2b, y la que existía para comprobar una sospecha. El README llevaba desde julio diciendo que el plan único «ya lo cubre el layout», diferido por eso. La ficha exigía medirlo antes de darlo por gratis, y no lo cubría. La causa está en la lista de pistas, no en cuántos planes hay: la fila es repeat(auto-fill, minmax(17rem, 1fr)), y auto-fill RESERVA toda pista que quepa, la ocupe alguien o no. Medido a 1280 sobre 992px de fila, un plan solo daba una tarjeta de 315px pegada al borde inicial con 677px de vacío al lado; fijar columns a 1 solo cambiaba eso por una tarjeta de 992px, que es un cartel. Meterlo en un Container sm tampoco: a 640px vuelven a caber dos pistas. Lo que faltaba era un tope sobre la FILA, y la parte no lo dejaba pasar: sus props están cerradas a propósito desde A-94, porque el envoltorio esparce el resto antes de las props que fija y un width del consumidor tipaba y se descartaba en silencio. Así que se abre nombrando: maxWidth entra en el tipo y viaja explícito al AutoGrid, que es exactamente lo que A-94 dejó dicho — el tipo dice lo que la parte honra. El marginX auto va con él sin condición: sin tope la fila ya llena la medida y auto no resuelve a nada. El número lo pone la app. Un block que horneara uno estaría decidiendo cuánto mide un plan; la demo pasa 28rem para uno y 44rem para dos, que es lo que las referencias le dan a cada arreglo, y gana un control vivo de recuento que también viaja en la URL de la vista previa. Medido después: un plan 448px centrado, dos planes 704px en dos pistas de 340 centradas, y tres planes 992px idénticos a antes — el tope es opt-in y no toca el caso que ya existía. A 375 es inerte, porque allí una sola pista ya toma el ancho. Queda anotada la lección en el README y en el handoff, porque no es de este block: una fila «diferida» puede ser una medición equivocada y no un aplazamiento. Nadie había mirado pricing con menos de tres planes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️ **Y lo que dejó V8, que vale para TODA la ola**: **una fila «diferida» puede
ser una medición equivocada, no un aplazamiento.** El README de `pricing` decía
desde julio que el plan único «ya lo cubre el layout» y era falso — la rejilla
es `auto-fill` y RESERVA las pistas que caben aunque nadie las ocupe (un plan
solo: card de 315px con 677px de vacío al lado). Nadie había mirado ese block
con menos de tres planes. Antes de dar por buena una disposición vieja de
cualquier README, mídela.
blocks(testimonials): una cita sola no va en una tarjeta La brecha que el dossier le apuntaba a este block: la cita única es la variante modal de todas las referencias y el grid la minoría, dos de ocho en Tailwind Plus. Entra como disposición, no como hermano. La anatomía no cambia —cita, autor, avatar—, sólo cómo se colocan, y el precedente es el fondo del hero, que también redefine lo que hacen sus partes. El hermano se reabre sólo si algún día pide rotación o carrusel, que es otro componente. Viaja por contexto de configuración, el patrón del align de feature-grid y team, no la coordinación de pricing. Y viaja porque el spotlight no es una piel sobre las mismas cajas: la rejilla deja de serlo y de estampar el ritmo estructural —que es para una FILA, no para una cita—, el ítem pierde la tarjeta, la cita sube de tamaño y se centra, y el autor pasa debajo, donde ya no hay una hilera de caras que alinear. Pedirle a la app que repita esa decisión en cinco partes es el agujero que A-84 cerró en feature-grid. Enmarcar una cita sola la hace parecer un ítem de una lista que no está ahí, así que ahí no hay tarjeta y el tipo lo dice, en vez de aceptar una superficie que luego descarta. La cita se centra con un párrafo de verdad: sobre una caja en línea el centrado no aplica, y sería mentira. Slot nuevo para la marca de quien firma, en las dos disposiciones: es lo que hace que una cita se lea como evidencia y no como una opinión, y es la pieza que ponen todas las referencias. Medido: en grid, cinco tarjetas, veinte píxeles, medida de mil veinticuatro y ritmo escalonado; en spotlight, cero tarjetas, una cita de veintiocho centrada en párrafo, medida de setecientos sesenta y ocho, autor centrado y sin escalonado; a 375 la cita cae a veinticuatro. El grid queda idéntico a antes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️ **Y dos cosas del árbol COMPARTIDO, medidas el 2026-08-17**: otra sesión está
a medias con un componente **`background`** (toca `morfo/`, `langs/` y
`eidos/generated`), así que `svelte-check` da 73 con cosas que no son del tier —
la base real sin nadie es **60**. Y **no hagas `git stash --include-untracked`
aquí**: arrastra su trabajo sin commitear. Si necesitas una base, mide por
fichero.
docs(blocks): la variedad se firma antes de construirla — F2b en cuatro tramos El usuario señaló que el dossier de referencias nos dejaba muy por debajo en variedad. El contraste fila a fila de su §P1 contra los 15 blocks dio 6 filas hechas y 4 resueltas por composición: lo que quedaba pendiente eran DECISIONES de julio, no medidas. Ninguna de las ocho variantes era un hallazgo nuevo — todas estaban ya en el README de su block esperando una firma. Pero ocho variantes no cierran la brecha que se ve, que es de CARDINALIDAD, y el método para esa ya estaba escrito en el dossier (P6.1: demostrar la equivalencia variante-a-variante en vez de competir en número de dumps). La primera versión de la sección no lo trajo y se reescribió entera el mismo día. F2b queda con cuatro tramos: A las variantes de suelo, B la matriz de equivalencia por block —el entregable central, con su plantilla y el guard encendido al final para no dejar 18 READMEs en rojo durante la ola—, C el catálogo que se reabre y D la página compuesta. La regla de forma gana el término que faltaba y que más trabajo hace: una variante alcanzable componiendo es una RECETA demostrada, cero código. Sin él cada fila de las referencias parece pedir un layout nuevo y el tier engorda por imitación. Tres decisiones de catálogo: logo-cloud vuelve (se difirió sobre una premisa que las refs desmienten, y su valor propio es la tinta monocroma derivada de tokens, que nadie más puede dar); blog entra por la misma puerta que team; cookie-consent entra con doctrina propia, porque la ley europea vive en el TIPO — rechazar al mismo nivel que aceptar, no esenciales apagadas por construcción. onboarding NO entra: es un wizard con otro nombre, y duplicar función es la inflación que este modelo existe para evitar. Y el cierre de F2 deja de mentir: cerrada EN UNIDADES. La página compuesta que exigía nunca se construyó, así que el claim de que los blocks ensamblan sin fricción se declara sin demostrar en vez de darse por probado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### e) Cabos y fases
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
1. **Tres cabos concretos**:
- Un **desbordamiento de texto en las cards del card-group** que el usuario ve
y que NO se reprodujo a 1280 en claro ni en oscuro. Falta el ancho de ventana.
- Los **hermanos del `Field`** (`password-field`, `search-field`, `textarea`)
declaran su propio `commit-submit` copiando el patrón: pueden duplicar igual
dentro de un `Form`. Se comprueba en un comando con la sonda (abajo).
docs(blocks): la variedad se firma antes de construirla — F2b en cuatro tramos El usuario señaló que el dossier de referencias nos dejaba muy por debajo en variedad. El contraste fila a fila de su §P1 contra los 15 blocks dio 6 filas hechas y 4 resueltas por composición: lo que quedaba pendiente eran DECISIONES de julio, no medidas. Ninguna de las ocho variantes era un hallazgo nuevo — todas estaban ya en el README de su block esperando una firma. Pero ocho variantes no cierran la brecha que se ve, que es de CARDINALIDAD, y el método para esa ya estaba escrito en el dossier (P6.1: demostrar la equivalencia variante-a-variante en vez de competir en número de dumps). La primera versión de la sección no lo trajo y se reescribió entera el mismo día. F2b queda con cuatro tramos: A las variantes de suelo, B la matriz de equivalencia por block —el entregable central, con su plantilla y el guard encendido al final para no dejar 18 READMEs en rojo durante la ola—, C el catálogo que se reabre y D la página compuesta. La regla de forma gana el término que faltaba y que más trabajo hace: una variante alcanzable componiendo es una RECETA demostrada, cero código. Sin él cada fila de las referencias parece pedir un layout nuevo y el tier engorda por imitación. Tres decisiones de catálogo: logo-cloud vuelve (se difirió sobre una premisa que las refs desmienten, y su valor propio es la tinta monocroma derivada de tokens, que nadie más puede dar); blog entra por la misma puerta que team; cookie-consent entra con doctrina propia, porque la ley europea vive en el TIPO — rechazar al mismo nivel que aceptar, no esenciales apagadas por construcción. onboarding NO entra: es un wizard con otro nombre, y duplicar función es la inflación que este modelo existe para evitar. Y el cierre de F2 deja de mentir: cerrada EN UNIDADES. La página compuesta que exigía nunca se construyó, así que el claim de que los blocks ensamblan sin fricción se declara sin demostrar en vez de darse por probado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **La página compuesta** dejó de ser un cabo suelto: es el tramo D de F2b.
2. **F3 del plan original** (10 blocks de aplicación), ya con orden recomendado
en el plan: **`app-shell` PRIMERO** (desbloquea A-95 y F4.1); `data-table` y
`kanban` al final por su fase 0 obligada.
## ⚠️ El sonido CAMBIÓ DE MODELO el mismo día — léelo antes de tocar un pack
Mientras esta sesión trabajaba, la de sema rehízo el sonido dos veces. Modelo
vigente (`CONTINUE-sema-audit.md` §3.0-bis):
```
nombre = per-emit ?? cascada ?? pack ?? morfo ?? familia[verbo] ?? familia.default
sonido = pack[`${nombre}.${intent}`] ?? pack[nombre] ?? nada
```
- **`soundTuning()`, `SOUND_TUNINGS` y `sound()` están RETIRADOS**, con guard
propio (`sounds-grammar.test.ts`). El sonido ya no se modula: **se elige**. Un
intent selecciona OTRO sonido entero, no doblega el mismo.
- **El sonido lo decide el mapa, por VERBO** (`SEMA_MAP.families[f].sounds`), así
que **un pack escribe una regla sólo cuando DIFIERE del default**: de ~165
reglas a 30 en 71 packs. Un pack migrado es casi sólo selectores.
- **`allowedTargets`** en el morfo declara a qué partes puede viajar el estampado.
- Guard de **distinguibilidad**: dos nombres han de diferir en ≥2 ejes.
**Qué significa para la cola de este handoff**: nada se invalida — lo pendiente es
QUÉ evento se emite y SOBRE QUÉ parte, no cómo suena. Lo que cambia es el método:
si al arreglar un confirmado hiciera falta tocar el sonido, ya no se afina, se
NOMBRA; y si el nombre no existe, se registra en el catálogo antes de usarlo.
El pack de `navigation-menu` de esta sesión ilustra el encaje: la otra sesión lo
migró encima y **las tres reglas sobrevivieron sin su `sound:`** — la aportación
era a qué parte apunta cada una, y eso es ortogonal al modelo de sonido.
## La sonda de sema — `G:/tmp/sonda-sema.mjs`
Herramienta nueva, y la forma de contestar «¿esto suena?» sin discutirlo:
```bash
node G:/tmp/sonda-sema.mjs <url> <enter|click|hover> [selector]
```
Dice, por gesto, cuántos nodos de audio se crean y qué eventos se estampan con su
familia e intent. Con ella se midió el doble `commit-submit` del `Field` (2
eventos a 11 ms y 4 nodos de audio → 1 y 2) y el mudo del `NavigationMenu.Link`.
⚠️ Sesgo conocido: asocia los metadatos por ventana temporal de 30 ms, así que
puede atribuir el `intent` de un evento vecino. El `contact-activate` NO lleva
intent (morfo de Button, cap. 22 §11).
feat(blocks): `contact` — el primer block que COORDINA (estado, datos y palabras) WIP declarado: el block funciona y renderiza, pero el arco interactivo completo no está verificado todavía. Lo que falta está en `CONTINUE-blocks.md`, en orden. ## El cambio de doctrina Decisión del usuario, textual: «si al final es una lista de componentes… el bloque es coordinación, estado, y data también». El motivo se veía en este mismo block: con el estado fuera, cada `disabled` era una expresión distinta montada en el punto de uso, y aparecían huecos — un envío que no se podía hacer y nadie decía por qué. Eso cambia lo firmado en `docs/architecture/blocks.md` (B-5/B-7, D-BLK). Queda ANOTADO como pendiente de escribir en el contrato: propagarlo sin actualizarlo sería deriva. ## Lo que ahora posee el block - **La máquina de estado** (`state.ts`): `incomplete · unverified · verifying · rejected · ready · sending · sent`, derivada de la validez del `Form`, del veredicto de verificación y del envío. Con dos registros EXHAUSTIVOS — `CONTACT_REASON` y `CONTACT_ACTION`— que hacen imposible un estado mudo: no se puede añadir un estado que bloquee el envío sin darle su frase, porque el `Record` obliga. - **La forma de los datos** (`schema.ts`): nombre · correo · mensaje, con las etiquetas como idlangref. El app lo sustituye pasando su `form` + `schema`. - **Las palabras**, por el traductor (`#?blocks.contact.…|fallback`), la misma puerta que usa el canon para sus `texts:`. Partes nuevas: `Contact.Fields` (los tres campos del esquema propio), `Contact.Submit` (bloqueo Y etiqueta desde el estado, nunca desde una expresión en el punto de uso) y `Contact.Reason` (la frase del estado). `Contact.Form` toma el handle del contexto en vez de pedirlo otra vez. La demo adelgaza en consecuencia: se le cayeron el esquema, las etiquetas, el `disabled`, el flag de envío y la frase. Le queda lo que es de un app — las palabras de la página, los datos de contacto, el reto que elige y qué significa «enviar». ## De paso, dos arreglos de composición - El `TextArea` iba dentro de `Field.Control` y salían DOS marcos: pinta su propia carcasa (borde, radio y relleno son de su recipe). `Field.Control` es la carcasa del `Field.Input` desnudo. - El `Form.ErrorSummary` vacío dejaba una caja naranja: su raíz pinta borde de riesgo en cuanto el form es inválido, aunque la lista esté vacía. ## Dos hilos de canon abiertos (medidos, sin causa raíz) - Con `progressive`/`onSubmit`, un envío inválido bloquea y mueve el foco pero no expone mensajes; con `onChange` sí, pero saltan los tres campos al escribir en uno. La máquina tapa el agujero de cara al usuario; el hueco sigue. - El provider de `ProofOfHuman` escribe `status` él mismo, así que el veredicto que devuelve el app no se sostiene y los slots `stage*` no renderizaron nunca. Gates: `blocks:check` verde (14 blocks) · `svelte-check` sin errores propios · prettier limpio. Verificado que la sección renderiza (section · form · 3 campos · submit · cero errores de página) en un dev server limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️⚠️ **Y su límite, que el handoff de sema documenta como lección cara**: contar
nodos de audio **no es medir la salida**. Sirve para «¿emite o no emite?», que es
para lo que se usó aquí. Para «¿suena como debe?» hay que renderizar el grafo
offline (`OfflineAudioContext`) y medir el pico de muestra — ahí se descubrió que
una firma «silenciada» salía a −13.9 dBFS.
feat(blocks): `contact` — el primer block que COORDINA (estado, datos y palabras) WIP declarado: el block funciona y renderiza, pero el arco interactivo completo no está verificado todavía. Lo que falta está en `CONTINUE-blocks.md`, en orden. ## El cambio de doctrina Decisión del usuario, textual: «si al final es una lista de componentes… el bloque es coordinación, estado, y data también». El motivo se veía en este mismo block: con el estado fuera, cada `disabled` era una expresión distinta montada en el punto de uso, y aparecían huecos — un envío que no se podía hacer y nadie decía por qué. Eso cambia lo firmado en `docs/architecture/blocks.md` (B-5/B-7, D-BLK). Queda ANOTADO como pendiente de escribir en el contrato: propagarlo sin actualizarlo sería deriva. ## Lo que ahora posee el block - **La máquina de estado** (`state.ts`): `incomplete · unverified · verifying · rejected · ready · sending · sent`, derivada de la validez del `Form`, del veredicto de verificación y del envío. Con dos registros EXHAUSTIVOS — `CONTACT_REASON` y `CONTACT_ACTION`— que hacen imposible un estado mudo: no se puede añadir un estado que bloquee el envío sin darle su frase, porque el `Record` obliga. - **La forma de los datos** (`schema.ts`): nombre · correo · mensaje, con las etiquetas como idlangref. El app lo sustituye pasando su `form` + `schema`. - **Las palabras**, por el traductor (`#?blocks.contact.…|fallback`), la misma puerta que usa el canon para sus `texts:`. Partes nuevas: `Contact.Fields` (los tres campos del esquema propio), `Contact.Submit` (bloqueo Y etiqueta desde el estado, nunca desde una expresión en el punto de uso) y `Contact.Reason` (la frase del estado). `Contact.Form` toma el handle del contexto en vez de pedirlo otra vez. La demo adelgaza en consecuencia: se le cayeron el esquema, las etiquetas, el `disabled`, el flag de envío y la frase. Le queda lo que es de un app — las palabras de la página, los datos de contacto, el reto que elige y qué significa «enviar». ## De paso, dos arreglos de composición - El `TextArea` iba dentro de `Field.Control` y salían DOS marcos: pinta su propia carcasa (borde, radio y relleno son de su recipe). `Field.Control` es la carcasa del `Field.Input` desnudo. - El `Form.ErrorSummary` vacío dejaba una caja naranja: su raíz pinta borde de riesgo en cuanto el form es inválido, aunque la lista esté vacía. ## Dos hilos de canon abiertos (medidos, sin causa raíz) - Con `progressive`/`onSubmit`, un envío inválido bloquea y mueve el foco pero no expone mensajes; con `onChange` sí, pero saltan los tres campos al escribir en uno. La máquina tapa el agujero de cara al usuario; el hueco sigue. - El provider de `ProofOfHuman` escribe `status` él mismo, así que el veredicto que devuelve el app no se sostiene y los slots `stage*` no renderizaron nunca. Gates: `blocks:check` verde (14 blocks) · `svelte-check` sin errores propios · prettier limpio. Verificado que la sección renderiza (section · form · 3 campos · submit · cero errores de página) en un dev server limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
> ⚠️ **CAMBIO DE DOCTRINA (decisión del usuario, 2026-07-31).** Lee la sección
> «La doctrina cambió» antes de tocar nada: un block ya no es solo colocación.
feat(blocks): contact CERRADO — la coordinacion entra en el contrato B El estado se le pregunta al ESQUEMA, no al Form. `form.isValid` con `validationBehaviour: 'progressive'` significa «aun no se ha encontrado nada mal»: un formulario vacio e intacto no tiene errores, asi que se declaraba valido y `incomplete` era INALCANZABLE al cargar — la seccion pedia resolver la verificacion con los tres campos vacios, justo el hueco que la doctrina existe para cerrar. Ahora la raiz valida los valores con `validateSync` de SIUM: sincrono y sin escribir errores (`form.validate()` habria encendido los tres campos en rojo en el primer frame). `state.test.ts` fija la maquina con 9 casos — primer test unitario del tier, porque `state.ts` es su primera logica pura: el orden de prioridad, que solo `ready` deja enviar, y que todo estado bloqueado tiene frase. Contrato B (architecture/blocks.md): seccion «Coordination» con las tres cosas que posee un block que coordina (estado, forma de sus datos, palabras), B-5 admite el esquema por defecto, B-7 enmendado (posee las palabras de SUS estados como idlangref con fallback ingles) y la convencion de servicios acotada: el traductor es el UNICO servicio sancionado. Dice tambien a quien NO aplica — los blocks de layout no coordinan nada. i18n por la via real: el arnes registra el namespace `blocks` en las DOS cadenas de arranque (galeria y previews, que duplican el boot) y la demo se lee en castellano en vez de caer al fallback ingles. Ademas: README y pestanas de doc rehechos al reparto nuevo, ficha F2.13 y bitacora en PLAN-blocks.md, y el control vivo que faltaba para un prop publico — `verification` con reto / sin reto, porque omitir el prop no es lo mismo que pasar un estado que nunca verifica. Verificado en navegador, arco completo y las dos ramas: sin reto vacio → un campo → tres campos (se desbloquea) → «Enviando…» → «Enviado»; con reto, con los tres campos llenos el boton sigue bloqueado y la razon pasa a «Resuelve la verificacion de arriba». `verifying` y `rejected` quedan cubiertos por test unitario, no por el reto en vivo: el provider de ProofOfHuman escribe `status` el mismo y el veredicto del app no se sostiene (hilo de canon abierto). Gates: blocks:check verde (14 blocks) · vitest 9/9 · docs:check 0 · svelte-check sin errores propios · prettier limpio en los ficheros propios. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
> Ya está ESCRITA en el contrato (`architecture/blocks.md` §«Coordination»).
feat(blocks): F2.3 `feature-grid` — el primer block compound del tier `<FeatureGrid>` + `.Header` + `.Items` + `.Item` + `.ItemIcon`/`.ItemTitle`/ `.ItemText`: una cabecera sobre una rejilla responsive de features (icono · título · texto). Es la sección que responde «qué hace», la nº1 tras el hero. Primer block COMPOUND del tier, y aplica la regla de forma que fijamos: el `.Item` se REPITE (el app mapea sobre N features) → gana sub-componentes, donde `hero`/`site-header` usan slots de snippet (partes fijas de layout). Las partes no coordinan —sin contexto ni estado entre ellas—: la rejilla es del padre, las celdas del app. `.Items` es el envoltorio honesto de la rejilla (`AutoGrid`), que deja la cabecera fuera sin un `grid-column: 1/-1` a pelo. - El block coloca (Section · Container · AutoGrid · Surface · Heading · Text); el app pone todo el contenido por children (B-7). - `.Items` fluido por `minChildWidth` (tantas columnas como quepan) o `columns` fijas; `.Item` `align` start/center; `.ItemIcon` chip `Surface`; `.ItemTitle` `Heading` h3; `.ItemText` `Text` apagado. - `align` de sección (center/start) coloca la cabecera coherente con las columnas. Dos cosas encontradas al construir, resueltas: - **Los sub-componentes de bloque extienden los props del componente canon que envuelven** (`BoxProps`, `StackProps`, `HeadingProps`…), **no `HTMLAttributes`**: el `style: string|null` del atributo HTML crudo choca con el `style: string` del canon al hacer spread (+ "union type too complex"). - **`.ItemIcon` por defecto `solid`, no `soft`**: el soft-primary en claro es casi blanco (oklch 0.99) → el chip era invisible; solid da el chip con glifo on-solid (la tinta de contraste la pone `Surface`). Demo (`web/routes/blocks/feature-grid/`): full-bleed + ruta `preview`, con control de columnas (fluido/2/3/4), align, nº de items y dir; 6 features con iconos del canon. Hueco a decisión del usuario (en los Gaps del block): el **feature-split/ alternante** (texto junto a un screenshot, lados alternos) — la brecha nº1 del dossier — es otra disposición (filas de 2 columnas, no rejilla de iconos): probablemente un block hermano `feature-split`. Presentado, no resuelto. Verificado en navegador (Playwright, módulos frescos): center/start × claro/ oscuro × LTR/RTL, columnas fluidas y fijas, 3/4/6 items, chips visibles. `blocks:check` verde (3 blocks) · `svelte-check` sin errores propios. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
(El plan fijó 14; `feature-split` se añadió como block hermano con
scope-approval, así que el tier tiene 15 y el denominador honesto es 15.)
fix(blocks): lo que la auditoría encontró DENTRO del tier Una auditoría multi-agente (7 dimensiones doctrinales + refutación adversarial) confirmó 32 hallazgos sobre la pasada de calidad. Esto corrige los que caen dentro de `blocks/`; la deuda de fuera queda REGISTRADA, no tocada (`PLAN-blocks-quality.md` §6). - **B-7 roto en `pricing`**: el block traía tres strings castellanas propias como defaults del toggle — dos visibles y un nombre accesible. Hardcodeaba un idioma DENTRO del framework y esquivaba `langs`, en el mismo block cuyo README predica «cero strings propias». Ahora los tres son props REQUERIDAS y las pone la app. - **El block pintaba**: `pricing.Plan` metía `box-shadow` por `style=` porque `Card` no expone elevación. Retirado; el hueco queda registrado como candidato a canon en vez de falseado. - **El escalonado estaba roto y el comentario mentía**: puse `spring-pop` (driver JS) en los planes, y un driver JS no lee el `animation-delay` donde vive el stagger — entraban TODOS a la vez mientras el comentario afirmaba lo contrario. Vuelto al preset CSS: verificado, índices 0,1,2 a 70ms. - **Comentario falso en la demo del hero**: atribuía al `intent` visual una consecuencia sonora/háptica que ningún camino produce (el morfo del Button dice explícitamente que `contact-activate` NO lleva intent). Reescrito. - **Composition maps mentían**: los 6 blocks que ahora componen `Motion` no lo decían; el hero seguía diciendo `Heading` (es `Display`), sin `Backdrop` ni `decor`, y declaraba DIFERIDO un preset de cromo de media que ya está shipeado (`Mockup`). Al día, sin filas duplicadas ni datos rancios (el chip de feature-grid es `solid`, no `soft`). - **Handoff y plan**: el plan seguía prescribiendo un `<Reveal>` que esta misma sesión creó y retiró; el handoff daba `feature-split` por «sin decidir» estando hecho, y los gates con números falsos. Verificado: `blocks:check` verde (7) · `svelte-check` sin errores propios · en el navegador, pricing escalona de nuevo, las etiquetas vienen de la app y ninguna tarjeta pinta sombra. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2 months ago
Commiteado en `alpha-0.1-dir-prefs` (`866089a40` + este handoff). SIN PUSH.
feat(blocks): F2.3 `feature-grid` — el primer block compound del tier `<FeatureGrid>` + `.Header` + `.Items` + `.Item` + `.ItemIcon`/`.ItemTitle`/ `.ItemText`: una cabecera sobre una rejilla responsive de features (icono · título · texto). Es la sección que responde «qué hace», la nº1 tras el hero. Primer block COMPOUND del tier, y aplica la regla de forma que fijamos: el `.Item` se REPITE (el app mapea sobre N features) → gana sub-componentes, donde `hero`/`site-header` usan slots de snippet (partes fijas de layout). Las partes no coordinan —sin contexto ni estado entre ellas—: la rejilla es del padre, las celdas del app. `.Items` es el envoltorio honesto de la rejilla (`AutoGrid`), que deja la cabecera fuera sin un `grid-column: 1/-1` a pelo. - El block coloca (Section · Container · AutoGrid · Surface · Heading · Text); el app pone todo el contenido por children (B-7). - `.Items` fluido por `minChildWidth` (tantas columnas como quepan) o `columns` fijas; `.Item` `align` start/center; `.ItemIcon` chip `Surface`; `.ItemTitle` `Heading` h3; `.ItemText` `Text` apagado. - `align` de sección (center/start) coloca la cabecera coherente con las columnas. Dos cosas encontradas al construir, resueltas: - **Los sub-componentes de bloque extienden los props del componente canon que envuelven** (`BoxProps`, `StackProps`, `HeadingProps`…), **no `HTMLAttributes`**: el `style: string|null` del atributo HTML crudo choca con el `style: string` del canon al hacer spread (+ "union type too complex"). - **`.ItemIcon` por defecto `solid`, no `soft`**: el soft-primary en claro es casi blanco (oklch 0.99) → el chip era invisible; solid da el chip con glifo on-solid (la tinta de contraste la pone `Surface`). Demo (`web/routes/blocks/feature-grid/`): full-bleed + ruta `preview`, con control de columnas (fluido/2/3/4), align, nº de items y dir; 6 features con iconos del canon. Hueco a decisión del usuario (en los Gaps del block): el **feature-split/ alternante** (texto junto a un screenshot, lados alternos) — la brecha nº1 del dossier — es otra disposición (filas de 2 columnas, no rejilla de iconos): probablemente un block hermano `feature-split`. Presentado, no resuelto. Verificado en navegador (Playwright, módulos frescos): center/start × claro/ oscuro × LTR/RTL, columnas fluidas y fijas, 3/4/6 items, chips visibles. `blocks:check` verde (3 blocks) · `svelte-check` sin errores propios. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Dónde vive cada cosa:
feat(blocks): F2.2 `hero` — center · split · background, por slots Segundo block del tier. API por SLOTS DE SNIPPET, no compound: la forma se razonó con el usuario y con el paisaje de referencia. Compound se reserva para partes que COORDINAN (estado/contexto/ARIA entre ellas — Accordion, Dialog); un hero son cinco slots de layout que no se hablan entre sí y que el root arregla, así que snippets. Además el campo entero shippea marketing como copy-paste plano —nadie aplica compound a una sección—, y los slots por zona son la historia de personalización que distingue al tier del copy-paste. `<Hero layout="center|split|background" level container size>` + `eyebrow/title/description/actions/media/background/children`. - El block **envuelve** título y subtítulo en `Heading`/`Text`: así posee el `id` que nombra el `<section aria-labelledby>` y el nivel del encabezado, mientras la app pone las palabras (B-7). `eyebrow`/`actions`/`media` son contenido libre (ahí los componentes del canon SON la API). - `center` = `Stack` centrado, media debajo (ancho-capado); `split` = `Grid` de dos columnas (una sola sin media), apila en estrecho. - **`background` (cover)** — añadido por scope-approval del usuario: la media a sangre detrás de la copy, con velo de contraste (`--color-overlay` a `--opacity-scrim`), texto `on-solid` y `object-fit: cover` vía un `<style>` justificado (D-BLK.2). Son las ÚNICAS reglas que el block posee, todas sobre tokens del ecosistema — cero color a mano. Capas por orden de fuente, sin `z-index`. Demo (`web/routes/blocks/hero/`): full-bleed en la página + ruta `preview` para anchos de dispositivo, cada prop un control vivo, y el backdrop del layout cover dogfooda el sistema de color — es un `Surface color="primary" gradient` (finish aurora = `--gradient-aurora`, derivado de los roles del tema; cambia con la paleta). Mini-site compartido por las dos superficies (`HeroSite.svelte`). Encontrado al componer, registrado no resuelto: `Box`/`Surface` `flex`/`grow` no hicieron crecer un hijo flex (bars a 0-width, `flex: 0 1 auto`; la prop no la usa ningún componente shipped). La demo usó `Grid` (tracks `1fr`). Flag en el README del block y en el handoff para revisar el cableado de `--box-flex`. Verificado en navegador (Playwright headless, módulos frescos): center/split/ background × claro/oscuro × LTR/RTL, media on/off, y el landmark nombrado (región con `aria-labelledby` que resuelve al título). `blocks:check` verde (2 blocks) · `svelte-check` sin errores propios. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Plan y bitácora por block**: `docs/process/PLAN-blocks.md` (fichas §F2.x +
registro cronológico al final, con el detalle de cada cierre).
- **Contrato del tier**: `docs/architecture/blocks.md` (B-1..B-11, D-BLK).
- **Suelo de paridad**: `docs/process/RESEARCH-blocks-references.md` (el dossier).
- **Deuda de canon congelada**: `docs/process/PLAN-blocks-quality.md` §6.
- **Decisiones por block**: el README de cada uno (`src/uix/blocks/{kebab}/`).
docs(blocks): registro de F2.1, doctrina de demo del tier y handoff Documentación al día de lo que se cerró hoy y handoff para retomar mañana. - `PLAN-blocks.md` §7: **F2.1 `site-header` HECHA** con sus siete commits, la fase 0 contra el dossier §P1, el landmark que le faltaba a `NavigationMenu` (arreglado en el canon, no parcheado en el block), el hueco del CTA que navega y parece botón (registrado, no falseado) y el defecto de framework que destapó la demo. - `theming/changelog.md` §46: las 44 variables de cascada de `Box` dejan de heredarse. Un `Section` regalaba su padding a cada descendiente —la galería arrastraba ~300px de aire desde F0— y los hijos heredaban anchos y `display` ajenos. `@property { inherits: false }`, radio verificado sin regresiones. Lección: una variable que un componente escribe para SÍ MISMO debe declararse `inherits: false`; si no, deja de ser un prop y se vuelve un contagio. - `architecture/blocks.md` B-9: la demo de un block se construye sobre el harness compartido y el block se enseña A SANGRE — nunca dentro de un marco con relleno ni de una caja con scroll, porque eso cambia lo que el block hace. - `src/uix/blocks/README.md`: anatomía de la demo (harness, `{Name}Site`, ruta `preview`, `DocRow`, catálogo único, ejes en el shell). - `CONTINUE-blocks.md` (nuevo): handoff — qué toca (F2.2 `hero`), la plantilla de ficheros para copiar, las reglas que ya costaron sangre (a sangre, iframe solo para anchos de dispositivo, cada prop un control, nada de backticks en `<Text>`, ojo con las variables que heredan), la deuda declarada que es decisión del usuario y el estado exacto de los gates. Gates al parar: `blocks:check` verde · `svelte-check` 73 errores, todos deuda ajena (0 propios) · `vitest src/uix/eidos` 353/353 · `contracts.test` con los 3 fallos ajenos conocidos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
---
feat(blocks): `contact` — el primer block que COORDINA (estado, datos y palabras) WIP declarado: el block funciona y renderiza, pero el arco interactivo completo no está verificado todavía. Lo que falta está en `CONTINUE-blocks.md`, en orden. ## El cambio de doctrina Decisión del usuario, textual: «si al final es una lista de componentes… el bloque es coordinación, estado, y data también». El motivo se veía en este mismo block: con el estado fuera, cada `disabled` era una expresión distinta montada en el punto de uso, y aparecían huecos — un envío que no se podía hacer y nadie decía por qué. Eso cambia lo firmado en `docs/architecture/blocks.md` (B-5/B-7, D-BLK). Queda ANOTADO como pendiente de escribir en el contrato: propagarlo sin actualizarlo sería deriva. ## Lo que ahora posee el block - **La máquina de estado** (`state.ts`): `incomplete · unverified · verifying · rejected · ready · sending · sent`, derivada de la validez del `Form`, del veredicto de verificación y del envío. Con dos registros EXHAUSTIVOS — `CONTACT_REASON` y `CONTACT_ACTION`— que hacen imposible un estado mudo: no se puede añadir un estado que bloquee el envío sin darle su frase, porque el `Record` obliga. - **La forma de los datos** (`schema.ts`): nombre · correo · mensaje, con las etiquetas como idlangref. El app lo sustituye pasando su `form` + `schema`. - **Las palabras**, por el traductor (`#?blocks.contact.…|fallback`), la misma puerta que usa el canon para sus `texts:`. Partes nuevas: `Contact.Fields` (los tres campos del esquema propio), `Contact.Submit` (bloqueo Y etiqueta desde el estado, nunca desde una expresión en el punto de uso) y `Contact.Reason` (la frase del estado). `Contact.Form` toma el handle del contexto en vez de pedirlo otra vez. La demo adelgaza en consecuencia: se le cayeron el esquema, las etiquetas, el `disabled`, el flag de envío y la frase. Le queda lo que es de un app — las palabras de la página, los datos de contacto, el reto que elige y qué significa «enviar». ## De paso, dos arreglos de composición - El `TextArea` iba dentro de `Field.Control` y salían DOS marcos: pinta su propia carcasa (borde, radio y relleno son de su recipe). `Field.Control` es la carcasa del `Field.Input` desnudo. - El `Form.ErrorSummary` vacío dejaba una caja naranja: su raíz pinta borde de riesgo en cuanto el form es inválido, aunque la lista esté vacía. ## Dos hilos de canon abiertos (medidos, sin causa raíz) - Con `progressive`/`onSubmit`, un envío inválido bloquea y mueve el foco pero no expone mensajes; con `onChange` sí, pero saltan los tres campos al escribir en uno. La máquina tapa el agujero de cara al usuario; el hueco sigue. - El provider de `ProofOfHuman` escribe `status` él mismo, así que el veredicto que devuelve el app no se sostiene y los slots `stage*` no renderizaron nunca. Gates: `blocks:check` verde (14 blocks) · `svelte-check` sin errores propios · prettier limpio. Verificado que la sección renderiza (section · form · 3 campos · submit · cero errores de página) en un dev server limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## La doctrina cambió: un block coordina, tiene estado y trae datos
Decisión del usuario, textual: **«si al final es una lista de componentes… el
bloque es coordinación, estado, y data también»**. El motivo, con el `contact`
delante: cuando el estado vive fuera, cada `disabled` es una expresión distinta
montada en el punto de uso y aparecen **huecos** — un envío que no se puede hacer
y nadie dice por qué.
Lo que cambia respecto de lo firmado en `docs/architecture/blocks.md` (B-5/B-7 y
D-BLK: «todo el contenido por snippets, cero cadenas propias, sin servicios»):
1. **El block posee el estado de su sección.** Una máquina única y EXHAUSTIVA,
derivada, en contexto. Sus partes la leen; ninguna la recalcula ni inventa un
`disabled`.
2. **El block trae la forma de sus datos** (el esquema por defecto). El app lo
sustituye pasando el suyo.
3. **El block habla**, con idlangrefs por el traductor
(`#?blocks.<block>.<clave>|fallback`), la misma puerta que usa el canon para
sus `texts:`. Fallback en inglés; el app traduce registrando `blocks.*`.
feat(blocks): contact CERRADO — la coordinacion entra en el contrato B El estado se le pregunta al ESQUEMA, no al Form. `form.isValid` con `validationBehaviour: 'progressive'` significa «aun no se ha encontrado nada mal»: un formulario vacio e intacto no tiene errores, asi que se declaraba valido y `incomplete` era INALCANZABLE al cargar — la seccion pedia resolver la verificacion con los tres campos vacios, justo el hueco que la doctrina existe para cerrar. Ahora la raiz valida los valores con `validateSync` de SIUM: sincrono y sin escribir errores (`form.validate()` habria encendido los tres campos en rojo en el primer frame). `state.test.ts` fija la maquina con 9 casos — primer test unitario del tier, porque `state.ts` es su primera logica pura: el orden de prioridad, que solo `ready` deja enviar, y que todo estado bloqueado tiene frase. Contrato B (architecture/blocks.md): seccion «Coordination» con las tres cosas que posee un block que coordina (estado, forma de sus datos, palabras), B-5 admite el esquema por defecto, B-7 enmendado (posee las palabras de SUS estados como idlangref con fallback ingles) y la convencion de servicios acotada: el traductor es el UNICO servicio sancionado. Dice tambien a quien NO aplica — los blocks de layout no coordinan nada. i18n por la via real: el arnes registra el namespace `blocks` en las DOS cadenas de arranque (galeria y previews, que duplican el boot) y la demo se lee en castellano en vez de caer al fallback ingles. Ademas: README y pestanas de doc rehechos al reparto nuevo, ficha F2.13 y bitacora en PLAN-blocks.md, y el control vivo que faltaba para un prop publico — `verification` con reto / sin reto, porque omitir el prop no es lo mismo que pasar un estado que nunca verifica. Verificado en navegador, arco completo y las dos ramas: sin reto vacio → un campo → tres campos (se desbloquea) → «Enviando…» → «Enviado»; con reto, con los tres campos llenos el boton sigue bloqueado y la razon pasa a «Resuelve la verificacion de arriba». `verifying` y `rejected` quedan cubiertos por test unitario, no por el reto en vivo: el provider de ProofOfHuman escribe `status` el mismo y el veredicto del app no se sostiene (hilo de canon abierto). Gates: blocks:check verde (14 blocks) · vitest 9/9 · docs:check 0 · svelte-check sin errores propios · prettier limpio en los ficheros propios. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**ESCRITO** (2026-07-31): `architecture/blocks.md` gana la sección
«Coordination», B-5 admite que el block traiga la FORMA de sus datos, B-7 queda
enmendado (posee las palabras de SUS estados, como idlangref con fallback
inglés) y la convención de servicios se acota. La sección dice también a quién NO
aplica.
**Enmendado el 2026-08-06**: los servicios sancionados son DOS — el traductor,
que resuelve las palabras, y el anunciador (`uix.announce`), que las entrega a la
tecnología asistiva. Entró por la misma razón que el primero: un block que posee
las palabras de sus estados tiene que poder decirlas, y montar una región viva
propia re-implementa `Announce`.
feat(blocks): `contact` — el primer block que COORDINA (estado, datos y palabras) WIP declarado: el block funciona y renderiza, pero el arco interactivo completo no está verificado todavía. Lo que falta está en `CONTINUE-blocks.md`, en orden. ## El cambio de doctrina Decisión del usuario, textual: «si al final es una lista de componentes… el bloque es coordinación, estado, y data también». El motivo se veía en este mismo block: con el estado fuera, cada `disabled` era una expresión distinta montada en el punto de uso, y aparecían huecos — un envío que no se podía hacer y nadie decía por qué. Eso cambia lo firmado en `docs/architecture/blocks.md` (B-5/B-7, D-BLK). Queda ANOTADO como pendiente de escribir en el contrato: propagarlo sin actualizarlo sería deriva. ## Lo que ahora posee el block - **La máquina de estado** (`state.ts`): `incomplete · unverified · verifying · rejected · ready · sending · sent`, derivada de la validez del `Form`, del veredicto de verificación y del envío. Con dos registros EXHAUSTIVOS — `CONTACT_REASON` y `CONTACT_ACTION`— que hacen imposible un estado mudo: no se puede añadir un estado que bloquee el envío sin darle su frase, porque el `Record` obliga. - **La forma de los datos** (`schema.ts`): nombre · correo · mensaje, con las etiquetas como idlangref. El app lo sustituye pasando su `form` + `schema`. - **Las palabras**, por el traductor (`#?blocks.contact.…|fallback`), la misma puerta que usa el canon para sus `texts:`. Partes nuevas: `Contact.Fields` (los tres campos del esquema propio), `Contact.Submit` (bloqueo Y etiqueta desde el estado, nunca desde una expresión en el punto de uso) y `Contact.Reason` (la frase del estado). `Contact.Form` toma el handle del contexto en vez de pedirlo otra vez. La demo adelgaza en consecuencia: se le cayeron el esquema, las etiquetas, el `disabled`, el flag de envío y la frase. Le queda lo que es de un app — las palabras de la página, los datos de contacto, el reto que elige y qué significa «enviar». ## De paso, dos arreglos de composición - El `TextArea` iba dentro de `Field.Control` y salían DOS marcos: pinta su propia carcasa (borde, radio y relleno son de su recipe). `Field.Control` es la carcasa del `Field.Input` desnudo. - El `Form.ErrorSummary` vacío dejaba una caja naranja: su raíz pinta borde de riesgo en cuanto el form es inválido, aunque la lista esté vacía. ## Dos hilos de canon abiertos (medidos, sin causa raíz) - Con `progressive`/`onSubmit`, un envío inválido bloquea y mueve el foco pero no expone mensajes; con `onChange` sí, pero saltan los tres campos al escribir en uno. La máquina tapa el agujero de cara al usuario; el hueco sigue. - El provider de `ProofOfHuman` escribe `status` él mismo, así que el veredicto que devuelve el app no se sostiene y los slots `stage*` no renderizaron nunca. Gates: `blocks:check` verde (14 blocks) · `svelte-check` sin errores propios · prettier limpio. Verificado que la sección renderiza (section · form · 3 campos · submit · cero errores de página) en un dev server limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(blocks): cada block declara su posicion bajo la doctrina de coordinacion Y `content-section.Media` pasa a seguir al texto por defecto. DEFAULT: `.Media` era `width='wide'`, asi que una figura se salia de la columna SALVO que dijeras lo contrario. Al reves de lo que hacen todas las referencias (en `@tailwindcss/typography` una imagen dentro de `prose` queda capada a la medida y salirse exige el truco del `translate`; en `markdown-body` de GitHub, `max-width: 100%` de la columna). Ahora el default es `measure` — la figura sigue al texto y el escape se PIDE. Cambiado en los cuatro sitios que decian lo contrario: la parte, la ruta `preview`, el estado inicial del control de la demo (una demo que pisa el default en silencio ensena algo que el block no hace solo) y la doc. Verificado: 528 = ancho del texto exacto a 1011/1280/1920, y `wide` / `full` siguen funcionando cuando se piden. DOCUMENTACION: los 15 READMEs declaran ahora su posicion bajo §«Coordination», y el mapa real no es uniforme — - Coordinan: `contact` (maquina + esquema + palabras) y `pricing` (el periodo por contexto). Pero en pricing nada se puede BLOQUEAR, asi que no necesita maquina ni palabras: coordinar no es siempre una maquina. - Comparten CONFIGURACION, no estado: `team` (`align`) y `content-section` (la medida). - Costura bindable hacia el canon: `faq` (`value` → `Accordion`) y `site-header` (`mobileOpen` → `Drawer`). Reenviar no es poseer. - No poseen nada: banner · cta · feature-grid · feature-split · hero · site-footer · stats-band · testimonials. Decirlo explicitamente es el punto: inventarle estado a un block que no coordina nada es el error contrario. - `newsletter` queda como CANDIDATO ABIERTO: coloca un envio que puede quedar bloqueado sin que nada diga por que — el `disabled` lo monta el app en el punto de uso — que es exactamente el hueco que cerro `contact`. Es anterior a la doctrina (block del 30-07, doctrina del 31-07). Registrado, no asumido: se toca con decision del usuario. El README del tier apunta a la doctrina y el handoff recoge el mapa completo. Gates: blocks:check verde (15) · docs:check 0 · svelte-check sin errores en lo tocado · prettier limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Alcance acordado**: `contact` primero como prueba de la forma — **HECHO**.
**Revisión documental de los 15 HECHA** (2026-08-01): cada README declara ahora
su posición bajo la doctrina, y el mapa real salió así —
- **Coordinan**: `contact` (máquina + esquema + palabras) · `pricing` (el periodo
por contexto, pero nada se puede BLOQUEAR ahí, así que no necesita máquina ni
palabras: coordinar no es siempre una máquina).
- **Comparten configuración, no estado**: `team` (`align`) · `content-section`
(la medida).
- **Costura bindable hacia el canon**: `faq` (`value` → `Accordion`) ·
`site-header` (`mobileOpen` → `Drawer`). Reenviar no es poseer.
- **No poseen nada**: banner · cta · feature-grid · feature-split · hero ·
site-footer · stats-band · testimonials.
- ✅ **`newsletter` COORDINA desde 2026-08-06** — era el candidato abierto de esta
lista y ya está cerrado. Máquina de cinco estados (`incomplete · invalid ·
ready · sending · sent`), dos `Record` exhaustivos de razón y acción, y
`Newsletter.Submit` / `Newsletter.Reason` como PARTES que leen el contexto: la
regla de forma del tier aplicada, no una excepción — compound se gana cuando las
partes repiten o **coordinan**. `state.test.ts` con 8 casos.
feat(blocks): contact CERRADO — la coordinacion entra en el contrato B El estado se le pregunta al ESQUEMA, no al Form. `form.isValid` con `validationBehaviour: 'progressive'` significa «aun no se ha encontrado nada mal»: un formulario vacio e intacto no tiene errores, asi que se declaraba valido y `incomplete` era INALCANZABLE al cargar — la seccion pedia resolver la verificacion con los tres campos vacios, justo el hueco que la doctrina existe para cerrar. Ahora la raiz valida los valores con `validateSync` de SIUM: sincrono y sin escribir errores (`form.validate()` habria encendido los tres campos en rojo en el primer frame). `state.test.ts` fija la maquina con 9 casos — primer test unitario del tier, porque `state.ts` es su primera logica pura: el orden de prioridad, que solo `ready` deja enviar, y que todo estado bloqueado tiene frase. Contrato B (architecture/blocks.md): seccion «Coordination» con las tres cosas que posee un block que coordina (estado, forma de sus datos, palabras), B-5 admite el esquema por defecto, B-7 enmendado (posee las palabras de SUS estados como idlangref con fallback ingles) y la convencion de servicios acotada: el traductor es el UNICO servicio sancionado. Dice tambien a quien NO aplica — los blocks de layout no coordinan nada. i18n por la via real: el arnes registra el namespace `blocks` en las DOS cadenas de arranque (galeria y previews, que duplican el boot) y la demo se lee en castellano en vez de caer al fallback ingles. Ademas: README y pestanas de doc rehechos al reparto nuevo, ficha F2.13 y bitacora en PLAN-blocks.md, y el control vivo que faltaba para un prop publico — `verification` con reto / sin reto, porque omitir el prop no es lo mismo que pasar un estado que nunca verifica. Verificado en navegador, arco completo y las dos ramas: sin reto vacio → un campo → tres campos (se desbloquea) → «Enviando…» → «Enviado»; con reto, con los tres campos llenos el boton sigue bloqueado y la razon pasa a «Resuelve la verificacion de arriba». `verifying` y `rejected` quedan cubiertos por test unitario, no por el reto en vivo: el provider de ProofOfHuman escribe `status` el mismo y el veredicto del app no se sostiene (hilo de canon abierto). Gates: blocks:check verde (14 blocks) · vitest 9/9 · docs:check 0 · svelte-check sin errores propios · prettier limpio en los ficheros propios. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️ Al revisarlos, el listón es el que dejó `contact`: **el estado se deriva de
una fuente y las partes lo leen**; si un estado puede bloquear algo, tiene frase
por `Record` exhaustivo. Y **no inventes estado donde no lo hay** — un block de
layout que no coordina nada se queda como está.
feat(blocks): `contact` — el primer block que COORDINA (estado, datos y palabras) WIP declarado: el block funciona y renderiza, pero el arco interactivo completo no está verificado todavía. Lo que falta está en `CONTINUE-blocks.md`, en orden. ## El cambio de doctrina Decisión del usuario, textual: «si al final es una lista de componentes… el bloque es coordinación, estado, y data también». El motivo se veía en este mismo block: con el estado fuera, cada `disabled` era una expresión distinta montada en el punto de uso, y aparecían huecos — un envío que no se podía hacer y nadie decía por qué. Eso cambia lo firmado en `docs/architecture/blocks.md` (B-5/B-7, D-BLK). Queda ANOTADO como pendiente de escribir en el contrato: propagarlo sin actualizarlo sería deriva. ## Lo que ahora posee el block - **La máquina de estado** (`state.ts`): `incomplete · unverified · verifying · rejected · ready · sending · sent`, derivada de la validez del `Form`, del veredicto de verificación y del envío. Con dos registros EXHAUSTIVOS — `CONTACT_REASON` y `CONTACT_ACTION`— que hacen imposible un estado mudo: no se puede añadir un estado que bloquee el envío sin darle su frase, porque el `Record` obliga. - **La forma de los datos** (`schema.ts`): nombre · correo · mensaje, con las etiquetas como idlangref. El app lo sustituye pasando su `form` + `schema`. - **Las palabras**, por el traductor (`#?blocks.contact.…|fallback`), la misma puerta que usa el canon para sus `texts:`. Partes nuevas: `Contact.Fields` (los tres campos del esquema propio), `Contact.Submit` (bloqueo Y etiqueta desde el estado, nunca desde una expresión en el punto de uso) y `Contact.Reason` (la frase del estado). `Contact.Form` toma el handle del contexto en vez de pedirlo otra vez. La demo adelgaza en consecuencia: se le cayeron el esquema, las etiquetas, el `disabled`, el flag de envío y la frase. Le queda lo que es de un app — las palabras de la página, los datos de contacto, el reto que elige y qué significa «enviar». ## De paso, dos arreglos de composición - El `TextArea` iba dentro de `Field.Control` y salían DOS marcos: pinta su propia carcasa (borde, radio y relleno son de su recipe). `Field.Control` es la carcasa del `Field.Input` desnudo. - El `Form.ErrorSummary` vacío dejaba una caja naranja: su raíz pinta borde de riesgo en cuanto el form es inválido, aunque la lista esté vacía. ## Dos hilos de canon abiertos (medidos, sin causa raíz) - Con `progressive`/`onSubmit`, un envío inválido bloquea y mueve el foco pero no expone mensajes; con `onChange` sí, pero saltan los tres campos al escribir en uno. La máquina tapa el agujero de cara al usuario; el hueco sigue. - El provider de `ProofOfHuman` escribe `status` él mismo, así que el veredicto que devuelve el app no se sostiene y los slots `stage*` no renderizaron nunca. Gates: `blocks:check` verde (14 blocks) · `svelte-check` sin errores propios · prettier limpio. Verificado que la sección renderiza (section · form · 3 campos · submit · cero errores de página) en un dev server limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
---
feat(blocks): contact CERRADO — la coordinacion entra en el contrato B El estado se le pregunta al ESQUEMA, no al Form. `form.isValid` con `validationBehaviour: 'progressive'` significa «aun no se ha encontrado nada mal»: un formulario vacio e intacto no tiene errores, asi que se declaraba valido y `incomplete` era INALCANZABLE al cargar — la seccion pedia resolver la verificacion con los tres campos vacios, justo el hueco que la doctrina existe para cerrar. Ahora la raiz valida los valores con `validateSync` de SIUM: sincrono y sin escribir errores (`form.validate()` habria encendido los tres campos en rojo en el primer frame). `state.test.ts` fija la maquina con 9 casos — primer test unitario del tier, porque `state.ts` es su primera logica pura: el orden de prioridad, que solo `ready` deja enviar, y que todo estado bloqueado tiene frase. Contrato B (architecture/blocks.md): seccion «Coordination» con las tres cosas que posee un block que coordina (estado, forma de sus datos, palabras), B-5 admite el esquema por defecto, B-7 enmendado (posee las palabras de SUS estados como idlangref con fallback ingles) y la convencion de servicios acotada: el traductor es el UNICO servicio sancionado. Dice tambien a quien NO aplica — los blocks de layout no coordinan nada. i18n por la via real: el arnes registra el namespace `blocks` en las DOS cadenas de arranque (galeria y previews, que duplican el boot) y la demo se lee en castellano en vez de caer al fallback ingles. Ademas: README y pestanas de doc rehechos al reparto nuevo, ficha F2.13 y bitacora en PLAN-blocks.md, y el control vivo que faltaba para un prop publico — `verification` con reto / sin reto, porque omitir el prop no es lo mismo que pasar un estado que nunca verifica. Verificado en navegador, arco completo y las dos ramas: sin reto vacio → un campo → tres campos (se desbloquea) → «Enviando…» → «Enviado»; con reto, con los tres campos llenos el boton sigue bloqueado y la razon pasa a «Resuelve la verificacion de arriba». `verifying` y `rejected` quedan cubiertos por test unitario, no por el reto en vivo: el provider de ProofOfHuman escribe `status` el mismo y el veredicto del app no se sostiene (hilo de canon abierto). Gates: blocks:check verde (14 blocks) · vitest 9/9 · docs:check 0 · svelte-check sin errores propios · prettier limpio en los ficheros propios. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## F2.13 `contact` — CERRADO (2026-07-31)
Los seis puntos que quedaban están hechos: arco verificado en navegador · README
rehecho · pestañas de doc al día · namespace `blocks` registrado en el arnés ·
ficha §F2.13 + bitácora en `PLAN-blocks.md` · contrato B actualizado.
**Un defecto real, encontrado al verificar**: la máquina leía `form.isValid`,
que con `progressive` significa «aún no se ha encontrado nada mal» — un
formulario vacío e intacto no tiene errores, así que se declaraba válido y
`incomplete` era INALCANZABLE al cargar: la sección pedía resolver la
verificación con los tres campos vacíos. Justo el hueco que la doctrina existe
para cerrar. Se arregla preguntando al ESQUEMA (`validateSync` de SIUM: síncrono
y sin escribir errores; `form.validate()` habría encendido los tres campos en
rojo al cargar). Fijado con `state.test.ts` — 9 casos, **primer test unitario
del tier**, porque `state.ts` es su primera lógica pura.
Añadido de paso el control vivo que faltaba para un prop público:
`verification` con reto / sin reto. **Omitir el prop NO es pasar `idle`**: sin
él la sección no tiene paso de verificación; con un estado que nunca llega a
`verified` tienes una verificación que no pasa, que es otra cosa.
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
feat(blocks): `contact` — el primer block que COORDINA (estado, datos y palabras) WIP declarado: el block funciona y renderiza, pero el arco interactivo completo no está verificado todavía. Lo que falta está en `CONTINUE-blocks.md`, en orden. ## El cambio de doctrina Decisión del usuario, textual: «si al final es una lista de componentes… el bloque es coordinación, estado, y data también». El motivo se veía en este mismo block: con el estado fuera, cada `disabled` era una expresión distinta montada en el punto de uso, y aparecían huecos — un envío que no se podía hacer y nadie decía por qué. Eso cambia lo firmado en `docs/architecture/blocks.md` (B-5/B-7, D-BLK). Queda ANOTADO como pendiente de escribir en el contrato: propagarlo sin actualizarlo sería deriva. ## Lo que ahora posee el block - **La máquina de estado** (`state.ts`): `incomplete · unverified · verifying · rejected · ready · sending · sent`, derivada de la validez del `Form`, del veredicto de verificación y del envío. Con dos registros EXHAUSTIVOS — `CONTACT_REASON` y `CONTACT_ACTION`— que hacen imposible un estado mudo: no se puede añadir un estado que bloquee el envío sin darle su frase, porque el `Record` obliga. - **La forma de los datos** (`schema.ts`): nombre · correo · mensaje, con las etiquetas como idlangref. El app lo sustituye pasando su `form` + `schema`. - **Las palabras**, por el traductor (`#?blocks.contact.…|fallback`), la misma puerta que usa el canon para sus `texts:`. Partes nuevas: `Contact.Fields` (los tres campos del esquema propio), `Contact.Submit` (bloqueo Y etiqueta desde el estado, nunca desde una expresión en el punto de uso) y `Contact.Reason` (la frase del estado). `Contact.Form` toma el handle del contexto en vez de pedirlo otra vez. La demo adelgaza en consecuencia: se le cayeron el esquema, las etiquetas, el `disabled`, el flag de envío y la frase. Le queda lo que es de un app — las palabras de la página, los datos de contacto, el reto que elige y qué significa «enviar». ## De paso, dos arreglos de composición - El `TextArea` iba dentro de `Field.Control` y salían DOS marcos: pinta su propia carcasa (borde, radio y relleno son de su recipe). `Field.Control` es la carcasa del `Field.Input` desnudo. - El `Form.ErrorSummary` vacío dejaba una caja naranja: su raíz pinta borde de riesgo en cuanto el form es inválido, aunque la lista esté vacía. ## Dos hilos de canon abiertos (medidos, sin causa raíz) - Con `progressive`/`onSubmit`, un envío inválido bloquea y mueve el foco pero no expone mensajes; con `onChange` sí, pero saltan los tres campos al escribir en uno. La máquina tapa el agujero de cara al usuario; el hueco sigue. - El provider de `ProofOfHuman` escribe `status` él mismo, así que el veredicto que devuelve el app no se sostiene y los slots `stage*` no renderizaron nunca. Gates: `blocks:check` verde (14 blocks) · `svelte-check` sin errores propios · prettier limpio. Verificado que la sección renderiza (section · form · 3 campos · submit · cero errores de página) en un dev server limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️ **Ojo con el dev server de otra sesión**: el de `:5173` sirvió un módulo VACÍO
para `blocks/contact/index.ts` (500 «does not provide an export named Contact»)
porque tenía el grafo caducado tras crear ficheros nuevos. Arrancado uno propio en
otro puerto, la página va perfecta. Si mañana ves ese 500, es eso: no persigas el
código.
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
feat(blocks): `contact` — el primer block que COORDINA (estado, datos y palabras) WIP declarado: el block funciona y renderiza, pero el arco interactivo completo no está verificado todavía. Lo que falta está en `CONTINUE-blocks.md`, en orden. ## El cambio de doctrina Decisión del usuario, textual: «si al final es una lista de componentes… el bloque es coordinación, estado, y data también». El motivo se veía en este mismo block: con el estado fuera, cada `disabled` era una expresión distinta montada en el punto de uso, y aparecían huecos — un envío que no se podía hacer y nadie decía por qué. Eso cambia lo firmado en `docs/architecture/blocks.md` (B-5/B-7, D-BLK). Queda ANOTADO como pendiente de escribir en el contrato: propagarlo sin actualizarlo sería deriva. ## Lo que ahora posee el block - **La máquina de estado** (`state.ts`): `incomplete · unverified · verifying · rejected · ready · sending · sent`, derivada de la validez del `Form`, del veredicto de verificación y del envío. Con dos registros EXHAUSTIVOS — `CONTACT_REASON` y `CONTACT_ACTION`— que hacen imposible un estado mudo: no se puede añadir un estado que bloquee el envío sin darle su frase, porque el `Record` obliga. - **La forma de los datos** (`schema.ts`): nombre · correo · mensaje, con las etiquetas como idlangref. El app lo sustituye pasando su `form` + `schema`. - **Las palabras**, por el traductor (`#?blocks.contact.…|fallback`), la misma puerta que usa el canon para sus `texts:`. Partes nuevas: `Contact.Fields` (los tres campos del esquema propio), `Contact.Submit` (bloqueo Y etiqueta desde el estado, nunca desde una expresión en el punto de uso) y `Contact.Reason` (la frase del estado). `Contact.Form` toma el handle del contexto en vez de pedirlo otra vez. La demo adelgaza en consecuencia: se le cayeron el esquema, las etiquetas, el `disabled`, el flag de envío y la frase. Le queda lo que es de un app — las palabras de la página, los datos de contacto, el reto que elige y qué significa «enviar». ## De paso, dos arreglos de composición - El `TextArea` iba dentro de `Field.Control` y salían DOS marcos: pinta su propia carcasa (borde, radio y relleno son de su recipe). `Field.Control` es la carcasa del `Field.Input` desnudo. - El `Form.ErrorSummary` vacío dejaba una caja naranja: su raíz pinta borde de riesgo en cuanto el form es inválido, aunque la lista esté vacía. ## Dos hilos de canon abiertos (medidos, sin causa raíz) - Con `progressive`/`onSubmit`, un envío inválido bloquea y mueve el foco pero no expone mensajes; con `onChange` sí, pero saltan los tres campos al escribir en uno. La máquina tapa el agujero de cara al usuario; el hueco sigue. - El provider de `ProofOfHuman` escribe `status` él mismo, así que el veredicto que devuelve el app no se sostiene y los slots `stage*` no renderizaron nunca. Gates: `blocks:check` verde (14 blocks) · `svelte-check` sin errores propios · prettier limpio. Verificado que la sección renderiza (section · form · 3 campos · submit · cero errores de página) en un dev server limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Dos hilos de canon abiertos (medidos, sin causa raíz)
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
feat(blocks): `contact` — el primer block que COORDINA (estado, datos y palabras) WIP declarado: el block funciona y renderiza, pero el arco interactivo completo no está verificado todavía. Lo que falta está en `CONTINUE-blocks.md`, en orden. ## El cambio de doctrina Decisión del usuario, textual: «si al final es una lista de componentes… el bloque es coordinación, estado, y data también». El motivo se veía en este mismo block: con el estado fuera, cada `disabled` era una expresión distinta montada en el punto de uso, y aparecían huecos — un envío que no se podía hacer y nadie decía por qué. Eso cambia lo firmado en `docs/architecture/blocks.md` (B-5/B-7, D-BLK). Queda ANOTADO como pendiente de escribir en el contrato: propagarlo sin actualizarlo sería deriva. ## Lo que ahora posee el block - **La máquina de estado** (`state.ts`): `incomplete · unverified · verifying · rejected · ready · sending · sent`, derivada de la validez del `Form`, del veredicto de verificación y del envío. Con dos registros EXHAUSTIVOS — `CONTACT_REASON` y `CONTACT_ACTION`— que hacen imposible un estado mudo: no se puede añadir un estado que bloquee el envío sin darle su frase, porque el `Record` obliga. - **La forma de los datos** (`schema.ts`): nombre · correo · mensaje, con las etiquetas como idlangref. El app lo sustituye pasando su `form` + `schema`. - **Las palabras**, por el traductor (`#?blocks.contact.…|fallback`), la misma puerta que usa el canon para sus `texts:`. Partes nuevas: `Contact.Fields` (los tres campos del esquema propio), `Contact.Submit` (bloqueo Y etiqueta desde el estado, nunca desde una expresión en el punto de uso) y `Contact.Reason` (la frase del estado). `Contact.Form` toma el handle del contexto en vez de pedirlo otra vez. La demo adelgaza en consecuencia: se le cayeron el esquema, las etiquetas, el `disabled`, el flag de envío y la frase. Le queda lo que es de un app — las palabras de la página, los datos de contacto, el reto que elige y qué significa «enviar». ## De paso, dos arreglos de composición - El `TextArea` iba dentro de `Field.Control` y salían DOS marcos: pinta su propia carcasa (borde, radio y relleno son de su recipe). `Field.Control` es la carcasa del `Field.Input` desnudo. - El `Form.ErrorSummary` vacío dejaba una caja naranja: su raíz pinta borde de riesgo en cuanto el form es inválido, aunque la lista esté vacía. ## Dos hilos de canon abiertos (medidos, sin causa raíz) - Con `progressive`/`onSubmit`, un envío inválido bloquea y mueve el foco pero no expone mensajes; con `onChange` sí, pero saltan los tres campos al escribir en uno. La máquina tapa el agujero de cara al usuario; el hueco sigue. - El provider de `ProofOfHuman` escribe `status` él mismo, así que el veredicto que devuelve el app no se sostiene y los slots `stage*` no renderizaron nunca. Gates: `blocks:check` verde (14 blocks) · `svelte-check` sin errores propios · prettier limpio. Verificado que la sección renderiza (section · form · 3 campos · submit · cero errores de página) en un dev server limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
1. **`Form`/SIUM**: con `progressive`/`onSubmit`, un envío inválido bloquea y
mueve el foco pero **no expone mensajes** (`form.errors` vacío). Con `onChange`
sí aparecen —y traducidos—, pero saltan en los tres campos al escribir en uno;
con `onBlur` aparecen desde la carga. La máquina de estado del block TAPA el
agujero de cara al usuario (el botón dice qué falta), pero el hueco sigue ahí.
2. **`ProofOfHuman`**: el provider de soma escribe `status` él mismo
(`writableActive`), así que el veredicto que devuelve el app tras consultar a su
servidor no se sostiene, y los slots `stage*` no renderizaron en ningún estado.
feat(blocks): contact CERRADO — la coordinacion entra en el contrato B El estado se le pregunta al ESQUEMA, no al Form. `form.isValid` con `validationBehaviour: 'progressive'` significa «aun no se ha encontrado nada mal»: un formulario vacio e intacto no tiene errores, asi que se declaraba valido y `incomplete` era INALCANZABLE al cargar — la seccion pedia resolver la verificacion con los tres campos vacios, justo el hueco que la doctrina existe para cerrar. Ahora la raiz valida los valores con `validateSync` de SIUM: sincrono y sin escribir errores (`form.validate()` habria encendido los tres campos en rojo en el primer frame). `state.test.ts` fija la maquina con 9 casos — primer test unitario del tier, porque `state.ts` es su primera logica pura: el orden de prioridad, que solo `ready` deja enviar, y que todo estado bloqueado tiene frase. Contrato B (architecture/blocks.md): seccion «Coordination» con las tres cosas que posee un block que coordina (estado, forma de sus datos, palabras), B-5 admite el esquema por defecto, B-7 enmendado (posee las palabras de SUS estados como idlangref con fallback ingles) y la convencion de servicios acotada: el traductor es el UNICO servicio sancionado. Dice tambien a quien NO aplica — los blocks de layout no coordinan nada. i18n por la via real: el arnes registra el namespace `blocks` en las DOS cadenas de arranque (galeria y previews, que duplican el boot) y la demo se lee en castellano en vez de caer al fallback ingles. Ademas: README y pestanas de doc rehechos al reparto nuevo, ficha F2.13 y bitacora en PLAN-blocks.md, y el control vivo que faltaba para un prop publico — `verification` con reto / sin reto, porque omitir el prop no es lo mismo que pasar un estado que nunca verifica. Verificado en navegador, arco completo y las dos ramas: sin reto vacio → un campo → tres campos (se desbloquea) → «Enviando…» → «Enviado»; con reto, con los tres campos llenos el boton sigue bloqueado y la razon pasa a «Resuelve la verificacion de arriba». `verifying` y `rejected` quedan cubiertos por test unitario, no por el reto en vivo: el provider de ProofOfHuman escribe `status` el mismo y el veredicto del app no se sostiene (hilo de canon abierto). Gates: blocks:check verde (14 blocks) · vitest 9/9 · docs:check 0 · svelte-check sin errores propios · prettier limpio en los ficheros propios. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
El camino «rechazado» no es contable hoy desde el app. **Consecuencia medida en
`contact`**: sus estados `verifying` y `rejected` quedan cubiertos por test
unitario de la máquina, no por el reto en vivo.
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
---
## La regla de forma del tier (no la re-decidas)
Compound **solo** si las partes:
- **SE REPITEN** — el app mapea sobre N (`feature-grid.Item`,
`testimonials.Item`, `pricing.Plan`, `faq.Item`, `stats-band.Stat`,
`site-footer.Column`), o
- **COORDINAN** — se hablan por contexto (`pricing.Switch` ↔ `PlanPrice`).
Si no hacen ninguna de las dos: **slots de snippet** en la raíz (`hero`, `cta`,
`newsletter`, y la marca / alta / social / legal / extra de `site-footer`). El
plan original dibujaba varias de esas como partes; la desviación está registrada
en cada README.
---
## Los 8 hallazgos de canon que dejó el tier (congelados)
Restricción del usuario en vigor: **no tocar componentes ni librerías fuera de
`src/uix/blocks/` y `web/routes/blocks/`**. Están todos medidos en navegador
y listados en `PLAN-blocks-quality.md` §6 (F15–F22) — más los de motion (A1, A2,
A4, C7, C8, C10, D12, E14) de la pasada de calidad.
docs(blocks): registro de F2.1, doctrina de demo del tier y handoff Documentación al día de lo que se cerró hoy y handoff para retomar mañana. - `PLAN-blocks.md` §7: **F2.1 `site-header` HECHA** con sus siete commits, la fase 0 contra el dossier §P1, el landmark que le faltaba a `NavigationMenu` (arreglado en el canon, no parcheado en el block), el hueco del CTA que navega y parece botón (registrado, no falseado) y el defecto de framework que destapó la demo. - `theming/changelog.md` §46: las 44 variables de cascada de `Box` dejan de heredarse. Un `Section` regalaba su padding a cada descendiente —la galería arrastraba ~300px de aire desde F0— y los hijos heredaban anchos y `display` ajenos. `@property { inherits: false }`, radio verificado sin regresiones. Lección: una variable que un componente escribe para SÍ MISMO debe declararse `inherits: false`; si no, deja de ser un prop y se vuelve un contagio. - `architecture/blocks.md` B-9: la demo de un block se construye sobre el harness compartido y el block se enseña A SANGRE — nunca dentro de un marco con relleno ni de una caja con scroll, porque eso cambia lo que el block hace. - `src/uix/blocks/README.md`: anatomía de la demo (harness, `{Name}Site`, ruta `preview`, `DocRow`, catálogo único, ejes en el shell). - `CONTINUE-blocks.md` (nuevo): handoff — qué toca (F2.2 `hero`), la plantilla de ficheros para copiar, las reglas que ya costaron sangre (a sangre, iframe solo para anchos de dispositivo, cada prop un control, nada de backticks en `<Text>`, ojo con las variables que heredan), la deuda declarada que es decisión del usuario y el estado exacto de los gates. Gates al parar: `blocks:check` verde · `svelte-check` 73 errores, todos deuda ajena (0 propios) · `vitest src/uix/eidos` 353/353 · `contracts.test` con los 3 fallos ajenos conocidos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| # | Qué |
| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| F15 | `Surface variant='soft'` **no acota un panel**: su track queda a 0.002 de luminancia del fondo de página en claro, y `Surface` no tiene borde. `Card outline` sí acota pero no acepta `gradient` → «panel sosegado con borde» no tiene primitivo. |
| F16 | La ranura `contrast` de la paleta es **blanca en todo escalón sólido**, así que un lienzo de luminancia media deja el cuerpo bajo AA: `primary` 5.18 · `indigo` 5.21 · `plum` 4.75 pasan; `neutral` 3.32 · `secondary`/`slate` 3.30 · `teal` 3.07 fallan en claro. |
| F17 | **`Text align` es inerte por defecto**: renderiza un `span` y `text-align` no hace nada sobre caja inline. Hay que pedir `as="p"`. |
| F18 | **La fundación de eidos no trae reset de modelo de caja y lo asume del app.** Bajo `content-box`, `[data-field-control]` (`inline-size:100%` + padding) mide 30px más que su contenedor. Resuelto en app-land: `web/routes/blocks/_lib/reset.css`. |
| F19 | **`onValidSubmit`/`onInvalidSubmit` son no-op silenciosos** si se pasa un `form` ya construido: el componente solo los reenvía al `createForm` que hace él mismo. El handler va SIEMPRE en `createForm`. |
| F20 | Los mensajes de SIUM son **idlangref** (`#?sium.errors.email\|…`): resolver con `uix.langs.t(issue.message, issue.params)`. La demo de docs del `Form` los parte a mano y por eso siempre salen en inglés. |
| F21 | **Los primitivos de layout no pueden cambiar de elemento**: `Text`/`Heading` aceptan `as`, pero `Box` —y `Stack`/`Flex`/`Grid`/`Group`/`Wrap`/`Container`/`Section`— es un `<div>` fijo. Una columna de enlaces no puede ser `ul`/`li`. |
| F22 | **Un `Select` controlado muestra el VALOR crudo hasta abrirse una vez**: las etiquetas las registran los `Select.Item` al montarse y el `Content` portaleado está cerrado. Rodeo: el `child` de `Select.Value`. |
Y dos huecos anteriores que siguen abiertos: **`Box`/`Surface` `flex`/`grow` no
hacen crecer a un hijo flex** (se rodea con tracks `1fr` de `Grid`) y **`Group` no
apila** (usa `Flex direction={{ base: 'column', sm: 'row' }}`; `hero` todavía
compone sus acciones con `Group`).
---
## La plantilla ya existe — cópiala, no la reinventes
docs(blocks): registro de F2.1, doctrina de demo del tier y handoff Documentación al día de lo que se cerró hoy y handoff para retomar mañana. - `PLAN-blocks.md` §7: **F2.1 `site-header` HECHA** con sus siete commits, la fase 0 contra el dossier §P1, el landmark que le faltaba a `NavigationMenu` (arreglado en el canon, no parcheado en el block), el hueco del CTA que navega y parece botón (registrado, no falseado) y el defecto de framework que destapó la demo. - `theming/changelog.md` §46: las 44 variables de cascada de `Box` dejan de heredarse. Un `Section` regalaba su padding a cada descendiente —la galería arrastraba ~300px de aire desde F0— y los hijos heredaban anchos y `display` ajenos. `@property { inherits: false }`, radio verificado sin regresiones. Lección: una variable que un componente escribe para SÍ MISMO debe declararse `inherits: false`; si no, deja de ser un prop y se vuelve un contagio. - `architecture/blocks.md` B-9: la demo de un block se construye sobre el harness compartido y el block se enseña A SANGRE — nunca dentro de un marco con relleno ni de una caja con scroll, porque eso cambia lo que el block hace. - `src/uix/blocks/README.md`: anatomía de la demo (harness, `{Name}Site`, ruta `preview`, `DocRow`, catálogo único, ejes en el shell). - `CONTINUE-blocks.md` (nuevo): handoff — qué toca (F2.2 `hero`), la plantilla de ficheros para copiar, las reglas que ya costaron sangre (a sangre, iframe solo para anchos de dispositivo, cada prop un control, nada de backticks en `<Text>`, ojo con las variables que heredan), la deuda declarada que es decisión del usuario y el estado exacto de los gates. Gates al parar: `blocks:check` verde · `svelte-check` 73 errores, todos deuda ajena (0 propios) · `vitest src/uix/eidos` 353/353 · `contracts.test` con los 3 fallos ajenos conocidos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
```text
src/uix/blocks/{kebab}/
├── README.md # Función · Mapa de composición · Decisiones · Gaps
├── index.ts # export del compound + tipos
├── types.ts # props (todo contenido entra por snippets, B-5/B-7)
└── {kebab}.svelte # composición: solo componentes del canon, sin CSS
web/routes/blocks/{kebab}/
├── +page.svelte # BlockDemo + controles vivos + pestañas de doc
├── {Name}Site.svelte # el block dentro de contenido REAL de producto
└── preview/
├── +layout@.svelte # `@` resetea el layout: la vista previa es su página
└── +page.svelte # sirve {Name}Site leyendo la URL
```
Y luego: marcar `shipped: true` en `web/routes/blocks/_lib/catalog.ts` (raíl y
galería leen esa única fuente) y `npm run blocks:check`.
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
---
docs(blocks): registro de F2.1, doctrina de demo del tier y handoff Documentación al día de lo que se cerró hoy y handoff para retomar mañana. - `PLAN-blocks.md` §7: **F2.1 `site-header` HECHA** con sus siete commits, la fase 0 contra el dossier §P1, el landmark que le faltaba a `NavigationMenu` (arreglado en el canon, no parcheado en el block), el hueco del CTA que navega y parece botón (registrado, no falseado) y el defecto de framework que destapó la demo. - `theming/changelog.md` §46: las 44 variables de cascada de `Box` dejan de heredarse. Un `Section` regalaba su padding a cada descendiente —la galería arrastraba ~300px de aire desde F0— y los hijos heredaban anchos y `display` ajenos. `@property { inherits: false }`, radio verificado sin regresiones. Lección: una variable que un componente escribe para SÍ MISMO debe declararse `inherits: false`; si no, deja de ser un prop y se vuelve un contagio. - `architecture/blocks.md` B-9: la demo de un block se construye sobre el harness compartido y el block se enseña A SANGRE — nunca dentro de un marco con relleno ni de una caja con scroll, porque eso cambia lo que el block hace. - `src/uix/blocks/README.md`: anatomía de la demo (harness, `{Name}Site`, ruta `preview`, `DocRow`, catálogo único, ejes en el shell). - `CONTINUE-blocks.md` (nuevo): handoff — qué toca (F2.2 `hero`), la plantilla de ficheros para copiar, las reglas que ya costaron sangre (a sangre, iframe solo para anchos de dispositivo, cada prop un control, nada de backticks en `<Text>`, ojo con las variables que heredan), la deuda declarada que es decisión del usuario y el estado exacto de los gates. Gates al parar: `blocks:check` verde · `svelte-check` 73 errores, todos deuda ajena (0 propios) · `vitest src/uix/eidos` 353/353 · `contracts.test` con los 3 fallos ajenos conocidos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
## Reglas que ya costaron sangre (no las re-aprendas)
- **El block se enseña A SANGRE en la página.** Nada entre el block y el borde:
ni marco con relleno, ni caja con scroll, ni cromo pegajoso encima. Medido: un
`Card` desplazaba 21px un header con `offset: 0` (su recipe pinta con
`--card-padding-*`, que `padding={0}` de la capa Box no alcanza), y un
`position: sticky` dentro de un div con scroll es un comportamiento que nadie
vive. **Si un block se ancla a algo, se mide contra lo que se anclará en
producción.**
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Verifica esperando la CONDICIÓN, nunca un timeout fijo.** Con `Form`+`Field`+
SIUM el dev server tarda ~2,5s en hidratar y un screenshot temprano fotografía
el panel todavía invisible (`data-animation-pending` puesto). Esperar a que ese
atributo desaparezca es la diferencia entre verificar y reportar un bug que no
existe.
feat(blocks): `banner` — el aviso de arriba, y tres defectos del canon que no existían F2.11. El block más FINO del tier a propósito: cuando el canon ya tiene la pieza, el block es colocación y nada más. Reenvía la superficie entera del `Banner` con `Omit<BannerProps, 'children'>` —sin re-declarar `intent`/`variant`/`size` ni estrecharlos—, lo mete en columna con `Container` (`width="100%"` + `paddingX={0}`: a sangre por fuera, en columna por dentro), envuelve la fila con `Wrap` en vez de aplastarla, y cablea `Banner.Close` solo si llega `onDismiss`. La visibilidad NO es suya: es la decisión que ya tomó el componente («composición, no un booleano `dismissible`»), así que el app envuelve en su `{#if}`. Un block que guardara ese estado sería una segunda fuente de verdad. Tampoco emite sema: el canon declara cero eventos para `Banner` a propósito, y un aviso persistente sin descarte es tan legítimo como uno descartable. La demo lo enseña **encima del `site-header` de verdad**, con página para desplazarse. Un aviso dentro de un recuadro no se parece a un aviso. ## El hallazgo que la fase 0 anticipó `Banner` estampa `role="banner"` DESPUÉS de sus rest props, así que no se puede relajar a una región normal. Con el `site-header` en la misma página —que es la única colocación que shipean las referencias— quedan **dos landmarks `banner`**. Medido en la vista previa: dos. Lo único que puede hacer un app hoy es nombrarlos con `aria-label`, y eso hace la demo. ## Y una lección de método que costó una sesión Reporté tres «defectos del canon» —`aria-label` ausente en `Banner.Close`, `type` desaparecido de todo `Button`, `IconButton` tragándose el `onclick`— y **los tres eran falsos**. La causa era la misma: medir demasiado pronto. Los `data-variant` / `data-size` los escribe el componente de eidos al renderizar, así que están desde el primer frame; `type`, `aria-label` y los handlers los aplica la **runtime del morfo en un efecto posterior**. A ~1s: `type` ausente en 3 de 3 botones y ningún clic disparando. A ~6s: `type="button"`, `aria-label="Descartar"` y el descarte funcionando. La espera válida es un atributo que solo pueda haber puesto la runtime —`waitForFunction(() => boton.hasAttribute('type'))`—, no que el nodo exista ni que se vea. La regla queda afinada en `CONTINUE-blocks.md`, que ya avisaba de esperar la condición y no el reloj: fallé al elegir la condición. De paso, un aviso de soma que sí era real y era mío: `Tabs.List` sin nombre accesible en `BlockDemo.svelte`. Afectaba a las 12 demos del tier. Verificado en navegador: los 4 intents, los 3 tratamientos, `descartable` sí/no (con `no` el botón deja de renderizarse, no se oculta), claro/oscuro/RTL y 420px, la tira siempre por encima de la cabecera, cero desbordamiento horizontal, el descarte con la página recolocándose, y los controles de la demo moviendo la vista previa en línea. Gates: `blocks:check` verde (12 blocks) · `svelte-check` sin errores propios · `docs:check` sin errores míos · prettier limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Y la condición tiene que ser algo que escriba la RUNTIME del morfo, no el
render.** Los `data-variant` / `data-size` los pone el componente de eidos al
renderizar, así que están desde el primer frame; `type`, `aria-label` y los
handlers los aplica la runtime en un efecto POSTERIOR. Esperar a que exista el
nodo (o a que se vea) no basta: a ~1s medí `type` ausente en TODOS los `Button`
del árbol y ningún `onclick` disparando, y a ~6s los mismos botones tenían
`type="button"`, `aria-label="Descartar"` y el clic funcionando. Reporté tres
feat(blocks): contact CERRADO — la coordinacion entra en el contrato B El estado se le pregunta al ESQUEMA, no al Form. `form.isValid` con `validationBehaviour: 'progressive'` significa «aun no se ha encontrado nada mal»: un formulario vacio e intacto no tiene errores, asi que se declaraba valido y `incomplete` era INALCANZABLE al cargar — la seccion pedia resolver la verificacion con los tres campos vacios, justo el hueco que la doctrina existe para cerrar. Ahora la raiz valida los valores con `validateSync` de SIUM: sincrono y sin escribir errores (`form.validate()` habria encendido los tres campos en rojo en el primer frame). `state.test.ts` fija la maquina con 9 casos — primer test unitario del tier, porque `state.ts` es su primera logica pura: el orden de prioridad, que solo `ready` deja enviar, y que todo estado bloqueado tiene frase. Contrato B (architecture/blocks.md): seccion «Coordination» con las tres cosas que posee un block que coordina (estado, forma de sus datos, palabras), B-5 admite el esquema por defecto, B-7 enmendado (posee las palabras de SUS estados como idlangref con fallback ingles) y la convencion de servicios acotada: el traductor es el UNICO servicio sancionado. Dice tambien a quien NO aplica — los blocks de layout no coordinan nada. i18n por la via real: el arnes registra el namespace `blocks` en las DOS cadenas de arranque (galeria y previews, que duplican el boot) y la demo se lee en castellano en vez de caer al fallback ingles. Ademas: README y pestanas de doc rehechos al reparto nuevo, ficha F2.13 y bitacora en PLAN-blocks.md, y el control vivo que faltaba para un prop publico — `verification` con reto / sin reto, porque omitir el prop no es lo mismo que pasar un estado que nunca verifica. Verificado en navegador, arco completo y las dos ramas: sin reto vacio → un campo → tres campos (se desbloquea) → «Enviando…» → «Enviado»; con reto, con los tres campos llenos el boton sigue bloqueado y la razon pasa a «Resuelve la verificacion de arriba». `verifying` y `rejected` quedan cubiertos por test unitario, no por el reto en vivo: el provider de ProofOfHuman escribe `status` el mismo y el veredicto del app no se sostiene (hilo de canon abierto). Gates: blocks:check verde (14 blocks) · vitest 9/9 · docs:check 0 · svelte-check sin errores propios · prettier limpio en los ficheros propios. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
«defectos del canon» que no existían.
- **MATIZ CARO (2026-07-31): que lo escriba la runtime NO basta — tiene que no
existir en el SSR.** Esperé `button[type="submit"]` con atributo `type` como
puerta de hidratación en `contact`, y **ese atributo viene ya en el HTML del
servidor**: la espera se cumplía sobre el documento estático y yo tecleaba
antes de que Svelte tomara los inputs. Resultado: los valores entraban en el
DOM, `form.values` seguía vacío, y pasé varias rondas persiguiendo un fallo del
block que no existía (llegué a «arreglar» un `$derived` que estaba bien; lo
revertí al medirlo). **La puerta honesta**: algo que solo pueda haber escrito
el cliente — aquí `<style id="uix-blocks-display">`, que pone un `$effect` de
`BootUix` — más un ida y vuelta reactivo real antes de dar por hidratado.
- **Si instrumentas con `console.log` y no lo ves en el navegador, míralo en el
SERVIDOR.** Un `console.log` dentro de un `$derived` sale por el stdout del dev
server durante el SSR. Ver el log SOLO ahí es la prueba de que el componente no
está corriendo en cliente — fue lo que delató el diagnóstico anterior.
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Playwright headless SÍ sirve para foco y teclado.** El pane suspendido no
(congela rAF y pierde `activeElement`), pero un `page.keyboard.type()` real
dispara `:placeholder-shown` y `:focus-within`: así se verificó que la etiqueta
flotante del `Field` sube al borde. `page.fill()` usa el setter nativo y NO los
dispara. Un script del scratchpad debe importar
`file:///G:/dev/svelte/vicen/node_modules/playwright/index.mjs` (no resuelve
`playwright` por ruta relativa).
docs(blocks): registro de F2.1, doctrina de demo del tier y handoff Documentación al día de lo que se cerró hoy y handoff para retomar mañana. - `PLAN-blocks.md` §7: **F2.1 `site-header` HECHA** con sus siete commits, la fase 0 contra el dossier §P1, el landmark que le faltaba a `NavigationMenu` (arreglado en el canon, no parcheado en el block), el hueco del CTA que navega y parece botón (registrado, no falseado) y el defecto de framework que destapó la demo. - `theming/changelog.md` §46: las 44 variables de cascada de `Box` dejan de heredarse. Un `Section` regalaba su padding a cada descendiente —la galería arrastraba ~300px de aire desde F0— y los hijos heredaban anchos y `display` ajenos. `@property { inherits: false }`, radio verificado sin regresiones. Lección: una variable que un componente escribe para SÍ MISMO debe declararse `inherits: false`; si no, deja de ser un prop y se vuelve un contagio. - `architecture/blocks.md` B-9: la demo de un block se construye sobre el harness compartido y el block se enseña A SANGRE — nunca dentro de un marco con relleno ni de una caja con scroll, porque eso cambia lo que el block hace. - `src/uix/blocks/README.md`: anatomía de la demo (harness, `{Name}Site`, ruta `preview`, `DocRow`, catálogo único, ejes en el shell). - `CONTINUE-blocks.md` (nuevo): handoff — qué toca (F2.2 `hero`), la plantilla de ficheros para copiar, las reglas que ya costaron sangre (a sangre, iframe solo para anchos de dispositivo, cada prop un control, nada de backticks en `<Text>`, ojo con las variables que heredan), la deuda declarada que es decisión del usuario y el estado exacto de los gates. Gates al parar: `blocks:check` verde · `svelte-check` 73 errores, todos deuda ajena (0 propios) · `vitest src/uix/eidos` 353/353 · `contracts.test` con los 3 fallos ajenos conocidos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
- **Los anchos de dispositivo (375/768) van por la ruta `preview` en iframe**, y
es opt-in: en dev, dos documentos sin empaquetar a la vez agotan las
conexiones del navegador (`ERR_INSUFFICIENT_RESOURCES` mata las DOS páginas).
- **Cada prop público, un control vivo** en la demo; los ejes de sección (tema,
idioma, dirección, densidad) ya los da el shell, no los repitas.
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Un slot que se apaga se pasa como `undefined`, no se renderiza vacío.**
Declara el snippet arriba y pásalo por prop
(`signup={activo ? banda : undefined}`): así el `{#if}` del block quita también
su hueco. Y **cuidado con el sombreado**: `{#snippet signup()}` pisa un prop
llamado `signup` dentro del componente.
docs(blocks): registro de F2.1, doctrina de demo del tier y handoff Documentación al día de lo que se cerró hoy y handoff para retomar mañana. - `PLAN-blocks.md` §7: **F2.1 `site-header` HECHA** con sus siete commits, la fase 0 contra el dossier §P1, el landmark que le faltaba a `NavigationMenu` (arreglado en el canon, no parcheado en el block), el hueco del CTA que navega y parece botón (registrado, no falseado) y el defecto de framework que destapó la demo. - `theming/changelog.md` §46: las 44 variables de cascada de `Box` dejan de heredarse. Un `Section` regalaba su padding a cada descendiente —la galería arrastraba ~300px de aire desde F0— y los hijos heredaban anchos y `display` ajenos. `@property { inherits: false }`, radio verificado sin regresiones. Lección: una variable que un componente escribe para SÍ MISMO debe declararse `inherits: false`; si no, deja de ser un prop y se vuelve un contagio. - `architecture/blocks.md` B-9: la demo de un block se construye sobre el harness compartido y el block se enseña A SANGRE — nunca dentro de un marco con relleno ni de una caja con scroll, porque eso cambia lo que el block hace. - `src/uix/blocks/README.md`: anatomía de la demo (harness, `{Name}Site`, ruta `preview`, `DocRow`, catálogo único, ejes en el shell). - `CONTINUE-blocks.md` (nuevo): handoff — qué toca (F2.2 `hero`), la plantilla de ficheros para copiar, las reglas que ya costaron sangre (a sangre, iframe solo para anchos de dispositivo, cada prop un control, nada de backticks en `<Text>`, ojo con las variables que heredan), la deuda declarada que es decisión del usuario y el estado exacto de los gates. Gates al parar: `blocks:check` verde · `svelte-check` 73 errores, todos deuda ajena (0 propios) · `vitest src/uix/eidos` 353/353 · `contracts.test` con los 3 fallos ajenos conocidos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
- **Nada de backticks de markdown dentro de `<Text>`**: se ven literales. Lo que
es código va en `<Code>`.
- **Ojo con las variables de layout que heredan.** `justify` de `Group` se
hereda a los clusters anidados (pon `justify` explícito) y las de `Box` YA no
heredan desde 2026-07-23 (`docs/theming/changelog.md` §46).
- **Un hueco del canon se registra, no se falsea.** Si al componer falta algo,
va a los Gaps del block como candidato a canon y la demo usa lo que hay.
feat(blocks): content-section cierra F2 — la rejilla de escape, y las escalas tipograficas salen de Text El ultimo block de sitio, y el que mas cerca estuvo de ser un envoltorio: `Section` + `Container` + `Prose` no habria anadido nada, porque `Prose` ya trae su medida de lectura. Lo que falta en el ecosistema es el ESCAPE — dentro de un `Container` nada puede ser mas ancho que el, asi que una figura a sangre hay que sacarla del articulo y ponerla de hermana, y el orden de lectura se rompe. La seccion es una rejilla de 5 pistas (canalon · flanco · MEDIDA · flanco · canalon) y cada parte dice hasta donde llega: `measure` col 3, `wide` col 2/5, `full` col 1/-1. Todas las longitudes son tokens del sistema (`--measure-*`, `--container-width-*`, `--container-padding-inline`). `.Body` y `.Media` son compound porque SE REPITEN; la cabecera son slots de snippet. `.Body` apaga la medida de `Prose`: dos duenos del mismo ancho se pelean y ganaria el mas estrecho en silencio. Los tres ejes son RESPONSIVE (`measure`, `wide`, y el `width` de cada parte), resueltos con `eidos.resolve()` — el mismo camino que usan los primitivos de eidos, asi que los unicos breakpoints en juego son los canonicos. Es lo que un valor unico no puede decir: `{ base: 'full', md: 'wide' }` = foto a sangre en movil y contenida de `md` arriba. CANON: un componente no es libreria de otro. `Heading` importaba CINCO escalas tipograficas de `Text` (`TextTracking`, `TextLeading`, `TextWrap`, `TextNumeric`, `TextMeasure`) y al tipar este block repeti la violacion. Las cinco se mueven a `eidos/lib/types.ts`, que es donde su propio encabezado dice que van y donde ya esta documentado el precedente del mismo fallo (`ColorRole` re-escrito a mano que derivo a 8 miembros contra 9). Sin shim de compatibilidad: `text` y `heading` las importan de la libreria. Cuatro defectos que solo dijo el navegador: 1. `gap` separa tambien las COLUMNAS y una parte que las cruza se lleva esos huecos encima — `wide` media 1088 en vez de los 1024 del contenedor con el que debe alinearse, y a 420px `full` llegaba a 532 dentro de una rejilla de 404 y hacia scrollear la pagina. Van `rowGap` + `columnGap={0}`. 2. Una pista `min(medida, 100%)` ignora sus propios canalones: a 420px la central se quedaba los 404 enteros y la rejilla se iba a 436. 3. Un token de container es un ancho EXTERIOR: con `--container-width-lg` a pelo la figura `wide` sobresalia 16px por cada lado respecto al texto de la seccion hermana de debajo, a 1280/1440/1920. La pista ancha resta ahora `2 * --container-padding-inline` (992 en `lg`) y el desfase es 0. Lo cazo el usuario mirando la pantalla: yo habia medido el block contra si mismo, no contra la pagina. 4. `100%` significa algo distinto dentro de cada parte — en `measure`/`wide` ya es una pista, en `full` es la rejilla entera con canalones —, asi que capar el pie igual en los dos casos lo dejaba a 340 contra una columna de 372 en uno y a 404 en el otro. Verificado en navegador: barrido 375→1920 sin desbordamiento; alineacion pie↔prosa identica en 3 viewports × 3 medidas × 3 anchuras (18/18); figura `wide` a ras del texto de la seccion hermana en 1280/1440/1920; y el valor responsive cambia exactamente en el `md` canonico (a sangre a 767, contenida a 768). Claro, oscuro, 420px y 1920 mirados, y la geometria confirmada tambien en el Chrome del usuario. Semantica propia `figure`/`figcaption` (no interactivos → estructura de documento, B-8) con el hueco senalado: el canon no tiene primitiva `Figure`. Contexto de CONFIGURACION, no de estado — es un block de layout y no coordina nada. Gates: blocks:check verde (15 blocks) · svelte-check sin errores en lo tocado · eidos 28/29 suites (la que falla es `audio-player` sin morfo, del hilo de audio, ajena) · docs:check 0 · prettier limpio. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **`gap` en un `Grid` separa también las COLUMNAS, y una parte que las cruza se
lleva esos huecos encima** (`content-section`, medido): con `gap={8}` y cinco
pistas, la parte que abarca 2/5 medía 1088 en vez de los 1024 del contenedor
con el que debía alinearse, y la de 1/-1 llegaba a 532 dentro de una rejilla de
404 y hacía scrollear la página a 420px. Si las columnas son un instrumento de
medida y no cosas puestas al lado: `rowGap` + `columnGap={0}`.
- **Y `100%` dentro de una pista no es `100%` de la rejilla.** Una pista
`min(medida, 100%)` se come sus propios canalones (a 420px la central se
quedaba los 404 enteros y la rejilla se iba a 436), y algo anidado dentro de una
parte ve el ancho de SU pista, no el de la rejilla — capar igual en los dos
casos descuadra uno de los dos. Los dos se cazaron midiendo, no leyendo.
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Los números de layout se miden.** Tres defaults de `site-footer` (`container`,
la razón de la rejilla, el gap de columnas) salieron mal a la primera y solo el
navegador lo dijo. Si un default decide cuántas cosas caben en una fila, se
comprueba con el contenido real.
---
## Deuda del arnés de demos (mía, sin tocar)
- La galería (`web/routes/blocks/+layout@.svelte`) **arranca UIX en línea** en vez
de usar `_lib/BootUix.svelte`, que es lo que usan los previews: la misma cadena
escrita dos veces, y el motivo de que `reset.css` haya que importarlo en los dos
sitios.
- En `BlockDemo`, a ~1400px, el conmutador de anchos de dispositivo se solapa con
el párrafo que lo precede. Idéntico en los 11 blocks → es del arnés, no de un
block.
---
docs(blocks): la variedad se firma antes de construirla — F2b en cuatro tramos El usuario señaló que el dossier de referencias nos dejaba muy por debajo en variedad. El contraste fila a fila de su §P1 contra los 15 blocks dio 6 filas hechas y 4 resueltas por composición: lo que quedaba pendiente eran DECISIONES de julio, no medidas. Ninguna de las ocho variantes era un hallazgo nuevo — todas estaban ya en el README de su block esperando una firma. Pero ocho variantes no cierran la brecha que se ve, que es de CARDINALIDAD, y el método para esa ya estaba escrito en el dossier (P6.1: demostrar la equivalencia variante-a-variante en vez de competir en número de dumps). La primera versión de la sección no lo trajo y se reescribió entera el mismo día. F2b queda con cuatro tramos: A las variantes de suelo, B la matriz de equivalencia por block —el entregable central, con su plantilla y el guard encendido al final para no dejar 18 READMEs en rojo durante la ola—, C el catálogo que se reabre y D la página compuesta. La regla de forma gana el término que faltaba y que más trabajo hace: una variante alcanzable componiendo es una RECETA demostrada, cero código. Sin él cada fila de las referencias parece pedir un layout nuevo y el tier engorda por imitación. Tres decisiones de catálogo: logo-cloud vuelve (se difirió sobre una premisa que las refs desmienten, y su valor propio es la tinta monocroma derivada de tokens, que nadie más puede dar); blog entra por la misma puerta que team; cookie-consent entra con doctrina propia, porque la ley europea vive en el TIPO — rechazar al mismo nivel que aceptar, no esenciales apagadas por construcción. onboarding NO entra: es un wizard con otro nombre, y duplicar función es la inflación que este modelo existe para evitar. Y el cierre de F2 deja de mentir: cerrada EN UNIDADES. La página compuesta que exigía nunca se construyó, así que el claim de que los blocks ensamblan sin fricción se declara sin demostrar en vez de darse por probado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Deuda a decisión tuya — SALDADA 2026-08-17
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(blocks): la variedad se firma antes de construirla — F2b en cuatro tramos El usuario señaló que el dossier de referencias nos dejaba muy por debajo en variedad. El contraste fila a fila de su §P1 contra los 15 blocks dio 6 filas hechas y 4 resueltas por composición: lo que quedaba pendiente eran DECISIONES de julio, no medidas. Ninguna de las ocho variantes era un hallazgo nuevo — todas estaban ya en el README de su block esperando una firma. Pero ocho variantes no cierran la brecha que se ve, que es de CARDINALIDAD, y el método para esa ya estaba escrito en el dossier (P6.1: demostrar la equivalencia variante-a-variante en vez de competir en número de dumps). La primera versión de la sección no lo trajo y se reescribió entera el mismo día. F2b queda con cuatro tramos: A las variantes de suelo, B la matriz de equivalencia por block —el entregable central, con su plantilla y el guard encendido al final para no dejar 18 READMEs en rojo durante la ola—, C el catálogo que se reabre y D la página compuesta. La regla de forma gana el término que faltaba y que más trabajo hace: una variante alcanzable componiendo es una RECETA demostrada, cero código. Sin él cada fila de las referencias parece pedir un layout nuevo y el tier engorda por imitación. Tres decisiones de catálogo: logo-cloud vuelve (se difirió sobre una premisa que las refs desmienten, y su valor propio es la tinta monocroma derivada de tokens, que nadie más puede dar); blog entra por la misma puerta que team; cookie-consent entra con doctrina propia, porque la ley europea vive en el TIPO — rechazar al mismo nivel que aceptar, no esenciales apagadas por construcción. onboarding NO entra: es un wizard con otro nombre, y duplicar función es la inflación que este modelo existe para evitar. Y el cierre de F2 deja de mentir: cerrada EN UNIDADES. La página compuesta que exigía nunca se construyó, así que el claim de que los blocks ensamblan sin fricción se declara sin demostrar en vez de darse por probado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Las cuatro se firmaron en `PLAN-blocks.md` §F2b (tramo A) y ya no bloquean:
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(blocks): la variedad se firma antes de construirla — F2b en cuatro tramos El usuario señaló que el dossier de referencias nos dejaba muy por debajo en variedad. El contraste fila a fila de su §P1 contra los 15 blocks dio 6 filas hechas y 4 resueltas por composición: lo que quedaba pendiente eran DECISIONES de julio, no medidas. Ninguna de las ocho variantes era un hallazgo nuevo — todas estaban ya en el README de su block esperando una firma. Pero ocho variantes no cierran la brecha que se ve, que es de CARDINALIDAD, y el método para esa ya estaba escrito en el dossier (P6.1: demostrar la equivalencia variante-a-variante en vez de competir en número de dumps). La primera versión de la sección no lo trajo y se reescribió entera el mismo día. F2b queda con cuatro tramos: A las variantes de suelo, B la matriz de equivalencia por block —el entregable central, con su plantilla y el guard encendido al final para no dejar 18 READMEs en rojo durante la ola—, C el catálogo que se reabre y D la página compuesta. La regla de forma gana el término que faltaba y que más trabajo hace: una variante alcanzable componiendo es una RECETA demostrada, cero código. Sin él cada fila de las referencias parece pedir un layout nuevo y el tier engorda por imitación. Tres decisiones de catálogo: logo-cloud vuelve (se difirió sobre una premisa que las refs desmienten, y su valor propio es la tinta monocroma derivada de tokens, que nadie más puede dar); blog entra por la misma puerta que team; cookie-consent entra con doctrina propia, porque la ley europea vive en el TIPO — rechazar al mismo nivel que aceptar, no esenciales apagadas por construcción. onboarding NO entra: es un wizard con otro nombre, y duplicar función es la inflación que este modelo existe para evitar. Y el cierre de F2 deja de mentir: cerrada EN UNIDADES. La página compuesta que exigía nunca se construyó, así que el claim de que los blocks ensamblan sin fricción se declara sin demostrar en vez de darse por probado. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
1. **Tabla de comparación** de features×planes → **`Pricing.Compare`**, PARTE
del block (el toggle de periodo vive en su contexto y B-10 impide que un
hermano lo lea). NO es el hermano `pricing-table` que esta lista sugería.
2. **Cita en spotlight** → `layout="spotlight"` en `testimonials`.
3. **Lista estática 2/3 columnas** → `layout="list"` en `faq`, con unión
discriminada en los tipos (A-94).
4. **`form-in-hero`** → slot `form` del hero.
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Resueltas ya: feature-split/alternante (F2.3b, con `Mockup`) · hero con fondo
cover (layout `background`) · CTA que navega y parece botón (el `child` de
`Button` entrega un snippet `content`; `Button` sigue sin `href` y `Link` sigue
poseyendo la navegación — doctrina en el README de eidos Button §«CTA que
navega»).
docs(blocks): registro de F2.1, doctrina de demo del tier y handoff Documentación al día de lo que se cerró hoy y handoff para retomar mañana. - `PLAN-blocks.md` §7: **F2.1 `site-header` HECHA** con sus siete commits, la fase 0 contra el dossier §P1, el landmark que le faltaba a `NavigationMenu` (arreglado en el canon, no parcheado en el block), el hueco del CTA que navega y parece botón (registrado, no falseado) y el defecto de framework que destapó la demo. - `theming/changelog.md` §46: las 44 variables de cascada de `Box` dejan de heredarse. Un `Section` regalaba su padding a cada descendiente —la galería arrastraba ~300px de aire desde F0— y los hijos heredaban anchos y `display` ajenos. `@property { inherits: false }`, radio verificado sin regresiones. Lección: una variable que un componente escribe para SÍ MISMO debe declararse `inherits: false`; si no, deja de ser un prop y se vuelve un contagio. - `architecture/blocks.md` B-9: la demo de un block se construye sobre el harness compartido y el block se enseña A SANGRE — nunca dentro de un marco con relleno ni de una caja con scroll, porque eso cambia lo que el block hace. - `src/uix/blocks/README.md`: anatomía de la demo (harness, `{Name}Site`, ruta `preview`, `DocRow`, catálogo único, ejes en el shell). - `CONTINUE-blocks.md` (nuevo): handoff — qué toca (F2.2 `hero`), la plantilla de ficheros para copiar, las reglas que ya costaron sangre (a sangre, iframe solo para anchos de dispositivo, cada prop un control, nada de backticks en `<Text>`, ojo con las variables que heredan), la deuda declarada que es decisión del usuario y el estado exacto de los gates. Gates al parar: `blocks:check` verde · `svelte-check` 73 errores, todos deuda ajena (0 propios) · `vitest src/uix/eidos` 353/353 · `contracts.test` con los 3 fallos ajenos conocidos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
docs(process): el handoff de blocks, reescrito para entrar en frío mañana El fichero se había convertido en una pila cronológica: la cabecera seguía contando el estado de hace tres blocks y los gates decían «8 blocks». Ahora es un punto de entrada. - **Estado honesto arriba**: 11 de **15** (el plan fijó 14; `feature-split` entró como hermano con scope-approval, así que el denominador real es 15), qué queda con su §, y dónde vive cada cosa (plan, contrato, dossier, deuda, READMEs). - **F2.11 `banner` con fase 0 en pasos**: leer primero el README del componente `Banner` que YA existe —si el descarte, la persistencia o el `role` son suyos, el block los compone, no los reinventa—, contrastar ≥2 catálogos, decidir la forma, y enseñarlo ENCIMA del header, que es donde vive. - **La regla de forma del tier** en su propia sección, con los ejemplos ya shipeados de cada lado (repiten / coordinan / slots). - **Los 8 hallazgos de canon (F15–F22) en una tabla**, cada uno con su número medido, en vez de repartidos por cinco párrafos. Más los dos huecos viejos que siguen abiertos (`flex` que no crece, `Group` que no apila). - **Tres reglas nuevas de las que costaron sangre**: esperar la CONDICIÓN y no un timeout (con Form+Field+SIUM la hidratación tarda ~2,5s y un screenshot temprano fotografía el panel invisible); Playwright headless SÍ vale para foco y teclado reales, `page.fill()` no; y un slot que se apaga se pasa como `undefined`, con el aviso de que `{#snippet signup()}` sombrea un prop del mismo nombre. - **Gates remedidos, no heredados**: `blocks:check` 11 blocks, `svelte-check` sin errores propios, y los 3 fallos de `contracts.test.ts` verificados uno a uno como ajenos (escrituras DOM en soma, data-attrs hardcodeados, claves camelCase de `aura`) — ninguno apunta a `blocks/`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
---
docs(blocks): registro de F2.1, doctrina de demo del tier y handoff Documentación al día de lo que se cerró hoy y handoff para retomar mañana. - `PLAN-blocks.md` §7: **F2.1 `site-header` HECHA** con sus siete commits, la fase 0 contra el dossier §P1, el landmark que le faltaba a `NavigationMenu` (arreglado en el canon, no parcheado en el block), el hueco del CTA que navega y parece botón (registrado, no falseado) y el defecto de framework que destapó la demo. - `theming/changelog.md` §46: las 44 variables de cascada de `Box` dejan de heredarse. Un `Section` regalaba su padding a cada descendiente —la galería arrastraba ~300px de aire desde F0— y los hijos heredaban anchos y `display` ajenos. `@property { inherits: false }`, radio verificado sin regresiones. Lección: una variable que un componente escribe para SÍ MISMO debe declararse `inherits: false`; si no, deja de ser un prop y se vuelve un contagio. - `architecture/blocks.md` B-9: la demo de un block se construye sobre el harness compartido y el block se enseña A SANGRE — nunca dentro de un marco con relleno ni de una caja con scroll, porque eso cambia lo que el block hace. - `src/uix/blocks/README.md`: anatomía de la demo (harness, `{Name}Site`, ruta `preview`, `DocRow`, catálogo único, ejes en el shell). - `CONTINUE-blocks.md` (nuevo): handoff — qué toca (F2.2 `hero`), la plantilla de ficheros para copiar, las reglas que ya costaron sangre (a sangre, iframe solo para anchos de dispositivo, cada prop un control, nada de backticks en `<Text>`, ojo con las variables que heredan), la deuda declarada que es decisión del usuario y el estado exacto de los gates. Gates al parar: `blocks:check` verde · `svelte-check` 73 errores, todos deuda ajena (0 propios) · `vitest src/uix/eidos` 353/353 · `contracts.test` con los 3 fallos ajenos conocidos. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
docs(process): el handoff dice donde estamos y por donde se entra El documento seguia contando la sesion del 2026-08-10: «fase 7, 7 de 15», «quedan 7 en este orden», el ledger a 51/27/12 y unas puertas «SIN COMMITEAR». Nada de eso era cierto ya, y un handoff rancio es peor que ninguno porque se lee como si fuera el estado. Puesto al dia: - **Fase 7 CERRADA 15/15.** Ninguno de los 15 tiene un defecto de composicion: lo que salio vive una capa mas abajo (canon) o en las FICHAS del ledger. Se conserva escrito COMO se llego ahi, porque me equivoque en el camino — declare «conformes» siete blocks de los que solo habia medido un eje, y se corrigio cuando el pregunto si habia terminado. Un barrido no es la rejilla. - **Ledger a 64 ARREGLADO / 19 CONFIRMADO / 13 REFUTADO** sobre 96 filas. - **§Qué queda reescrita como puerta de entrada**, agrupando las 19 vivas por lo que hace falta para cerrarlas en vez de por severidad: tres bloqueadas por decision suya (A-67 al eje de sema con la puerta ya elegida · A-47, que por doctrina es un VALOR de configuracion y no un cambio de CSS por componente · A-09, cuya disposicion apagaria la deteccion live), una bloqueada por una pieza que no existe (A-95 espera a `app-shell`, F3.1), y quince de trabajo normal — con el aviso de que A-55 no es un defecto visible (1,6% del ancho) y de que A-65/A-75 son el mismo patron. - **Las dos sesiones del 16/17** con sus dos commits (`4caf1100a` el renombrado del eje de tamaño, `d02021aee` los dos arreglos de canon), incluido el residuo del 35,4% de A-68, que es peor que mi estimacion y queda escrito como tal. - **Puertas al parar**, con la advertencia de siempre reforzada: la cifra de `svelte-check` SE MUEVE con otras sesiones vivas en el arbol (72, 74, 75, 76, 77 y 80 en dias distintos), asi que se mide justo antes y justo despues del cambio, nunca contra un numero recordado. Y los 8 rojos vivos se nombran uno a uno como ajenos, con el commit que los introduce. Y tres errores de METODO de estas sesiones, que es lo que un handoff existe para que no se repita: 1. Medir un default en una demo que lo pisa no es medir un default. 2. El panel del navegador oculto suspende el IntersectionObserver, no solo el rAF — una medicion dio «contadores congelados» que era la suspension, no el arreglo. La via fiable es Playwright headless. 3. `Motion` es `once: true`: empujar algo bajo el pliegue DESPUES de cargar no lo hace invisible, su observador ya disparo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Estado de gates al parar (2026-08-17 — TODO COMMITEADO Y PUSHEADO)
- `npm run blocks:check` — **verde, 0 errores sobre 15 blocks / 115 ficheros**.
- `npm run docs:check` — **0 errores, 0 avisos** (629 docs).
- `svelte-check`: **72 errores / 59 avisos**, medido justo antes y justo después
de cada cambio — misma cifra, cero regresión, ninguno en lo tocado. ⚠️ Esa
cifra SE MUEVE: con otras sesiones vivas en el mismo árbol se midió 72, 74,
75, 76, 77 y 80 en días distintos. Mídela justo antes y justo después de tu
cambio, **nunca contra un número recordado**.
- Suite completa: **8 rojos en 3 ficheros, todos AJENOS** —
`contracts.test.ts` (6), `eidos/lint.test.ts` y `soma-attr-audit.test.ts`
nombran `waveform` / `skin-media-player` / `radio-group`, que entran por
`bf12b8a57` y `68a48a440` (sesión del media-player, componentes sin morfo), más
un timeout de `engine-orca` que huele a flaky. Ninguno cita nada del tier.
- `prettier`: los avisos que quedan son de ficheros **CRLF preexistentes**
(`motion.svelte`, `motion.css`, `motion/types.ts`, `motion/README.md`,
`AUDIT-blocks-ledger.md`) — ya fallaban en HEAD y formatearlos produciría un
diff del fichero entero. Se dejan como están, a propósito.
## Estado de gates al parar (2026-08-09, fase 5 — histórico)
- `npm run blocks:check` verde con las tres reglas nuevas, 15 blocks / 114
ficheros · `vitest src/uix/blocks/` 20/20 · `vitest src/uix/eidos
src/uix/blocks` 410/410 · `docs:check` 0/0 (618 docs) · `svelte-check` 74/54.
## ⚠️ El árbol está COMPARTIDO — cuidado al commitear
El commit `866089a40` incluye ficheros que **ya venían modificados** cuando
empezó la sesión: había trabajo sin commitear de otras sesiones sobre `blocks/` y
`eidos/`, y al editar encima no hay forma de separarlo por fichero. Lo que sí se
respetó: `morfo/{calendar,pagination,rating-group,toolbar,tree-view,schema,types}`,
`sema/components/textarea.ts` y `soma/tree-view` quedaron FUERA por ser de otra
sesión.
Antes de tocar sema o morfo, mira si hay otra sesión viva ahí. En este mismo día,
una arregló el emparejamiento de las reglas (`closest()`) y el renombrado que mató
el prefijo `form.` en las claves de sonido, y otra (ésta) cambió a qué parte
apuntan los eventos. Se complementaron por suerte, no por diseño.
docs(blocks): auditoria del tier congelada — 29 confirmados, 50 sin verificar Auditoria de los 15 blocks con 50 agentes: dos dimensiones en paralelo —doctrina (contrato B + regla de coordinacion, por lectura) y percepcion (sema en vivo en navegador, interaccion por interaccion)— y despues un verificador ESCEPTICO por hallazgo, con el encargo de refutarlo y la lista de falsos positivos conocidos del repo. 90 en bruto → 40 verificados → 29 CONFIRMADOS + 11 refutados (28%) Ese 28% es la razon de existir de la fase adversarial: sin ella habrian entrado once acusaciones falsas. ⚠️ 50 hallazgos quedaron SIN VERIFICAR, 18 de ellos marcados ALTA. El tope de 40 lo puso mi script, no el trabajo. No son menos graves: estan sin comprobar. `AUDIT-blocks-2026-08-01.md` es la UNICA copia — el journal del workflow era de sesion y ya no existe. Incluye los refutados con su motivo para que nadie los vuelva a reportar. Lo gordo confirmado: - `contact` importa `$libs/forms`, fuera de la lista de la frontera dura 1. - El nombre accesible del submit de `contact` esta congelado en «Enviar» en los cinco estados: `Form.Submit` impone su `aria-label`, asi que las palabras de estado que el block existe para poseer NO llegan al lector de pantalla. El block cumple su promesa solo a la vista. - `site-header` congela la pagina: con el cajon abierto, cruzar el `breakpoint` esconde cajon/overlay/trigger con `display:none` pero deja el Drawer abierto y el scroll del body bloqueado. Reproducido con swipe tactil real rotando un telefono; la unica salida es Escape, que en tactil no existe. - `hero` en `layout="background"`: CTA secundaria a 1.78:1, bajo AA, y el token que la demo escribe a mano para arreglarlo es inerte. - `height="100%"` sobre `Card` es INERTE (atributo HTML, no prop) en `pricing` y `testimonials`: las tarjetas no igualan alto mientras README y demo afirman lo contrario. - B-8 sin declarar (landmark + jerarquia de encabezados) en seis READMEs. La dimension CRUZADA —los 15 en una pagina compuesta— NO se ejecuto, y es ademas la condicion de cierre de F2 del plan. La auditoria confirmo su propia premisa: la capa perceptiva no se habia ejercido NUNCA porque la galeria arrancaba sin packs de sema desde F0, y ahi esta lo mas feo (todavia sin verificar): el nav del header emitiendo `commit-select`+`affirm` con earcon audible al pasar el RATON por encima, un `Enter` en `newsletter` emitiendo dos `commit-submit` con intents contradictorios, y 4 de 7 elementos del header mudos. El handoff `CONTINUE-blocks.md` arranca ahora por la auditoria, con el orden recomendado (verificar los 50 → arreglar por severidad → pagina compuesta → catalogo → v2) y la deuda declarada del arnes, que triplica la cadena de arranque. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
---
## Sesión 2026-08-01 — lo que cambió
- **`content-section` HECHO** → F2 cerrada 15/15. Rejilla de escape de 5 pistas
(`measure` col 3 · `wide` col 2/5 · `full` col 1/-1), los tres ejes RESPONSIVE
por `eidos.resolve()`, y `.Media` con default **`measure`**: la figura sigue al
texto y salirse se PIDE, como en todas las referencias.
- **CANON tocado por orden del usuario**: un componente no es librería de otro. Las
cinco escalas tipográficas (`TextTracking`, `TextLeading`, `TextWrap`,
`TextNumeric`, `TextMeasure`) salieron de `components/text/types.ts` a
`eidos/lib/types.ts`. `Heading` ya las importaba de `Text` desde antes.
- **La galería EMITE**: arrancaba sin packs de sema desde F0 — el motor estampaba
`data-event-*` y nada era audible. Ahora `events: { sound, haptic, components }`
con la lista DERIVADA del barrel (`Object.values`), no escrita a mano: la lista a
mano del otro arnés se quedó atrás dos veces.
- **Los 15 READMEs declaran su posición** bajo la doctrina de coordinación. El mapa
no es uniforme y está en la sección de arriba.
### Lecciones de verificación que costaron esta sesión
1. **La puerta de hidratación no puede ser un atributo que el SSR ya manda.** Usé
el `type` del submit y la espera se cumplía sobre el documento estático: tecleé
antes de hidratar, los valores entraron en el DOM, `form.values` siguió vacío, y
perseguí un fallo inexistente varias rondas. La puerta honesta es algo que solo
escriba el cliente (`style#uix-blocks-display`).
2. **Medir el block contra SÍ MISMO no basta.** El defecto de los 16px de
`content-section` solo apareció al poner una sección normal debajo y comparar
bordes. Los 15 blocks están verificados cada uno contra sí mismo.
3. **Inspeccionar en una pestaña de fondo miente**: `visibilityState: 'hidden'`
suspende el rAF y deja `data-animation-pending` con `opacity: 0`, que parece un
fallo de visibilidad grave y no lo es.
4. **Screenshot Y MIRAR.** Generé la captura en oscuro y nunca la abrí.

Powered by TurnKey Linux.