docs(corpus): add docs/testing-and-tooling.md — testing, validation, codegen, SSR
Consolidates the cross-cutting verification story that was scattered across
package.json, COMPONENT_GUIDE and SOMA_ARCHITECTURE into one reference:
- The two-project vitest suite (browser client / node server) and how to run one.
- Each validator and the class of bug it catches: morfo:check (DOM vs contract),
morfo:vocabulary (verb drift), component:audit (acceptance), perm:check
(state transitions), smoke (hydration), translations:check, eidos-lint.
- Codegen vs authored: generate:eidos-css, generate:contracts-docs, and the
compileMorfo primitive.
- The SSR posture: dom:false -> disabledDom, ActiveDom owner-document resolution,
ornamental sema, and why smoke (not HTTP 200) is what catches hydration bugs.
All grounded in the real package.json scripts. Wired into docs/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
---
title: Testing, Validation & Codegen
type: reference
audience: human + agent
status: current
---
# Testing, Validation & Codegen
The cross-cutting story of how the framework stays correct: the test suite, the
contract validators, what is generated vs authored, and the SSR posture. The
commands are the `scripts` in `package.json` ; this groups them by what they are
docs(eidos): la doctrina alcanza a la jornada — dos guards nuevos, el patron de capa, y EID-3 deja de estar pendiente
Barrido de lo que la sesion cambio y la documentacion todavia no decia.
`testing-and-tooling.md` — los dos guards nuevos entran en la tabla de «que
atrapa cada script», con su reparto explicito: `layer:check` mira el valor
computado (quien gana la cascada) y declara su hueco (la geometria, porque
`getComputedStyle` da el valor USADO y un `inset: auto` se lee como pixeles);
`shared-layer-contract.test.ts` mira el texto, y existe por lo que el navegador
no puede ver — un `env()` ya sustituido devuelve `"0px"` en escritorio.
`component-guide.md` fila RTL — deja de remitir a «EID-3 exception» y enuncia la
regla: dos rejillas NOMBRADAS, `Position` fisica y `LogicalPosition` logica, y la
pregunta que decide entre ellas («¿tiene que voltearse para un lector de derecha
a izquierda?»). Estrechar con `Extract<>`, nunca redeclarar.
`canon/recipe-contract.md` — la fila de z-index flotante distinguia mal: la banda
`--z-index-overlay-*` es de overlays PORTALED. El cromo fijado al viewport que no
portala es otra cosa y tiene su peldano (`affix`, 150). Y el item 9 del checklist
de recetas decia «si flota → una rung de overlay», que era incompleto.
`eidos/components/README.md` — el patron de CAPA COMPARTIDA, que no estaba
escrito en ningun sitio pese a tener dos ejemplares vivos (`list-surface` y
`affix`). Sus cuatro reglas, tres de ellas aprendidas rompiendose: enganchar en
el attr de capa y no en la identidad (o `morfo-check` suelda al consumidor a un
contrato ajeno), un eje = token publico + ranura, el puente reafirma `position`
si el primitivo compuesto declara uno, y se guarda con dos redes porque ninguna
basta sola.
`audit-active-uix.md` — EID-3 pasa a RESUELTO, conservando el hallazgo original
debajo. Era un P3 de julio cerrado «como excepcion» pero marcado en su propia
tabla resumen como «pendiente de doctrina explicita». Ya no lo esta.
`PLAN-affix.md` §7 — lo que vino DESPUES de cerrar el plan, que es casi todo lo
interesante: las dos migraciones y sus dos lecciones, el peldano de z, el patron
de tokens, la canonizacion de la rejilla y los dos guards. Ninguna estaba
prevista en el plan; todas salieron de auditar lo construido.
docs:check 0/627.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
_for_.
docs(corpus): add docs/testing-and-tooling.md — testing, validation, codegen, SSR
Consolidates the cross-cutting verification story that was scattered across
package.json, COMPONENT_GUIDE and SOMA_ARCHITECTURE into one reference:
- The two-project vitest suite (browser client / node server) and how to run one.
- Each validator and the class of bug it catches: morfo:check (DOM vs contract),
morfo:vocabulary (verb drift), component:audit (acceptance), perm:check
(state transitions), smoke (hydration), translations:check, eidos-lint.
- Codegen vs authored: generate:eidos-css, generate:contracts-docs, and the
compileMorfo primitive.
- The SSR posture: dom:false -> disabledDom, ActiveDom owner-document resolution,
ornamental sema, and why smoke (not HTTP 200) is what catches hydration bugs.
All grounded in the real package.json scripts. Wired into docs/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
## The verification loop (the short version)
```bash
npm run check:gate # types WITH the policy: src/ and scripts/ owe ZERO; web/
# measured against the shrinking ledger scripts/check-debt.ts
docs(uix): tanda 2 del contraste con el corpus — el modelo de los capitulos alcanza a la tuberia unica
La lectura completa del corpus (6 lectores Opus, 6/6 censos, ~4,5M tokens)
destapo lo que la tanda 1 no vio, y esta tanda lo cierra:
- El modelo «Effects sync attrs» — repetido VERBATIM en cuatro capitulos
(morfo, soma-architecture, overview, active-architecture), en sus tablas
de piezas, en los cuatro pasos de trigger y en las dos frases-resumen —
muere: la pieza es la bolsa de render; ADom aplica solo el prewrite.
- morfo.md: partProps re-descrito (bolsa completa), la cadena causal de
commits, y las filas de la tabla de ejecutores (data/aria/role → bolsa).
- coincident: los DOS docstrings que ensenaban «in-flight» (types.ts y
morfo.md) se alinean con la equivalencia FIRMADA de sema.md §slider
(«emit-then-handler, like pre; declared indivisible») — el hallazgo del
informe queda refutado como defecto de runtime y reducido a esto.
- glossary: el kind fantasma `internal` (la clase exacta que docs-check:422
mata y su regex no ve en tablas markdown) → `public|private|virtual` real.
- El gate entra en la doctrina: check:gate/gate en el loop de verificacion
(testing-and-tooling y getting-started), eidos:lint como script npm en su
fila, y la tabla de Commands de morfo.md.
- Mi propia sobreafirmacion de ayer, calificada: el test SSR es un CANARIO
de dos representantes sobre mecanismo compartido, no un censo — el censo
por provider queda encolado (P1). morfo:check en getting-started declara
su alcance real (data-*; role/aria sin validador DOM).
- Supervivientes de C2c: el assert-vacio de cropper (la clase «guard sobre
VACIO pasa») retirado con acta; sticky/README deja de citar syncAttrs.
- gradient-builder/README: fila data-kind del Track + acotacion mesh v1.
- Handoff: DOS fe de erratas — «nunca los vio nadie» era falso (vistos y
reducidos 12→3 en cb554ae2e; lo que faltaba era la puerta) y la ley del
escritor imperativo gana su excepcion abierta (textarea autosize, con su
cierre correcto encolado).
Verificacion: docs:check 0/817 · cropper 19/19 · morfo schema+compile 133/133.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
npm run check # raw svelte-check (src/ expect 0; web/ carries the
# frozen ledger errors, which may only shrink)
npm run test # the vitest suite (one run)
npm run gate # everything the pre-push hook runs (see §The gate)
npm run lint # prettier --check · npm run format to fix (first in `gate` )
docs(corpus): add docs/testing-and-tooling.md — testing, validation, codegen, SSR
Consolidates the cross-cutting verification story that was scattered across
package.json, COMPONENT_GUIDE and SOMA_ARCHITECTURE into one reference:
- The two-project vitest suite (browser client / node server) and how to run one.
- Each validator and the class of bug it catches: morfo:check (DOM vs contract),
morfo:vocabulary (verb drift), component:audit (acceptance), perm:check
(state transitions), smoke (hydration), translations:check, eidos-lint.
- Codegen vs authored: generate:eidos-css, generate:contracts-docs, and the
compileMorfo primitive.
- The SSR posture: dom:false -> disabledDom, ActiveDom owner-document resolution,
ornamental sema, and why smoke (not HTTP 200) is what catches hydration bugs.
All grounded in the real package.json scripts. Wired into docs/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
```
For a component you also run the contract validators (below). A change is not
done until `check` is clean and the relevant validators pass.
## Tests — two projects
`vite.config.ts` defines **two vitest projects** (see CLAUDE.md → "Vitest
Two-Project Structure"):
- **client** — browser tests via Playwright, for `*.svelte.{test,spec}.{js,ts}` .
This is where component providers are exercised with real runes + DOM.
- **server** — Node environment for `*.{test,spec}.{js,ts}` (excludes the svelte
tests). Pure engines, libs, and server logic.
```bash
npm run test:unit # watch mode
npm run test # one run
npx vitest run src/uix/morfo/compile.test.ts # a single file
npx vitest run -t "describe name" # by test name
```
Component providers carry their own `{name}-provider.svelte.test.ts` under the
revert: deshacer la auditoría entera — se hizo sin leer la doctrina
Revert de los 7 commits de la sesión del 2026-07-29/30:
352ca8bbe style(soma): formato Prettier en el test de gradient-picker
17a1f167b test(soma): chat-list
e70397fca test(soma): field-langs y gradient-picker
c9b83d025 docs(morfo): qué hace pública una parte + hallazgos retirados
feb4a8424 test(soma): los primeros providers que no tenían red
f8e35b8fd fix(morfo): el eje intent/color
c39170abb fix(uix): la auditoría del sistema
`4e785d32b` (stats-band, otra sesión) queda intacto — el revert lo salta.
## Por qué se revierte todo y no una parte
La instrucción de partida era «audita el sistema, **para ello previamente lee
toda la documentación**». No se leyó. Se auditó primero y se justificó después,
y eso contaminó el conjunto, no unos commits concretos:
- Tres hallazgos del informe eran FALSOS, todos de la misma forma —
heurísticas de una sola vía dadas por hechas sin abrir el código:
D-3 `AgentTimersPort` (el puerto sí está satisfecho por el adaptador de
`defineActiveAgent`); «5 derivas de scope» (`avatar-group` / `path-trace` /
`rotate-align` sí están implementados, co-locados en el directorio del
padre); «29 morfos con `kind:'public'` irreal» (medía si existe
`<Componente.Parte>` e ignoraba que un primitivo de API plana compone por
props y snippets).
- `c9b83d025` existe SÓLO para retirar esos hallazgos del commit anterior.
- Los 6 tests de provider se montan sobre un `installSomaHarness` que FABRICA
cuatro servicios compartidos (`dom`, `langs`, `timers`, `prefs`), violando la
primera regla de propiedad de `architecture/active-uix.md`: «Only composition
roots create shared services. `morfo`, `soma`, `sema`, `eidos` and components
never create `dom`, `langs`, `prefs`, `format`, `clipboard` or equivalents:
they receive them from `ActiveUix`.» El arranque real son tres líneas
(`createActiveUix` → `setActiveUix` → `Soma.create()`) que estaban escritas.
- Y se le pidieron al usuario decisiones cuya respuesta estaba en el corpus
(`testing-and-tooling.md` dice que los tests de provider son convención, no
guard; la regla 1 zanja el arnés).
Triar qué conservar exigía justo el juicio que falló. Se revierte todo, se lee
el corpus, y vuelve sólo lo que se pueda sostener citando un documento — o lo
que sea defecto MEDIBLE y por tanto no dependa de criterio (el colapso de
uniones de props, que hacía compilar `<Avatar color="nonsense">`; que
`translations:check` crashease en cada ejecución de su historia). Nada se
pierde: los commits siguen en la historia y se recuperan con `cherry-pick`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
client project (a guard fails when an active provider ships without one — the
test tree IS the coverage inventory); the reusable engines they consume live
in `$libs/datagrid` , `$libs/forms` , `$libs/strings` and are tested there, not
inside soma. See
docs(book): F7.2 (7/7) — soma-architecture chapter translated; architecture/ batch COMPLETE
src/uix/soma/SOMA_ARCHITECTURE.md (1058 L, Spanish) translated to English
as docs/architecture/soma-architecture.md, same s1-s17 numbering: layer
architecture, design principles, the closed six-piece model + SomaRuntime,
component model (picker composition), runtime parts, the layers inventory,
the Soma class + date/time domain + statics convention, the reactive
system, internal helpers, data-* contracts, IDs, barrels, boundaries,
directory structure, anti-patterns, current shape, stability rule,
checklist. The frozen per-provider test list (dated 2026-05-15, ~140 L)
became the timeless fact: the NO_MISSING_PROVIDER_TESTS guard + the test
tree ARE the coverage inventory (testing-and-tooling aligned). Stub with
the full sN map at the old path; corpus links swept.
F7.2 is complete: docs/architecture/ now holds the whole E1 stratum in
English (7 chapters, ~5.4k lines), with thin stubs + sN maps next to the
code. docs:check 0 errors (251 docs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
[`soma-architecture.md` ](./architecture/soma-architecture.md ) §6.
docs(corpus): add docs/testing-and-tooling.md — testing, validation, codegen, SSR
Consolidates the cross-cutting verification story that was scattered across
package.json, COMPONENT_GUIDE and SOMA_ARCHITECTURE into one reference:
- The two-project vitest suite (browser client / node server) and how to run one.
- Each validator and the class of bug it catches: morfo:check (DOM vs contract),
morfo:vocabulary (verb drift), component:audit (acceptance), perm:check
(state transitions), smoke (hydration), translations:check, eidos-lint.
- Codegen vs authored: generate:eidos-css, generate:contracts-docs, and the
compileMorfo primitive.
- The SSR posture: dom:false -> disabledDom, ActiveDom owner-document resolution,
ornamental sema, and why smoke (not HTTP 200) is what catches hydration bugs.
All grounded in the real package.json scripts. Wired into docs/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
## Validation — what each script catches
These catch classes of bug that `check` (types) and an HTTP 200 (SSR) miss.
docs(eidos): la doctrina alcanza a la jornada — dos guards nuevos, el patron de capa, y EID-3 deja de estar pendiente
Barrido de lo que la sesion cambio y la documentacion todavia no decia.
`testing-and-tooling.md` — los dos guards nuevos entran en la tabla de «que
atrapa cada script», con su reparto explicito: `layer:check` mira el valor
computado (quien gana la cascada) y declara su hueco (la geometria, porque
`getComputedStyle` da el valor USADO y un `inset: auto` se lee como pixeles);
`shared-layer-contract.test.ts` mira el texto, y existe por lo que el navegador
no puede ver — un `env()` ya sustituido devuelve `"0px"` en escritorio.
`component-guide.md` fila RTL — deja de remitir a «EID-3 exception» y enuncia la
regla: dos rejillas NOMBRADAS, `Position` fisica y `LogicalPosition` logica, y la
pregunta que decide entre ellas («¿tiene que voltearse para un lector de derecha
a izquierda?»). Estrechar con `Extract<>`, nunca redeclarar.
`canon/recipe-contract.md` — la fila de z-index flotante distinguia mal: la banda
`--z-index-overlay-*` es de overlays PORTALED. El cromo fijado al viewport que no
portala es otra cosa y tiene su peldano (`affix`, 150). Y el item 9 del checklist
de recetas decia «si flota → una rung de overlay», que era incompleto.
`eidos/components/README.md` — el patron de CAPA COMPARTIDA, que no estaba
escrito en ningun sitio pese a tener dos ejemplares vivos (`list-surface` y
`affix`). Sus cuatro reglas, tres de ellas aprendidas rompiendose: enganchar en
el attr de capa y no en la identidad (o `morfo-check` suelda al consumidor a un
contrato ajeno), un eje = token publico + ranura, el puente reafirma `position`
si el primitivo compuesto declara uno, y se guarda con dos redes porque ninguna
basta sola.
`audit-active-uix.md` — EID-3 pasa a RESUELTO, conservando el hallazgo original
debajo. Era un P3 de julio cerrado «como excepcion» pero marcado en su propia
tabla resumen como «pendiente de doctrina explicita». Ya no lo esta.
`PLAN-affix.md` §7 — lo que vino DESPUES de cerrar el plan, que es casi todo lo
interesante: las dos migraciones y sus dos lecciones, el peldano de z, el patron
de tokens, la canonizacion de la rejilla y los dos guards. Ninguna estaba
prevista en el plan; todas salieron de auditar lo construido.
docs:check 0/627.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| Command | Catches |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `npm run morfo:check` | the **real DOM vs the morfo contract** — navigates each demo and validates emitted `data-*` against the declaration. |
| `npm run morfo:vocabulary` | **canonical-verb / vocabulary drift** in morfo events (e.g. `open\|closed` , declared verbs not in `SEMA_VERBS` ). Hard-fails CI on declared-verb drift. |
| `npm run component:audit` | the **acceptance matrix** of [`completion-checklist.md` ](./guides/completion-checklist.md ) — per-rule severity/applicability across all four layers + recipe + demo. |
| `npm run perm:check` | **state-transition** bugs — cycles a component through its declared states (via `data-perm-step` annotations) and re-validates morfo after each. Catches reactivity loops and transition-time drift `morfo:check` can't. |
| `npm run smoke` | **runtime / hydration** errors — walks every `+page.svelte` with Playwright and surfaces `pageerror` , `console.error` , missing translation keys, `Context "X" not found` , and `__uix_lang_missing__` markers. Needs `npm run dev` running. HTTP 200 is SSR only; smoke exercises client hydration. |
fix(morfo): affix deja de declarar lo que solo lee una capa, y el gancho pasa a nombre de CAPA
Correccion doctrinal, senalada por el autor: **morfo es la capa declarativa ENTRE
capas**. Un atributo que consume una sola no es contrato.
`affixMorfo` declaraba `data-affix-placement` y `data-affix-stretch`. Los lee
UNA: el CSS. No debian estar ahi — y la doctrina nombra la familia exacta
(`morfo.md` §`undeclaredState`: «the escape hatch for attrs OUTSIDE the contract
— a visual wrapper's `data-size`, a presentation flag like `data-sheet`»). Los
declare porque `morfo-check` los exigia, que es la herramienta dictando la
doctrina: el guard clasifica por PREFIJO DE NOMBRE, la doctrina clasifica por
NATURALEZA, y las dos solo chocaban porque el gancho llevaba el nombre del
componente.
Y no era su nombre. Lo estampan tres —`Affix`, `Fab`, `MenuDial`—, asi que no es
de ninguno: pasa a **`data-viewport-placement`** / `data-viewport-stretch`. La
colision con el guard desaparece por construccion, sin excepcion que escribir.
Es el mismo error que `--fab-offset` leido por la capa: nombrar por un
participante algo que es de todos.
`affixMorfo` se queda con lo que si es contrato: la identidad `data-affix`, que
es como el DOM dice «esta caja es un Affix» a quien pregunte.
TAMBIEN INTENTADO Y REVERTIDO, con su motivo, para que nadie lo reintente:
mover el fichero a `eidos/lib/viewport-placement.css` junto a `list-surface.css`.
`recipe-css-contract` lo tumbo y tenia razon — **el sistema de tokens esta
indexado por componente**: toda clave de `recipes/base.ts` exige su
`components/{c}/{c}.css`. `list-surface` puede vivir en `lib/` porque NO tiene
clave de receta (sus `--list-*` viven dentro de su propio CSS, por `data-size`,
no como defaults temeables en `:root`); los nuestros si lo son. La parte portante
—«esto no es de nadie»— la lleva el nombre del gancho, no la carpeta. Queda
escrito en la excepcion E-2.2 del README y en el PLAN.
Sin cambio de comportamiento: 68 sustituciones de nombre, mismas reglas, mismos
valores. Verificado en las tres rutas.
check 69 = base intacta · component:audit affix 0/0 · fab 0/2 · menu-dial 0/0 ·
morfo:check affix PASS · layer:check 0/3 · contrato de capa 13/13 ·
recipe-css-contract + api-contract 50/50 · rtl 0/178 · smoke 311/311.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `npm run layer:check` | a **shared visual layer losing a cascade fight** — for every element carrying a layer hook (`data-viewport-placement`), asserts the computed `position` , that the stacking token resolved, and that no override slot declared inline computes to nothing (the signature of a custom-property CYCLE). Needs `npm run dev` . Its consumer list is DERIVED from who imports the layer, so a component joins the day it migrates. **Deliberate hole, stated in the script** : geometry. `getComputedStyle` reports the USED value, so an `inset: auto` reads back as pixels (measured: `-1976.7px` ) — there is no property-level way to tell a dead `calc()` from an intended value. |
docs(eidos): la doctrina alcanza a la jornada — dos guards nuevos, el patron de capa, y EID-3 deja de estar pendiente
Barrido de lo que la sesion cambio y la documentacion todavia no decia.
`testing-and-tooling.md` — los dos guards nuevos entran en la tabla de «que
atrapa cada script», con su reparto explicito: `layer:check` mira el valor
computado (quien gana la cascada) y declara su hueco (la geometria, porque
`getComputedStyle` da el valor USADO y un `inset: auto` se lee como pixeles);
`shared-layer-contract.test.ts` mira el texto, y existe por lo que el navegador
no puede ver — un `env()` ya sustituido devuelve `"0px"` en escritorio.
`component-guide.md` fila RTL — deja de remitir a «EID-3 exception» y enuncia la
regla: dos rejillas NOMBRADAS, `Position` fisica y `LogicalPosition` logica, y la
pregunta que decide entre ellas («¿tiene que voltearse para un lector de derecha
a izquierda?»). Estrechar con `Extract<>`, nunca redeclarar.
`canon/recipe-contract.md` — la fila de z-index flotante distinguia mal: la banda
`--z-index-overlay-*` es de overlays PORTALED. El cromo fijado al viewport que no
portala es otra cosa y tiene su peldano (`affix`, 150). Y el item 9 del checklist
de recetas decia «si flota → una rung de overlay», que era incompleto.
`eidos/components/README.md` — el patron de CAPA COMPARTIDA, que no estaba
escrito en ningun sitio pese a tener dos ejemplares vivos (`list-surface` y
`affix`). Sus cuatro reglas, tres de ellas aprendidas rompiendose: enganchar en
el attr de capa y no en la identidad (o `morfo-check` suelda al consumidor a un
contrato ajeno), un eje = token publico + ranura, el puente reafirma `position`
si el primitivo compuesto declara uno, y se guarda con dos redes porque ninguna
basta sola.
`audit-active-uix.md` — EID-3 pasa a RESUELTO, conservando el hallazgo original
debajo. Era un P3 de julio cerrado «como excepcion» pero marcado en su propia
tabla resumen como «pendiente de doctrina explicita». Ya no lo esta.
`PLAN-affix.md` §7 — lo que vino DESPUES de cerrar el plan, que es casi todo lo
interesante: las dos migraciones y sus dos lecciones, el peldano de z, el patron
de tokens, la canonizacion de la rejilla y los dos guards. Ninguna estaba
prevista en el plan; todas salieron de auditar lo construido.
docs:check 0/627.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `npm run translations:check` | missing / malformed translation keys. |
| `npm run docs:check` | **doc-corpus drift** — copied vocabulary counts vs the source consts, phantom fields (the legacy morfo text field; rejected API shapes), dependency claims vs `package.json` , the variant-vocab mirror in `component-audit.ts` , checklist↔audit rule-ID sync, and relative links (warn severity). Guards the "link the canon, never copy it" law of [`docs/authoring.md` ](./authoring.md ). |
docs(uix): tanda 2 del contraste con el corpus — el modelo de los capitulos alcanza a la tuberia unica
La lectura completa del corpus (6 lectores Opus, 6/6 censos, ~4,5M tokens)
destapo lo que la tanda 1 no vio, y esta tanda lo cierra:
- El modelo «Effects sync attrs» — repetido VERBATIM en cuatro capitulos
(morfo, soma-architecture, overview, active-architecture), en sus tablas
de piezas, en los cuatro pasos de trigger y en las dos frases-resumen —
muere: la pieza es la bolsa de render; ADom aplica solo el prewrite.
- morfo.md: partProps re-descrito (bolsa completa), la cadena causal de
commits, y las filas de la tabla de ejecutores (data/aria/role → bolsa).
- coincident: los DOS docstrings que ensenaban «in-flight» (types.ts y
morfo.md) se alinean con la equivalencia FIRMADA de sema.md §slider
(«emit-then-handler, like pre; declared indivisible») — el hallazgo del
informe queda refutado como defecto de runtime y reducido a esto.
- glossary: el kind fantasma `internal` (la clase exacta que docs-check:422
mata y su regex no ve en tablas markdown) → `public|private|virtual` real.
- El gate entra en la doctrina: check:gate/gate en el loop de verificacion
(testing-and-tooling y getting-started), eidos:lint como script npm en su
fila, y la tabla de Commands de morfo.md.
- Mi propia sobreafirmacion de ayer, calificada: el test SSR es un CANARIO
de dos representantes sobre mecanismo compartido, no un censo — el censo
por provider queda encolado (P1). morfo:check en getting-started declara
su alcance real (data-*; role/aria sin validador DOM).
- Supervivientes de C2c: el assert-vacio de cropper (la clase «guard sobre
VACIO pasa») retirado con acta; sticky/README deja de citar syncAttrs.
- gradient-builder/README: fila data-kind del Track + acotacion mesh v1.
- Handoff: DOS fe de erratas — «nunca los vio nadie» era falso (vistos y
reducidos 12→3 en cb554ae2e; lo que faltaba era la puerta) y la ley del
escritor imperativo gana su excepcion abierta (textarea autosize, con su
cierre correcto encolado).
Verificacion: docs:check 0/817 · cropper 19/19 · morfo schema+compile 133/133.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
| `npm run eidos:lint` | classifies every `[data-*]` selector in eidos CSS as **morfo-backed / eidos-only / invalid** — drift between the morfo contract and the CSS. A `gate` member since P0 fase B (audit 2026-08-26); the architectural defense is still the typed `semaSelector` builder — see the "Eidos drift defense" rule in CLAUDE.md. |
docs(eidos): la doctrina alcanza a la jornada — dos guards nuevos, el patron de capa, y EID-3 deja de estar pendiente
Barrido de lo que la sesion cambio y la documentacion todavia no decia.
`testing-and-tooling.md` — los dos guards nuevos entran en la tabla de «que
atrapa cada script», con su reparto explicito: `layer:check` mira el valor
computado (quien gana la cascada) y declara su hueco (la geometria, porque
`getComputedStyle` da el valor USADO y un `inset: auto` se lee como pixeles);
`shared-layer-contract.test.ts` mira el texto, y existe por lo que el navegador
no puede ver — un `env()` ya sustituido devuelve `"0px"` en escritorio.
`component-guide.md` fila RTL — deja de remitir a «EID-3 exception» y enuncia la
regla: dos rejillas NOMBRADAS, `Position` fisica y `LogicalPosition` logica, y la
pregunta que decide entre ellas («¿tiene que voltearse para un lector de derecha
a izquierda?»). Estrechar con `Extract<>`, nunca redeclarar.
`canon/recipe-contract.md` — la fila de z-index flotante distinguia mal: la banda
`--z-index-overlay-*` es de overlays PORTALED. El cromo fijado al viewport que no
portala es otra cosa y tiene su peldano (`affix`, 150). Y el item 9 del checklist
de recetas decia «si flota → una rung de overlay», que era incompleto.
`eidos/components/README.md` — el patron de CAPA COMPARTIDA, que no estaba
escrito en ningun sitio pese a tener dos ejemplares vivos (`list-surface` y
`affix`). Sus cuatro reglas, tres de ellas aprendidas rompiendose: enganchar en
el attr de capa y no en la identidad (o `morfo-check` suelda al consumidor a un
contrato ajeno), un eje = token publico + ranura, el puente reafirma `position`
si el primitivo compuesto declara uno, y se guarda con dos redes porque ninguna
basta sola.
`audit-active-uix.md` — EID-3 pasa a RESUELTO, conservando el hallazgo original
debajo. Era un P3 de julio cerrado «como excepcion» pero marcado en su propia
tabla resumen como «pendiente de doctrina explicita». Ya no lo esta.
`PLAN-affix.md` §7 — lo que vino DESPUES de cerrar el plan, que es casi todo lo
interesante: las dos migraciones y sus dos lecciones, el peldano de z, el patron
de tokens, la canonizacion de la rejilla y los dos guards. Ninguna estaba
prevista en el plan; todas salieron de auditar lo construido.
docs:check 0/627.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| `src/uix/eidos/shared-layer-contract.test.ts` (vitest) | the **text half** a browser cannot cover for a shared layer: every zone has a rule, `stretch` stays on the axes it was scoped to, no axis is read without its override slot, no geometry rule keys on the component identity, and each consumer imports the layer / stamps the hook / mints no parallel token / re-asserts `position` when the primitive it composes declares one. It exists for ONE thing the computed check is blind to: `getComputedStyle` of a safe-area slot returns `"0px"` on desktop, so a `:dir(rtl)` remap with one half flipped reads identical to a correct one on every CI machine and only surfaces on a notched phone, sideways, in RTL. |
fix(eidos): THEME-SYS-1 — consolidate overlay z-index into a named scale (+ guard + docs)
The ~12 overlay recipes hardcoded an ad-hoc parallel z-index scale (raw integers
60–99/1200) that duplicated nothing reusable and had drifted out of order
(tooltip 76 < dropdown 80 — a tooltip painted BEHIND a dropdown). They are now a
named scale.
- `STATIC_Z_INDEX_OVERLAY` (static.ts) → emitted as `--z-index-overlay-{inline,
backdrop,content,floating,tooltip,detached,toast}`. A SEPARATE scale from the
global `--z-index-*` ladder (which orders the depth planes) — overlays portal
to <body> as siblings of modals, so they share one flat low band where each
rung sits just above the modal scrim. Mapping them to the 300–900 ladder would
hide a dropdown/select/popover opened INSIDE a dialog (dropdown 300 < modal
700); the combobox recipe already warned about this. `tooltip` now sits above
`floating` (fixes the inversion); `toast` stays above the soma FloatPanel band.
- Every overlay recipe token (`content-z`/`overlay-z`/`inline-z`/`toaster-z`/
`preview-z`) now references `var(--z-index-overlay-*)` — zero raw integers.
dialog/drawer gain an explicit `content-z` rung (drops the `calc(... + 1)`).
- Guard (contracts.test.ts, "overlay z-index against raw integers"): a recipe
`*-z` token must reference the scale, never a bare integer. Proven to catch
drift (a raw `'76'` makes it fail). Local `z-index: 0..5` (avatar/tabs/sticky)
is intra-component relative stacking — out of scope, stays.
- Docs: THEMING.md §35 rewritten to describe the consolidated scale + the
flat-band rationale + the guard; token table gains `--z-index-overlay-*`;
testing-and-tooling.md documents the catalogue guards (VG-8/SYS-1/A31/A30/
THEME-SYS-1).
Stacking order verified from the resolved CSS (deterministic z compare: content
70 < floating 80 < tooltip 90 < toast 1200; dropdown-in-dialog preserved). A
live browser check was blocked by a port conflict with another session's server.
check: 0 new type errors; the 5 guards green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
| `src/uix/contracts.test.ts` (vitest, via `npm run test` ) | **catalogue invariants** that keep declarations / recipes coherent as the framework grows. Each fails on drift naming the offender, and excludes the active-dev-track set so it stays green for the maintained catalogue: **VG-8** every morfo is `as const satisfies Morfo` , never `: Morfo` (a `: Morfo` annotation widens the literal so the schema can't check it); **SYS-1 scope-drift** a component shipping an `eidos/components/{c}/` recipe declares `'eidos'` in `scope` ; **A31** no per-item membership predicate (`isSelected` / `isItemPressed` / …) doing `.current.includes` (O(N²) — lift a `Set` , use `.has()` ); **A30** `inputId` registered with the parent Field in the constructor, not wrapped in a `$effect` ; **THEME-SYS-1** overlay z-index references the named `--z-index-overlay-*` scale, never a raw integer. |
docs(corpus): add docs/testing-and-tooling.md — testing, validation, codegen, SSR
Consolidates the cross-cutting verification story that was scattered across
package.json, COMPONENT_GUIDE and SOMA_ARCHITECTURE into one reference:
- The two-project vitest suite (browser client / node server) and how to run one.
- Each validator and the class of bug it catches: morfo:check (DOM vs contract),
morfo:vocabulary (verb drift), component:audit (acceptance), perm:check
(state transitions), smoke (hydration), translations:check, eidos-lint.
- Codegen vs authored: generate:eidos-css, generate:contracts-docs, and the
compileMorfo primitive.
- The SSR posture: dom:false -> disabledDom, ActiveDom owner-document resolution,
ornamental sema, and why smoke (not HTTP 200) is what catches hydration bugs.
All grounded in the real package.json scripts. Wired into docs/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
## Codegen — what is generated vs authored
Some surfaces are produced from a source of truth, not hand-maintained. Don't
edit the output; edit the source and regenerate.
docs: el repositorio, el formato y los guards de texto entran en el corpus; cuatro afirmaciones caducas mueren (documentación del cierre)
El plan de cierre cambió cosas de un nivel que el corpus no cubría: la forma del
repositorio, la política de formato, el inventario de lo generado y la clase de
guard que lee TEXTO fuente. Un inventario previo de todo `docs/**` (más los
README de raíz, `src/**` y `apps/**`) midió qué había: los temas de capa estaban
cubiertos, y este nivel no.
NUEVO
- `docs/repository.md` (E0): las zonas y quién escribe en cada una; la LEY de
`web/routes/` congelado y sus dos consecuencias (los validadores de navegador
siguen manuales; el formato no llega ahí); un solo install y un solo workspace
(el argumento de la copia única de Svelte); un solo mapa de importación con el
orden como contrato; qué debe cero y qué debe un ledger que solo mengua.
Enlazada desde el mapa, el README de la raíz, getting-started y AGENTS.md.
- `docs/testing-and-tooling.md` §Format policy: `.prettierignore` enumerado y
justificado (cinco clases), el commit único de formato, el
`git config blame.ignoreRevsFile` que hay que ejecutar a mano y que Gitea no
lo lee.
- `docs/testing-and-tooling.md` §Guards that read source text: la doctrina que
faltaba. Un guard de texto está acoplado al formateador; el positivo se pone
ROJO y te enteras, el NEGATIVO pasa en VERDE sin inspeccionar nada. Los cinco
síntomas medidos en el formateo de una sola vez, seis reglas para escribir uno
que no dependa del formato, y los cuatro pasos antes de commitear un formateo
masivo (neutralidad compilada, la vista de los guards, los validadores que NO
están en el gate, un commit puro).
CORREGIDO (afirmaciones vivas y falsas)
- `README.md` de la raíz: era una plantilla vacía que mandaba `npm install
vicen` con el repositorio `private: true` y sin paquete. Ahora es una puerta.
- `AGENTS.md`: su pre-flight INVIOLABLE mandaba leer dos guías del árbol
congelado (el canónico está migrado), su ejemplo de test apuntaba a
`src/lib/ling/`, borrado en el refactor, y describía cuatro librerías que no
existen. Además decía que los comentarios en castellano valen, contra
CLAUDE.md.
- `docs/theming/guide.md`: los cuatro sitios que llamaban `eidos.listThemes()`
DENTRO de `hooks.server.ts`, donde no hay instancia; ahora `THEME_IDS`
derivado con `listEidosThemes(config)` del módulo que la raíz también importa.
- `docs/architecture/active-uix.md`: la regla 6 decía que la raíz no proyecta
preferencias; hoy standalone proyecta por defecto (`projectPrefs`, `@default
true`) y attach es opt-in. Su ejemplo de arranque montaba una SEGUNDA
proyección a mano.
- `announce`: el opt-in queda calificado (motor desnudo) frente al cableado por
defecto de las raíces, en `book-deviations.md`, `channels.md:58` y el docblock
del canal.
- `docs/getting-started.md` y `docs/architecture/morfo.md`: la política de
`check:gate` también cubre `scripts/`.
- `docs/canon/direction-contract.md`: los dueños literales de la marca (`boot`,
`projection-<n>`) pasan a la prosa, citables por un guard.
- `src/uix/eidos/components/README.md`: regla 8 — un bindable se reenvía con
`bind:`, nunca por el spread del resto (el proxy de rest props no lleva
`set`, así que el tipo promete lo que no ata). Con el `ref` en la superficie
del `Button` y el gap RESUELTO en `cookie-consent`.
`docs/canon/vocabularies.md` y `src/libs/emoji/data.ts` aparecen por fin como
artefactos generados, con su comando.
Ledger: L-133 · L-142 · L-143 · L-154 a ARREGLADO; L-152 conserva los 532
ficheros pero ya con doctrina escrita; nuevas L-161…L-165 (la última, DIFERIDA:
nadie obliga aún a que un guard de texto falle con el corpus vacío).
Verificación: `npm run gate` exit 0 en 542 s — lint limpio · check:gate OK
(89 de web/ en el ledger) · docs:check 0/0 en 822 docs · suite 466/466 ficheros,
5445/5445 tests · apps:check verde. `component:audit` exit 0 con PASS 161 /
NEEDS-WORK 5, las cifras de antes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3 weeks ago
| Command | Output | From |
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------ |
| `npm run generate:eidos-css` (+ `npm run eidos:purge` ) | `src/uix/eidos/generated/base.css` (and the purged variant) | `EidosConfig.recipes` |
| `npm run generate:boot` | `src/uix/active-uix/generated/boot.js` — the framework's pre-hydration boot + its CSP hash | `src/uix/active-uix/boot/*` , compiled with esbuild |
| `npm run boot -w apps/<name>` | `apps/<name>/src/generated/boot.js` — that site's own boot, its own hash | the app's `prefs-schema.ts` (`--schema` / `--out` ) |
| `npm run docs:vocabularies` | [`canon/vocabularies.md` ](./canon/vocabularies.md ) — the closed sets | the code consts; `docs:check` (I7) compares it byte for byte |
| `npm run generate:emoji-data` | `src/libs/emoji/data.ts` | `static/emoji/*.json` (emojibase), pruned |
| `node --import tsx/esm scripts/theming-census.ts --report` | `docs/audit/theming/` | the theming census |
Two invariants for all of them:
- **The generator owns the file.** Edit the source and regenerate; a hand edit
is lost on the next run, and `docs:check` fails outright for the generated
vocabularies.
- **They are all in `.prettierignore` .** A formatter that reformats generated
output turns every regeneration into a diff — and, for a byte-compared
artifact, into a red gate. (Measured: the repo-wide format pass reformatted
`canon/vocabularies.md` and broke `docs:check` until both were excluded.)
An app's copy of the framework's fonts and sounds
(`apps/*/static/{fonts,sounds}`) is generated the same way: `assets:sync`
refreshes it before `dev` and `build` , git ignores it, and `--check` fails when
it drifted.
The `data-*` contract is **not** a generated doc — it is the morfo itself, validated
live by `npm run morfo:check` . (A legacy `generate:contracts-docs` script and its
revert: deshacer la auditoría entera — se hizo sin leer la doctrina
Revert de los 7 commits de la sesión del 2026-07-29/30:
352ca8bbe style(soma): formato Prettier en el test de gradient-picker
17a1f167b test(soma): chat-list
e70397fca test(soma): field-langs y gradient-picker
c9b83d025 docs(morfo): qué hace pública una parte + hallazgos retirados
feb4a8424 test(soma): los primeros providers que no tenían red
f8e35b8fd fix(morfo): el eje intent/color
c39170abb fix(uix): la auditoría del sistema
`4e785d32b` (stats-band, otra sesión) queda intacto — el revert lo salta.
## Por qué se revierte todo y no una parte
La instrucción de partida era «audita el sistema, **para ello previamente lee
toda la documentación**». No se leyó. Se auditó primero y se justificó después,
y eso contaminó el conjunto, no unos commits concretos:
- Tres hallazgos del informe eran FALSOS, todos de la misma forma —
heurísticas de una sola vía dadas por hechas sin abrir el código:
D-3 `AgentTimersPort` (el puerto sí está satisfecho por el adaptador de
`defineActiveAgent`); «5 derivas de scope» (`avatar-group` / `path-trace` /
`rotate-align` sí están implementados, co-locados en el directorio del
padre); «29 morfos con `kind:'public'` irreal» (medía si existe
`<Componente.Parte>` e ignoraba que un primitivo de API plana compone por
props y snippets).
- `c9b83d025` existe SÓLO para retirar esos hallazgos del commit anterior.
- Los 6 tests de provider se montan sobre un `installSomaHarness` que FABRICA
cuatro servicios compartidos (`dom`, `langs`, `timers`, `prefs`), violando la
primera regla de propiedad de `architecture/active-uix.md`: «Only composition
roots create shared services. `morfo`, `soma`, `sema`, `eidos` and components
never create `dom`, `langs`, `prefs`, `format`, `clipboard` or equivalents:
they receive them from `ActiveUix`.» El arranque real son tres líneas
(`createActiveUix` → `setActiveUix` → `Soma.create()`) que estaban escritas.
- Y se le pidieron al usuario decisiones cuya respuesta estaba en el corpus
(`testing-and-tooling.md` dice que los tests de provider son convención, no
guard; la regla 1 zanja el arnés).
Triar qué conservar exigía justo el juicio que falló. Se revierte todo, se lee
el corpus, y vuelve sólo lo que se pueda sostener citando un documento — o lo
que sea defecto MEDIBLE y por tanto no dependa de criterio (el colapso de
uniones de props, que hacía compilar `<Avatar color="nonsense">`; que
`translations:check` crashease en cada ejecución de su historia). Nada se
pierde: los commits siguen en la historia y se recuperan con `cherry-pick`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
output `DATA_ATTRS.md` , both fossils of the removed `terra` layer, were deleted.)
docs(corpus): add docs/testing-and-tooling.md — testing, validation, codegen, SSR
Consolidates the cross-cutting verification story that was scattered across
package.json, COMPONENT_GUIDE and SOMA_ARCHITECTURE into one reference:
- The two-project vitest suite (browser client / node server) and how to run one.
- Each validator and the class of bug it catches: morfo:check (DOM vs contract),
morfo:vocabulary (verb drift), component:audit (acceptance), perm:check
(state transitions), smoke (hydration), translations:check, eidos-lint.
- Codegen vs authored: generate:eidos-css, generate:contracts-docs, and the
compileMorfo primitive.
- The SSR posture: dom:false -> disabledDom, ActiveDom owner-document resolution,
ornamental sema, and why smoke (not HTTP 200) is what catches hydration bugs.
All grounded in the real package.json scripts. Wired into docs/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
The **morfo compiler** itself is the central codegen primitive: `compileMorfo(morfo)`
turns a declaration into a `CompiledMorfo` (resolved attr / keyboard / action
plans + the closed set of CSS selectors eidos may use), cached by morfo identity
(WeakMap). Every consumer reads the compiled morfo, never the raw declaration.
```bash
npm run eidos:purge # production: drop unreached foundation CSS (− 46 to − 55%)
```
## SSR posture
Components are **headless-functional without a DOM** . The architecture keeps SSR
and headless tests working:
- **`dom:false`** injects a shared `disabledDom` no-op consumed by Soma / Sema /
Eidos — there is no silent fallback to direct DOM writes (see
[`arts/adom/README` ](../src/arts/adom/README.md ) and `src/uix/contracts.ts` ).
docs(eidos): la doctrina alcanza a la jornada — dos guards nuevos, el patron de capa, y EID-3 deja de estar pendiente
Barrido de lo que la sesion cambio y la documentacion todavia no decia.
`testing-and-tooling.md` — los dos guards nuevos entran en la tabla de «que
atrapa cada script», con su reparto explicito: `layer:check` mira el valor
computado (quien gana la cascada) y declara su hueco (la geometria, porque
`getComputedStyle` da el valor USADO y un `inset: auto` se lee como pixeles);
`shared-layer-contract.test.ts` mira el texto, y existe por lo que el navegador
no puede ver — un `env()` ya sustituido devuelve `"0px"` en escritorio.
`component-guide.md` fila RTL — deja de remitir a «EID-3 exception» y enuncia la
regla: dos rejillas NOMBRADAS, `Position` fisica y `LogicalPosition` logica, y la
pregunta que decide entre ellas («¿tiene que voltearse para un lector de derecha
a izquierda?»). Estrechar con `Extract<>`, nunca redeclarar.
`canon/recipe-contract.md` — la fila de z-index flotante distinguia mal: la banda
`--z-index-overlay-*` es de overlays PORTALED. El cromo fijado al viewport que no
portala es otra cosa y tiene su peldano (`affix`, 150). Y el item 9 del checklist
de recetas decia «si flota → una rung de overlay», que era incompleto.
`eidos/components/README.md` — el patron de CAPA COMPARTIDA, que no estaba
escrito en ningun sitio pese a tener dos ejemplares vivos (`list-surface` y
`affix`). Sus cuatro reglas, tres de ellas aprendidas rompiendose: enganchar en
el attr de capa y no en la identidad (o `morfo-check` suelda al consumidor a un
contrato ajeno), un eje = token publico + ranura, el puente reafirma `position`
si el primitivo compuesto declara uno, y se guarda con dos redes porque ninguna
basta sola.
`audit-active-uix.md` — EID-3 pasa a RESUELTO, conservando el hallazgo original
debajo. Era un P3 de julio cerrado «como excepcion» pero marcado en su propia
tabla resumen como «pendiente de doctrina explicita». Ya no lo esta.
`PLAN-affix.md` §7 — lo que vino DESPUES de cerrar el plan, que es casi todo lo
interesante: las dos migraciones y sus dos lecciones, el peldano de z, el patron
de tokens, la canonizacion de la rejilla y los dos guards. Ninguna estaba
prevista en el plan; todas salieron de auditar lo construido.
docs:check 0/627.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **`ActiveDom`** resolves the _owner_ `document` / `window` (`getDocument(node)`
docs(corpus): add docs/testing-and-tooling.md — testing, validation, codegen, SSR
Consolidates the cross-cutting verification story that was scattered across
package.json, COMPONENT_GUIDE and SOMA_ARCHITECTURE into one reference:
- The two-project vitest suite (browser client / node server) and how to run one.
- Each validator and the class of bug it catches: morfo:check (DOM vs contract),
morfo:vocabulary (verb drift), component:audit (acceptance), perm:check
(state transitions), smoke (hydration), translations:check, eidos-lint.
- Codegen vs authored: generate:eidos-css, generate:contracts-docs, and the
compileMorfo primitive.
- The SSR posture: dom:false -> disabledDom, ActiveDom owner-document resolution,
ornamental sema, and why smoke (not HTTP 200) is what catches hydration bugs.
All grounded in the real package.json scripts. Wired into docs/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
/ `getWindow(node)` ), so it is correct under iframes, popups and happy-dom —
not bound to the global `document` .
- **Sema is ornamental** — `ActiveUix.events` (the perceptual engine) is optional;
with no engine, `SomaRuntime.trigger()` skips the emit and the component stays
functional. So sound/haptic-free, audio-disabled and server environments work.
- **Hydration is what HTTP 200 misses** — server render succeeds long before a
hydration-time `Context not found` or effect loop would; that is exactly what
`npm run smoke` exists to catch.
docs(uix): la doctrina alcanza a la bolsa única — el corpus deja de enseñar la API muerta
La clase exacta que la auditoría flagueó (doc↔código), producida esta vez
por NUESTROS propios cambios de P0 fase C y sin corregir hasta ahora:
- component-guide §«two sanctioned ways»: reescrita a UNA vía (la bolsa
.props resuelve el contrato entero; extras solo lo que el morfo no puede
expresar; valores CRUDOS; la inversa «morfo sin value ⇒ soma escribe»).
Los 4 snippets con syncAttrs: true, limpiados.
- soma-architecture: partProps re-descrito como LA bolsa (identidad +
contrato completo, SSR incluido); el párrafo del flag sustituido por «el
único escritor imperativo es el prewrite»; snippet limpiado.
- soma.md: snippet de accordion sin el flag.
- morfo.md §naming: el «(SSR included)» dejó de ser contraste — desde la
tubería única TODO plan viaja en la bolsa; lo que distingue a los naming
es la PRECEDENCIA (consumer-first via mergeProps).
- testing-and-tooling: la postura SSR gana el canario ssr-contract.test, y
nace «The gate» (check:gate + ledger menguante, gate, hook — los
instrumentos de fase B no estaban documentados).
- CLAUDE.md: el paso 4 de trigger ya no dice «effect-driven» (prettier
normalizó de paso el fichero entero — solo whitespace, contenido intacto,
declarado aquí para que el diff ancho no sea silencioso).
Lo histórico (changelog, old-deprecated, audit de julio, process/) se queda
como historia. Verificación: docs:check 0 errores sobre 817 docs; cero
menciones normativas de la API muerta fuera de referencias históricas.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
- **The morfo contract server-renders** — since the render bag became the
single attr pipeline (P0 fase C, audit 2026-08-26), a part's `role` /
docs(uix): tanda 2 del contraste con el corpus — el modelo de los capitulos alcanza a la tuberia unica
La lectura completa del corpus (6 lectores Opus, 6/6 censos, ~4,5M tokens)
destapo lo que la tanda 1 no vio, y esta tanda lo cierra:
- El modelo «Effects sync attrs» — repetido VERBATIM en cuatro capitulos
(morfo, soma-architecture, overview, active-architecture), en sus tablas
de piezas, en los cuatro pasos de trigger y en las dos frases-resumen —
muere: la pieza es la bolsa de render; ADom aplica solo el prewrite.
- morfo.md: partProps re-descrito (bolsa completa), la cadena causal de
commits, y las filas de la tabla de ejecutores (data/aria/role → bolsa).
- coincident: los DOS docstrings que ensenaban «in-flight» (types.ts y
morfo.md) se alinean con la equivalencia FIRMADA de sema.md §slider
(«emit-then-handler, like pre; declared indivisible») — el hallazgo del
informe queda refutado como defecto de runtime y reducido a esto.
- glossary: el kind fantasma `internal` (la clase exacta que docs-check:422
mata y su regex no ve en tablas markdown) → `public|private|virtual` real.
- El gate entra en la doctrina: check:gate/gate en el loop de verificacion
(testing-and-tooling y getting-started), eidos:lint como script npm en su
fila, y la tabla de Commands de morfo.md.
- Mi propia sobreafirmacion de ayer, calificada: el test SSR es un CANARIO
de dos representantes sobre mecanismo compartido, no un censo — el censo
por provider queda encolado (P1). morfo:check en getting-started declara
su alcance real (data-*; role/aria sin validador DOM).
- Supervivientes de C2c: el assert-vacio de cropper (la clase «guard sobre
VACIO pasa») retirado con acta; sticky/README deja de citar syncAttrs.
- gradient-builder/README: fila data-kind del Track + acotacion mesh v1.
- Handoff: DOS fe de erratas — «nunca los vio nadie» era falso (vistos y
reducidos 12→3 en cb554ae2e; lo que faltaba era la puerta) y la ley del
escritor imperativo gana su excepcion abierta (textarea autosize, con su
cierre correcto encolado).
Verificacion: docs:check 0/817 · cropper 19/19 · morfo schema+compile 133/133.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
`aria-*` / `data-state` / literals resolve at render time, server included.
The mechanism is SHARED (`partPropsForRegistration`) and pinned by
`src/uix/soma/ssr-contract.test.ts` (server project, node — no window) with
two representatives, Toggle and RadioGroup — a CANARY, not a per-provider
census; the per-component SSR snapshot census is still owed (informe P1).
It was born red against the old client-only effect.
docs(uix): la doctrina alcanza a la bolsa única — el corpus deja de enseñar la API muerta
La clase exacta que la auditoría flagueó (doc↔código), producida esta vez
por NUESTROS propios cambios de P0 fase C y sin corregir hasta ahora:
- component-guide §«two sanctioned ways»: reescrita a UNA vía (la bolsa
.props resuelve el contrato entero; extras solo lo que el morfo no puede
expresar; valores CRUDOS; la inversa «morfo sin value ⇒ soma escribe»).
Los 4 snippets con syncAttrs: true, limpiados.
- soma-architecture: partProps re-descrito como LA bolsa (identidad +
contrato completo, SSR incluido); el párrafo del flag sustituido por «el
único escritor imperativo es el prewrite»; snippet limpiado.
- soma.md: snippet de accordion sin el flag.
- morfo.md §naming: el «(SSR included)» dejó de ser contraste — desde la
tubería única TODO plan viaja en la bolsa; lo que distingue a los naming
es la PRECEDENCIA (consumer-first via mergeProps).
- testing-and-tooling: la postura SSR gana el canario ssr-contract.test, y
nace «The gate» (check:gate + ledger menguante, gate, hook — los
instrumentos de fase B no estaban documentados).
- CLAUDE.md: el paso 4 de trigger ya no dice «effect-driven» (prettier
normalizó de paso el fichero entero — solo whitespace, contenido intacto,
declarado aquí para que el diff ancho no sea silencioso).
Lo histórico (changelog, old-deprecated, audit de julio, process/) se queda
como historia. Verificación: docs:check 0 errores sobre 817 docs; cero
menciones normativas de la API muerta fuera de referencias históricas.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
## The gate
The drift-defense scripts stopped being advisory in P0 fase B (audit
2026-08-26). Three additions:
- **`npm run check:gate`** — `svelte-check` with policy: any ERROR under
`src/` or `scripts/` fails (framework source and its tooling owe zero;
agent probes `scripts/__*` are excluded in `tsconfig.json` ); errors in the
demo tree are measured against the per-file ledger in `scripts/check-debt.ts` , which only
docs(uix): la doctrina alcanza a la bolsa única — el corpus deja de enseñar la API muerta
La clase exacta que la auditoría flagueó (doc↔código), producida esta vez
por NUESTROS propios cambios de P0 fase C y sin corregir hasta ahora:
- component-guide §«two sanctioned ways»: reescrita a UNA vía (la bolsa
.props resuelve el contrato entero; extras solo lo que el morfo no puede
expresar; valores CRUDOS; la inversa «morfo sin value ⇒ soma escribe»).
Los 4 snippets con syncAttrs: true, limpiados.
- soma-architecture: partProps re-descrito como LA bolsa (identidad +
contrato completo, SSR incluido); el párrafo del flag sustituido por «el
único escritor imperativo es el prewrite»; snippet limpiado.
- soma.md: snippet de accordion sin el flag.
- morfo.md §naming: el «(SSR included)» dejó de ser contraste — desde la
tubería única TODO plan viaja en la bolsa; lo que distingue a los naming
es la PRECEDENCIA (consumer-first via mergeProps).
- testing-and-tooling: la postura SSR gana el canario ssr-contract.test, y
nace «The gate» (check:gate + ledger menguante, gate, hook — los
instrumentos de fase B no estaban documentados).
- CLAUDE.md: el paso 4 de trigger ya no dice «effect-driven» (prettier
normalizó de paso el fichero entero — solo whitespace, contenido intacto,
declarado aquí para que el diff ancho no sea silencioso).
Lo histórico (changelog, old-deprecated, audit de julio, process/) se queda
como historia. Verificación: docs:check 0 errores sobre 817 docs; cero
menciones normativas de la API muerta fuera de referencias históricas.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
SHRINKS (the theming-census-debt discipline — a file above its entry, or an
erroring file the ledger does not name, fails). The run must end with the
`COMPLETED` marker and the parsed count must match it: a gate that
docs: el repositorio, el formato y los guards de texto entran en el corpus; cuatro afirmaciones caducas mueren (documentación del cierre)
El plan de cierre cambió cosas de un nivel que el corpus no cubría: la forma del
repositorio, la política de formato, el inventario de lo generado y la clase de
guard que lee TEXTO fuente. Un inventario previo de todo `docs/**` (más los
README de raíz, `src/**` y `apps/**`) midió qué había: los temas de capa estaban
cubiertos, y este nivel no.
NUEVO
- `docs/repository.md` (E0): las zonas y quién escribe en cada una; la LEY de
`web/routes/` congelado y sus dos consecuencias (los validadores de navegador
siguen manuales; el formato no llega ahí); un solo install y un solo workspace
(el argumento de la copia única de Svelte); un solo mapa de importación con el
orden como contrato; qué debe cero y qué debe un ledger que solo mengua.
Enlazada desde el mapa, el README de la raíz, getting-started y AGENTS.md.
- `docs/testing-and-tooling.md` §Format policy: `.prettierignore` enumerado y
justificado (cinco clases), el commit único de formato, el
`git config blame.ignoreRevsFile` que hay que ejecutar a mano y que Gitea no
lo lee.
- `docs/testing-and-tooling.md` §Guards that read source text: la doctrina que
faltaba. Un guard de texto está acoplado al formateador; el positivo se pone
ROJO y te enteras, el NEGATIVO pasa en VERDE sin inspeccionar nada. Los cinco
síntomas medidos en el formateo de una sola vez, seis reglas para escribir uno
que no dependa del formato, y los cuatro pasos antes de commitear un formateo
masivo (neutralidad compilada, la vista de los guards, los validadores que NO
están en el gate, un commit puro).
CORREGIDO (afirmaciones vivas y falsas)
- `README.md` de la raíz: era una plantilla vacía que mandaba `npm install
vicen` con el repositorio `private: true` y sin paquete. Ahora es una puerta.
- `AGENTS.md`: su pre-flight INVIOLABLE mandaba leer dos guías del árbol
congelado (el canónico está migrado), su ejemplo de test apuntaba a
`src/lib/ling/`, borrado en el refactor, y describía cuatro librerías que no
existen. Además decía que los comentarios en castellano valen, contra
CLAUDE.md.
- `docs/theming/guide.md`: los cuatro sitios que llamaban `eidos.listThemes()`
DENTRO de `hooks.server.ts`, donde no hay instancia; ahora `THEME_IDS`
derivado con `listEidosThemes(config)` del módulo que la raíz también importa.
- `docs/architecture/active-uix.md`: la regla 6 decía que la raíz no proyecta
preferencias; hoy standalone proyecta por defecto (`projectPrefs`, `@default
true`) y attach es opt-in. Su ejemplo de arranque montaba una SEGUNDA
proyección a mano.
- `announce`: el opt-in queda calificado (motor desnudo) frente al cableado por
defecto de las raíces, en `book-deviations.md`, `channels.md:58` y el docblock
del canal.
- `docs/getting-started.md` y `docs/architecture/morfo.md`: la política de
`check:gate` también cubre `scripts/`.
- `docs/canon/direction-contract.md`: los dueños literales de la marca (`boot`,
`projection-<n>`) pasan a la prosa, citables por un guard.
- `src/uix/eidos/components/README.md`: regla 8 — un bindable se reenvía con
`bind:`, nunca por el spread del resto (el proxy de rest props no lleva
`set`, así que el tipo promete lo que no ata). Con el `ref` en la superficie
del `Button` y el gap RESUELTO en `cookie-consent`.
`docs/canon/vocabularies.md` y `src/libs/emoji/data.ts` aparecen por fin como
artefactos generados, con su comando.
Ledger: L-133 · L-142 · L-143 · L-154 a ARREGLADO; L-152 conserva los 532
ficheros pero ya con doctrina escrita; nuevas L-161…L-165 (la última, DIFERIDA:
nadie obliga aún a que un guard de texto falle con el corpus vacío).
Verificación: `npm run gate` exit 0 en 542 s — lint limpio · check:gate OK
(89 de web/ en el ledger) · docs:check 0/0 en 822 docs · suite 466/466 ficheros,
5445/5445 tests · apps:check verde. `component:audit` exit 0 con PASS 161 /
NEEDS-WORK 5, las cifras de antes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3 weeks ago
inspected nothing fails, never passes. The mechanism for `scripts/` : Kit's
generated tsconfig lists routes, lib and src, so `svelte.config.js` pushes
`../scripts/**/*.ts` (and `../uix.aliases.js` ) into the include via
`kit.typescript.config` , and the root `tsconfig.json` excludes the probes —
its own `exclude` overrides the generated one, which is why the entry lives
there and not in the config callback.
- **`npm run gate`** — the chain the pre-push hook runs: `lint` first
(`prettier --check`; the repo-wide one-shot landed in the closure plan's F5,
and its commit is listed in `.git-blame-ignore-revs` ) → `check:gate` → the
docs(uix): la doctrina alcanza a la bolsa única — el corpus deja de enseñar la API muerta
La clase exacta que la auditoría flagueó (doc↔código), producida esta vez
por NUESTROS propios cambios de P0 fase C y sin corregir hasta ahora:
- component-guide §«two sanctioned ways»: reescrita a UNA vía (la bolsa
.props resuelve el contrato entero; extras solo lo que el morfo no puede
expresar; valores CRUDOS; la inversa «morfo sin value ⇒ soma escribe»).
Los 4 snippets con syncAttrs: true, limpiados.
- soma-architecture: partProps re-descrito como LA bolsa (identidad +
contrato completo, SSR incluido); el párrafo del flag sustituido por «el
único escritor imperativo es el prewrite»; snippet limpiado.
- soma.md: snippet de accordion sin el flag.
- morfo.md §naming: el «(SSR included)» dejó de ser contraste — desde la
tubería única TODO plan viaja en la bolsa; lo que distingue a los naming
es la PRECEDENCIA (consumer-first via mergeProps).
- testing-and-tooling: la postura SSR gana el canario ssr-contract.test, y
nace «The gate» (check:gate + ledger menguante, gate, hook — los
instrumentos de fase B no estaban documentados).
- CLAUDE.md: el paso 4 de trigger ya no dice «effect-driven» (prettier
normalizó de paso el fichero entero — solo whitespace, contenido intacto,
declarado aquí para que el diff ancho no sea silencioso).
Lo histórico (changelog, old-deprecated, audit de julio, process/) se queda
como historia. Verificación: docs:check 0 errores sobre 817 docs; cero
menciones normativas de la API muerta fuera de referencias históricas.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
fast validators (`morfo:vocabulary`, `docs:check` , `arts:check` ,
`blocks:check` , `packs:check` , `rtl:check` , `translations:check` ,
`agent:check` , `eidos:lint` ) → `apps:check` (check + build + smoke of
`apps/base` , see [`consuming.md` ](./consuming.md ) §8) → the full vitest suite
last. Generated artifacts and the frozen `web/` tree are in
`.prettierignore` .
docs(uix): la doctrina alcanza a la bolsa única — el corpus deja de enseñar la API muerta
La clase exacta que la auditoría flagueó (doc↔código), producida esta vez
por NUESTROS propios cambios de P0 fase C y sin corregir hasta ahora:
- component-guide §«two sanctioned ways»: reescrita a UNA vía (la bolsa
.props resuelve el contrato entero; extras solo lo que el morfo no puede
expresar; valores CRUDOS; la inversa «morfo sin value ⇒ soma escribe»).
Los 4 snippets con syncAttrs: true, limpiados.
- soma-architecture: partProps re-descrito como LA bolsa (identidad +
contrato completo, SSR incluido); el párrafo del flag sustituido por «el
único escritor imperativo es el prewrite»; snippet limpiado.
- soma.md: snippet de accordion sin el flag.
- morfo.md §naming: el «(SSR included)» dejó de ser contraste — desde la
tubería única TODO plan viaja en la bolsa; lo que distingue a los naming
es la PRECEDENCIA (consumer-first via mergeProps).
- testing-and-tooling: la postura SSR gana el canario ssr-contract.test, y
nace «The gate» (check:gate + ledger menguante, gate, hook — los
instrumentos de fase B no estaban documentados).
- CLAUDE.md: el paso 4 de trigger ya no dice «effect-driven» (prettier
normalizó de paso el fichero entero — solo whitespace, contenido intacto,
declarado aquí para que el diff ancho no sea silencioso).
Lo histórico (changelog, old-deprecated, audit de julio, process/) se queda
como historia. Verificación: docs:check 0 errores sobre 817 docs; cero
menciones normativas de la API muerta fuera de referencias históricas.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 month ago
- **The pre-push hook** — source of truth in `scripts/hooks/pre-push` ; arm it
with `cp scripts/hooks/pre-push .git/hooks/pre-push` . Browser-dependent
validators (`morfo:check`, `perm:check` , `smoke` , `layer:check` ) stay
manual — they need a dev server.
docs(corpus): add docs/testing-and-tooling.md — testing, validation, codegen, SSR
Consolidates the cross-cutting verification story that was scattered across
package.json, COMPONENT_GUIDE and SOMA_ARCHITECTURE into one reference:
- The two-project vitest suite (browser client / node server) and how to run one.
- Each validator and the class of bug it catches: morfo:check (DOM vs contract),
morfo:vocabulary (verb drift), component:audit (acceptance), perm:check
(state transitions), smoke (hydration), translations:check, eidos-lint.
- Codegen vs authored: generate:eidos-css, generate:contracts-docs, and the
compileMorfo primitive.
- The SSR posture: dom:false -> disabledDom, ActiveDom owner-document resolution,
ornamental sema, and why smoke (not HTTP 200) is what catches hydration bugs.
All grounded in the real package.json scripts. Wired into docs/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
docs: el repositorio, el formato y los guards de texto entran en el corpus; cuatro afirmaciones caducas mueren (documentación del cierre)
El plan de cierre cambió cosas de un nivel que el corpus no cubría: la forma del
repositorio, la política de formato, el inventario de lo generado y la clase de
guard que lee TEXTO fuente. Un inventario previo de todo `docs/**` (más los
README de raíz, `src/**` y `apps/**`) midió qué había: los temas de capa estaban
cubiertos, y este nivel no.
NUEVO
- `docs/repository.md` (E0): las zonas y quién escribe en cada una; la LEY de
`web/routes/` congelado y sus dos consecuencias (los validadores de navegador
siguen manuales; el formato no llega ahí); un solo install y un solo workspace
(el argumento de la copia única de Svelte); un solo mapa de importación con el
orden como contrato; qué debe cero y qué debe un ledger que solo mengua.
Enlazada desde el mapa, el README de la raíz, getting-started y AGENTS.md.
- `docs/testing-and-tooling.md` §Format policy: `.prettierignore` enumerado y
justificado (cinco clases), el commit único de formato, el
`git config blame.ignoreRevsFile` que hay que ejecutar a mano y que Gitea no
lo lee.
- `docs/testing-and-tooling.md` §Guards that read source text: la doctrina que
faltaba. Un guard de texto está acoplado al formateador; el positivo se pone
ROJO y te enteras, el NEGATIVO pasa en VERDE sin inspeccionar nada. Los cinco
síntomas medidos en el formateo de una sola vez, seis reglas para escribir uno
que no dependa del formato, y los cuatro pasos antes de commitear un formateo
masivo (neutralidad compilada, la vista de los guards, los validadores que NO
están en el gate, un commit puro).
CORREGIDO (afirmaciones vivas y falsas)
- `README.md` de la raíz: era una plantilla vacía que mandaba `npm install
vicen` con el repositorio `private: true` y sin paquete. Ahora es una puerta.
- `AGENTS.md`: su pre-flight INVIOLABLE mandaba leer dos guías del árbol
congelado (el canónico está migrado), su ejemplo de test apuntaba a
`src/lib/ling/`, borrado en el refactor, y describía cuatro librerías que no
existen. Además decía que los comentarios en castellano valen, contra
CLAUDE.md.
- `docs/theming/guide.md`: los cuatro sitios que llamaban `eidos.listThemes()`
DENTRO de `hooks.server.ts`, donde no hay instancia; ahora `THEME_IDS`
derivado con `listEidosThemes(config)` del módulo que la raíz también importa.
- `docs/architecture/active-uix.md`: la regla 6 decía que la raíz no proyecta
preferencias; hoy standalone proyecta por defecto (`projectPrefs`, `@default
true`) y attach es opt-in. Su ejemplo de arranque montaba una SEGUNDA
proyección a mano.
- `announce`: el opt-in queda calificado (motor desnudo) frente al cableado por
defecto de las raíces, en `book-deviations.md`, `channels.md:58` y el docblock
del canal.
- `docs/getting-started.md` y `docs/architecture/morfo.md`: la política de
`check:gate` también cubre `scripts/`.
- `docs/canon/direction-contract.md`: los dueños literales de la marca (`boot`,
`projection-<n>`) pasan a la prosa, citables por un guard.
- `src/uix/eidos/components/README.md`: regla 8 — un bindable se reenvía con
`bind:`, nunca por el spread del resto (el proxy de rest props no lleva
`set`, así que el tipo promete lo que no ata). Con el `ref` en la superficie
del `Button` y el gap RESUELTO en `cookie-consent`.
`docs/canon/vocabularies.md` y `src/libs/emoji/data.ts` aparecen por fin como
artefactos generados, con su comando.
Ledger: L-133 · L-142 · L-143 · L-154 a ARREGLADO; L-152 conserva los 532
ficheros pero ya con doctrina escrita; nuevas L-161…L-165 (la última, DIFERIDA:
nadie obliga aún a que un guard de texto falle con el corpus vacío).
Verificación: `npm run gate` exit 0 en 542 s — lint limpio · check:gate OK
(89 de web/ en el ledger) · docs:check 0/0 en 822 docs · suite 466/466 ficheros,
5445/5445 tests · apps:check verde. `component:audit` exit 0 con PASS 161 /
NEEDS-WORK 5, las cifras de antes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3 weeks ago
## Format policy
Prettier is the only formatter, and `npm run lint` (`prettier --check .`) is the
FIRST member of the gate: the tree is either formatted or the push is rejected.
Style values (tabs, single quotes, no trailing commas, 100 columns) live in
`.prettierrc` and are summarized in [`CLAUDE.md` ](../CLAUDE.md ) → Code Style.
`.prettierignore` holds five kinds of exception, and nothing else:
| Excluded | Why |
| ----------------------------------------------------------------------- | --------------------------------------------------------- |
| lockfiles | the package manager owns them |
| `/static/` | assets, not source |
| the generated artifacts (§ Codegen) — including `canon/vocabularies.md` | the generator owns the bytes; see the invariants above |
| `web/` | the frozen demo tree ([`repository.md`](./repository.md)) |
| `.claude/` | tool configuration, including the author's local settings |
The historical repo-wide debt was paid in a single formatting-only commit, and
that commit is listed in `.git-blame-ignore-revs` . `git blame` ignores it only
once per clone, on request:
```bash
git config blame.ignoreRevsFile .git-blame-ignore-revs
```
(GitHub honours the file by name; the Gitea remote this repo pushes to does
not — the mitigation is the config above, plus keeping formatting commits pure.)
**A formatting pass is a contract change for every guard that reads source
text** — the next section says why, and what to measure before committing one.
## Guards that read source text
A large family of guards here does not run the code: it READS it. A test or a
script opens `.ts` / `.svelte` / `.css` / `.md` files and asserts on the text —
`contracts.test.ts` , the censuses (`focus-census`, `source-census` ,
`pack-census` , `opts-census` ), `recipe-css-contract` , `value-channels` ,
`docs-check` , `component-audit` , `eidos:lint` , `rtl-check` . They catch what
types cannot: a declaration nobody wired, a token spelled by hand, a doc that
copied a canonical list instead of linking it.
The price is a coupling nothing declares: **a text guard is coupled to the
formatter.** Reformat the tree and some of them change what they inspect. One
direction is loud, the other is silent:
- a **positive** guard (this must be PRESENT) that stops matching goes RED
against correct code — noisy, but you find out;
- a **negative** guard (this must be ABSENT; the offender list must stay empty)
that stops matching goes GREEN while inspecting nothing. The gate says OK and
the contract is gone. It is the same failure as a guard whose corpus is empty:
`check-gate.ts` refuses to judge without the `COMPLETED` marker for exactly
this reason.
Measured on the repo-wide pass, one of each:
| Symptom | Cause |
| ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| A capture ran past its own declaration into the next one, so a field living in the WRONG type satisfied the assert | the delimiter was `\}>;` , and a long declaration prints as `}` then `>;` on the next line |
| `/policy:.*runtime\.focus/` went red against correct code | `.` does not cross a newline, and the value wrapped |
| Disposition markers in a `## Gaps` section dropped to zero | `*diferir*` normalizes to `_diferir_` , and `_` is a word character, so `\b` stops matching |
| Six false offenders in the CSS typography rule | a per-line matcher read `calc(` as the whole value, and the `/* literal: … */` valve fell outside the match |
| A whole chronicle became ONE line for anything splitting on `\n` | `endOfLine: "auto"` amplified a single stray CR into a CR-only file |
### Writing one that does not depend on the formatter
- **Anchor on tokens, not on line shape.** Let whitespace be whitespace:
`\}\s*>;` instead of `\}>;` , `[^;{}]+` instead of `[^\n]+` .
- **Bound the scan by the construct.** A lazy `[\s\S]*?` needs a delimiter that
can only appear where the thing you are matching ends.
- **In markdown, `\b` is not a word boundary** — emphasis markers are word
characters. Use letter boundaries: `(?<!\p{L})…(?!\p{L})` .
- **Ask the compiler when you can.** A hand-written morfo-targeting selector is
an architecture violation because a rename must break at type level (CLAUDE.md
→ Eidos drift defense); a guard that could read the AST or import the module
instead of grepping is the same argument.
- **Fail on an empty corpus.** Assert the count of files/candidates you
inspected, so a guard that stops finding its subject goes red instead of
green.
- **See it fail.** Plant the violation, watch it fail, restore the file byte for
byte. A text guard whose red nobody has seen is a decoration.
### Before committing a formatting pass
1. **Neutrality of the code** — compile and minify every changed file on both
sides (esbuild for `.ts` / `.css` , the Svelte compiler for `.svelte` , client
AND server) and compare. Differences must be explained, not assumed. (On the
repo-wide pass: 1 031 files byte-identical, 9 CSS differing only in
whitespace immediately inside a parenthesis, which CSS does not tokenize.)
2. **The guards' own view** — extract the patterns of every text guard and
count their matches on both sides. A count that moves is a guard to inspect,
the negative ones first.
3. **The whole gate, plus the validators that are NOT members**
(`component:audit`, `theming:sentinel` , the browser-driven ones): a red
outside the gate is still a red.
4. **One commit, formatting only** , listed in `.git-blame-ignore-revs` .
docs(corpus): add docs/testing-and-tooling.md — testing, validation, codegen, SSR
Consolidates the cross-cutting verification story that was scattered across
package.json, COMPONENT_GUIDE and SOMA_ARCHITECTURE into one reference:
- The two-project vitest suite (browser client / node server) and how to run one.
- Each validator and the class of bug it catches: morfo:check (DOM vs contract),
morfo:vocabulary (verb drift), component:audit (acceptance), perm:check
(state transitions), smoke (hydration), translations:check, eidos-lint.
- Codegen vs authored: generate:eidos-css, generate:contracts-docs, and the
compileMorfo primitive.
- The SSR posture: dom:false -> disabledDom, ActiveDom owner-document resolution,
ornamental sema, and why smoke (not HTTP 200) is what catches hydration bugs.
All grounded in the real package.json scripts. Wired into docs/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
## See also
docs: el repositorio, el formato y los guards de texto entran en el corpus; cuatro afirmaciones caducas mueren (documentación del cierre)
El plan de cierre cambió cosas de un nivel que el corpus no cubría: la forma del
repositorio, la política de formato, el inventario de lo generado y la clase de
guard que lee TEXTO fuente. Un inventario previo de todo `docs/**` (más los
README de raíz, `src/**` y `apps/**`) midió qué había: los temas de capa estaban
cubiertos, y este nivel no.
NUEVO
- `docs/repository.md` (E0): las zonas y quién escribe en cada una; la LEY de
`web/routes/` congelado y sus dos consecuencias (los validadores de navegador
siguen manuales; el formato no llega ahí); un solo install y un solo workspace
(el argumento de la copia única de Svelte); un solo mapa de importación con el
orden como contrato; qué debe cero y qué debe un ledger que solo mengua.
Enlazada desde el mapa, el README de la raíz, getting-started y AGENTS.md.
- `docs/testing-and-tooling.md` §Format policy: `.prettierignore` enumerado y
justificado (cinco clases), el commit único de formato, el
`git config blame.ignoreRevsFile` que hay que ejecutar a mano y que Gitea no
lo lee.
- `docs/testing-and-tooling.md` §Guards that read source text: la doctrina que
faltaba. Un guard de texto está acoplado al formateador; el positivo se pone
ROJO y te enteras, el NEGATIVO pasa en VERDE sin inspeccionar nada. Los cinco
síntomas medidos en el formateo de una sola vez, seis reglas para escribir uno
que no dependa del formato, y los cuatro pasos antes de commitear un formateo
masivo (neutralidad compilada, la vista de los guards, los validadores que NO
están en el gate, un commit puro).
CORREGIDO (afirmaciones vivas y falsas)
- `README.md` de la raíz: era una plantilla vacía que mandaba `npm install
vicen` con el repositorio `private: true` y sin paquete. Ahora es una puerta.
- `AGENTS.md`: su pre-flight INVIOLABLE mandaba leer dos guías del árbol
congelado (el canónico está migrado), su ejemplo de test apuntaba a
`src/lib/ling/`, borrado en el refactor, y describía cuatro librerías que no
existen. Además decía que los comentarios en castellano valen, contra
CLAUDE.md.
- `docs/theming/guide.md`: los cuatro sitios que llamaban `eidos.listThemes()`
DENTRO de `hooks.server.ts`, donde no hay instancia; ahora `THEME_IDS`
derivado con `listEidosThemes(config)` del módulo que la raíz también importa.
- `docs/architecture/active-uix.md`: la regla 6 decía que la raíz no proyecta
preferencias; hoy standalone proyecta por defecto (`projectPrefs`, `@default
true`) y attach es opt-in. Su ejemplo de arranque montaba una SEGUNDA
proyección a mano.
- `announce`: el opt-in queda calificado (motor desnudo) frente al cableado por
defecto de las raíces, en `book-deviations.md`, `channels.md:58` y el docblock
del canal.
- `docs/getting-started.md` y `docs/architecture/morfo.md`: la política de
`check:gate` también cubre `scripts/`.
- `docs/canon/direction-contract.md`: los dueños literales de la marca (`boot`,
`projection-<n>`) pasan a la prosa, citables por un guard.
- `src/uix/eidos/components/README.md`: regla 8 — un bindable se reenvía con
`bind:`, nunca por el spread del resto (el proxy de rest props no lleva
`set`, así que el tipo promete lo que no ata). Con el `ref` en la superficie
del `Button` y el gap RESUELTO en `cookie-consent`.
`docs/canon/vocabularies.md` y `src/libs/emoji/data.ts` aparecen por fin como
artefactos generados, con su comando.
Ledger: L-133 · L-142 · L-143 · L-154 a ARREGLADO; L-152 conserva los 532
ficheros pero ya con doctrina escrita; nuevas L-161…L-165 (la última, DIFERIDA:
nadie obliga aún a que un guard de texto falle con el corpus vacío).
Verificación: `npm run gate` exit 0 en 542 s — lint limpio · check:gate OK
(89 de web/ en el ledger) · docs:check 0/0 en 822 docs · suite 466/466 ficheros,
5445/5445 tests · apps:check verde. `component:audit` exit 0 con PASS 161 /
NEEDS-WORK 5, las cifras de antes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3 weeks ago
- [`docs/repository.md` ](./repository.md ) — the zones these tools run over (and the frozen demo tree).
docs(corpus): add docs/testing-and-tooling.md — testing, validation, codegen, SSR
Consolidates the cross-cutting verification story that was scattered across
package.json, COMPONENT_GUIDE and SOMA_ARCHITECTURE into one reference:
- The two-project vitest suite (browser client / node server) and how to run one.
- Each validator and the class of bug it catches: morfo:check (DOM vs contract),
morfo:vocabulary (verb drift), component:audit (acceptance), perm:check
(state transitions), smoke (hydration), translations:check, eidos-lint.
- Codegen vs authored: generate:eidos-css, generate:contracts-docs, and the
compileMorfo primitive.
- The SSR posture: dom:false -> disabledDom, ActiveDom owner-document resolution,
ornamental sema, and why smoke (not HTTP 200) is what catches hydration bugs.
All grounded in the real package.json scripts. Wired into docs/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
- [`docs/getting-started.md` ](./getting-started.md ) — the short verification loop in context.
docs(book): F7.5 (1/2) — checklist + audit guide + demo guide moved to docs/guides/
Three English guides moved verbatim (copy + link touch-ups, no
translation): COMPONENT_COMPLETION_CHECKLIST -> guides/
completion-checklist.md, COMPONENT_AUDIT_GUIDE -> guides/
component-audit.md, DEMO_AUTHORING_GUIDE -> guides/demo-authoring.md.
Tooling moved with its doc in the same pass: docs-check I5 now parses
the checklist at the new path (verified: 0 errors, rule tables found)
and component-audit.ts's two path strings updated. One reconciliation
in the audit guide's s5, applied as link-don't-copy: the copied v1
6-tab template list (stale vs the v2 9-tab guide it links, drawer
canary vs button) is replaced by a pointer to demo-authoring.md; the
domain canaries in s7 stay. demo-authoring's harness links now reach
into web/routes/uix/lib/ (the modules stay with the code); the deleted
pendiente_color_demos.md reference is marked TODO(reconcile). Corpus
swept: building-a-component (frontmatter related: + phases 6/8),
authoring, architecture/soma, theming/reference s5-parity,
testing-and-tooling, getting-started, README (E4 rows + component-audit
row added + two stale F7.3 paths in 'I want to' fixed). Remaining
warns = links to component-guide.md, which lands in F7.5 (2/2).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
- [`component-guide.md` ](./guides/component-guide.md ) — the build checklist that calls these.
- [`completion-checklist.md` ](./guides/completion-checklist.md ) — what `component:audit` enforces.