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

113 lines
16 KiB

---
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_.
## 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
[`soma-architecture.md`](./architecture/soma-architecture.md) §6.
## 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. |
## 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 |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `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.)
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)`
/ `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.
- [`component-guide.md`](./guides/component-guide.md) — the build checklist that calls these.
- [`completion-checklist.md`](./guides/completion-checklist.md) — what `component:audit` enforces.

Powered by TurnKey Linux.