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 # types — svelte-kit sync & & svelte-check (expect 0 errors)
npm run test # the vitest suite (one run)
npm run lint # prettier --check · npm run format to fix
```
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 ). |
| `scripts/eidos-lint.ts` · `eidos-lint-all.ts` | classifies every `[data-*]` selector in eidos CSS as **morfo-backed / eidos-only / invalid** — drift between the morfo contract and the CSS. (Opt-in safety net; the architectural defense is the typed `semaSelector` builder — see the "Eidos drift defense" rule in CLAUDE.md.) |
| `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(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 | Generates from |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
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
| `npm run generate:eidos-css` | the eidos foundation/recipe CSS, from `EidosConfig.recipes` . (`generated/base.css` is output — regenerate, don't hand-edit.) |
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.
## See also
- [`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.