Ship the base theme's default families (Instrument Sans / Lora / Azeret Mono --
identity unchanged) as self-hosted VARIABLE woff2 (SIL OFL, latin subset, wght
range, preload on primary), so the engine's variable path is exercised by the
default theme, not merely capable. The hand-written themes/fonts.css is retired
(@font-face is config-driven from typography.families[].faces); the static TTF
set under static/fonts/air is removed.
Also close the theming-API gaps so it supports ANY variable font, not just
wght+opsz:
- FontAxes is now a 4-letter-tag map. renderFontFace emits a descriptor per
registered axis: wdth -> font-stretch: min% max%, slnt -> font-style: oblique
(OpenType slnt negated to the CSS oblique sign), alongside wght/opsz.
- TypographyStyle.variationSettings -> --style-{name}-font-variation-settings,
applied by the Text recipe (fallback normal), engaging non-standard axes
(GRAD/MONO/custom) and fixed axis defaults.
Verified: variable faces load with weight ranges + mid-axis rendering; new axis
+ variation-settings emission covered by active-eidos-config.test.ts (99 pass);
npm run check src/ = 9-error baseline (0 new); no default-font regression.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a canonical `readonly` prop to Select and ToggleGroup (morfo -> soma ->
eidos + provider tests), mirroring radio-group/Field: the value stays legible
(unlike `disabled`) while interaction is gated. Chronos view-mode composes it
and the `[data-view]` disabled-stripping workaround is removed.
Chronos consolidation (recipe/doctrine + behavior), verified in-browser:
- recipe: focus box-shadow -> outline (theming ss32), opacity/typography ->
tokens, hover -> state-layer (R-4.2 / R-2.7 / R-4.3).
- event tooltip composed from the framework Tooltip (`eventTooltip` snippet);
`color` prop wired to the accent (`--_chronos-accent` per `data-color`).
- edits dispatch the `update` command; Intl -> getCachedDateFormat; ToggleGroup
and Select migrated `type` -> `selectionMode`.
- README restructured to the F-* format (Baseline / Comparativa / Gaps).
recipes/base.ts + generated/base.css are intentionally excluded (their working
tree carries unrelated typography/font changes); the now-unused chronos
`focus-shadow` recipe token stays until a clean regen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a "Foundation globals" section to eidos/archetypes.css (document-wide,
not archetype-keyed) closing the two zero-coverage systemic gaps + the
scrollbar item from the F4-D GAP menu:
- ::selection — translucent accent wash (background only, text keeps its
colour so it stays legible in light and dark)
- caret-color — accent identity on input/textarea/contenteditable, in
:where() so a field recipe can override (invalid -> threat)
- native scrollbars — themed + thin via the STANDARD properties on :root
(Firefox + Chromium >= 121). Heavy ::-webkit-scrollbar deliberately
skipped: ScrollArea draws overlay bars and hides the native one inline
(scrollbar-width: none on its viewport, which wins). Thumb colour matches
ScrollArea's thumb.
Cursors were already archetype-wired (trigger/close/action/item/option =
pointer, thumb = grab/grabbing, disabled = not-allowed, text zones = native
input + explicit cursor:text in date-field/editable) — no change needed.
All values read role tokens (--color-primary-solid, --color-content-muted),
lowest specificity so any component recipe still wins.
Verified live (tags-input demo, base-dark): input caret = --color-primary-solid
exactly; scrollbar-width thin applied; ::selection rule present + token
resolves; docs-harness :root override wins (app > foundation). npm run check
src/ = 9-error baseline, 0 new.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a close-of-session state block at the top: what shipped this session
(media-player Batch-4, THM-2 full rollout + avatar + closure, THM-4
5-hotspot adjudication) with commit refs, the real-component verification
method, and the remaining §9 / side queue (F4-D GAP scoping, motion
cascade-vs-signatures).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adjudicate color-picker (29), avatar (28), time-range-picker (26): all
0 debt — composition (de-dialoged pickers compose Popover; avatar's
per-role color now lives in the shared layer after the THM-2 migration;
sliders/toggle composed), behavioral (sema last-action, format, endpoint,
loading status), and per-file-lint blind spots (recipe-token variant
rules). Across the 5 biggest hotspots (156 unused) the only real debt was
stepper's dual-representation API, now consolidated. Confirms the doctrine:
the unused column stays informational, no machine rule warranted. THM-4
closed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every step part (item/trigger/indicator/separator) declared BOTH
`data-state` (enum) AND `data-current`/`data-complete`/`data-incomplete`
(booleans) — the same state twice, used inconsistently (enum on
trigger/indicator, boolean on separator). Consolidate on the canonical
`data-state`:
- morfo: prune the 12 boolean declarations.
- provider: drop the current/complete/incomplete sources
(item/indicator/separator) + the trigger's explicit boolean writes +
the now-unused isComplete/isIncomplete getters (isCurrent stays — it
drives aria-current/tabindex).
- separator.css: [data-complete] -> [data-state='complete'].
- README + provider test updated to the single form.
Verified with the real component (Next advances → complete/current/
incomplete via data-state, boolean attrs gone, complete separator still
paints). stepper unused 30->18; provider test + contracts green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Burn the two biggest THM-4 hotspots. media-player (47 unused): 0 real
debt — all composition artifacts (composed Buttons/Sliders), behavioral
state mirrors of the media element, default-state enum values, or
documented-v2 roadmap surfaces (settings-button, custom captions).
stepper (30 unused): mostly legit + one API redundancy — every step
part declares both data-state (enum) and data-current/complete/incomplete
(booleans), used inconsistently (enum on trigger/indicator, boolean on
separator). Consolidating is a public-API design decision, not a prune.
Emerging read (2 batches): hotspots are mostly legitimate; genuine
declared-for-nothing debt is rare, confirming the doctrine — the debt
rate does not justify a machine rule. THM-4 is mostly documented
adjudication.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Record the rollout as shipped (05f0031c + cc7e9a16) and re-label the
Avatar.Badge as a deliberate design boundary, not debt: a status badge
takes a role/intent or a direct CSS color (MUI/Spectrum/Bootstrap =
semantic; Chakra/Mantine/Ant = direct), and no framework routes an
avatar's status badge through a brand-scale palette. THM-2 closed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The avatar body's per-instance palette now resolves through the shared
per-instance layer (size collapse, behavior-preserving for roles, adds
the 33 scales):
- avatar.svelte: isCanonicalColor recognizes palette scales, so a scale
name routes to data-color instead of the custom CSS-color path ('teal'
is also a CSS color name, so it used to fall to --avatar-color-custom).
- recipes/base.ts: _palette-{solid,surface,contrast,text,border} (host
fallback only - the avatar always emits a canonical data-color, so the
presence-guarded forward routes roles + scales) + _bg/_fg/_border move
from a variant x color matrix to variant-only readers of
--_avatar-palette-*. The matrix helper + intermediates stay (the badge
still uses them; 0 orphans). avatar.css unchanged.
- demo: scale picker.
Verified end-to-end with the REAL component (drive the demo color control
-> the avatar emits data-color -> the shared layer resolves the exact
scale): affirm+soft behavior-preserving, teal+soft = scale-teal-a2
(translucent surface), teal+solid = scale-teal-9.
The Avatar.Badge sub-part (aria-hidden decorative chip with its own color
+ default) stays on its role palette + custom-CSS: migrating it needs a
per-part forward + pruning ~36 orphaned intermediates, disproportionate
for a decoration whose arbitrary-color case already works. Documented for
a decision.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
media-player Batch-4 (closes SOM-4): the 10 sub-parts migrate to
renderProps() (35 attr-dup hits -> 0). Register the sources the morfo
reads (label propRef, on stateRef, direction/type) so renderProps emits
type/role/aria-*/data-state; keep only contract-only soma-owned attrs.
Pin the soma-attr-audit ceiling to 0.
THM-2 rollout - collapse each per-component palette cascade into the
shared per-instance layer (size win, behavior-preserving for roles,
adds the 33 scales):
- Rename palette tokens to canonical _palette-{slot} + route via the
presence-guarded forward: tags-input, stepper, badge, card, select
(parts-aware trigger+content), file-upload, editable, tag-group.
- Extend the shared vocabulary with alpha surface(a2)/surface-hover(a3)
slots (soft variant of variant-aware recipes) and hover(4) - the
latter also fixes Toggle's latent scale-hover.
- tag-group: variant-aware migration (solid/outline -> canonical,
soft -> alpha surface; merge outline-fg into text, prune orphans).
- toggle-group: replace the 4-role cross-recipe composition with a
hand-authored presence-scoped route to the shared layer (the
composition DSL can't presence-scope); covers roles + 33 scales.
- Widen color to ComponentColor (roles + 33 scales) where arbitrary
color is meaningful: badge, tag-group, tags-input, toggle-group, and
add the scale picker to their demos. Semantic controls stay restricted.
Verified end-to-end with the REAL components (drive the demo color
control -> the component emits data-color -> the shared layer resolves
the exact scale). Gates: recipe-css-contract/config/contracts/
soma-attr-audit/media-player suites green; 0 orphan tokens.
avatar remains for a focused pass: its variant-resolved matrix and badge
sub-part don't fit a mechanical migration.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ruta-herramienta en web/routes/temas/sema/. Dogfoodea tokens de eidos y
consume solo API publica de $uix/sema y $uix/eidos (cero cambios en src/uix).
- Seleccion por 2 ejes del canon: 8 familias x 6 intents (loss incluida).
- Dispara el evento por los 3 canales reales (EngineSemantic.emit): visual
(data-event-* -> signature de eidos), sound y haptic, con mezclador.
- Subir .wav: analisis DSP propio 0-dep (autocorrelacion pitch, FFT
centroide + planitud espectral, contorno por trayectoria f0, RMS) ->
coloca el sonido en el evento del canon mas cercano + ranking de encaje.
- Desviacion por eje vs la firma canonica (SEMA_MAP familia+intent) con
veredicto de coherencia valencia-aware.
- Export de pack Sema (codigo + JSON).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per request: one `colors` prop that discriminates by shape instead of two
rival props. A `string[]` is an explicit stop list (unchanged); a bare
`string` names a canonical gradient from the theming's named set, resolved as
`var(--gradient-{name})` — exactly what the removed `preset` prop did. The set
is an open cage (`EidosConfig.gradients` / `applyGradients`), so the type stays
`string | readonly string[]`, not a closed union. Removed `preset` outright (no
back-compat shim, per project rule); the canonical S9 vocabulary and raw stops
are now the SAME input.
Docs shell: register a small canonical named set on `uix/+layout@` via
`applyGradients` (`brand`, `spectrum`) — role-derived, so they re-tint with the
seed and flip light/dark. Demo gains a live stops|named toggle so both branches
are a real testbed.
Finding worth recording (types + README): a named gradient painted through
`background-clip: text` must be a single `<image>` (linear/radial/conic). A
role-derived MESH serializes to radials + a base COLOR, and a bare color is not
a valid `background-image` (only the `background` shorthand accepts it) — so a
mesh name computes to `none` and never paints. The docs set is linear-only for
this reason.
Verified in real Chrome: stops branch paints the token gradient; `colors="spectrum"`
paints `var(--gradient-spectrum)` through the text. svelte-check 0 own errors,
component:audit 141/0/0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Looking at the original seed demo (a big bold "1,000+" stat), the ported
CountUp was impoverished: a plain grouped decimal, no affixes, no currency/
percent — "just a countdown, you don't need an animation for that".
- Component: add the affixes the seed had (`prefix`/`suffix`, each in its own
span) and the FULL `<FormatNumber>` option surface (`formatStyle` currency/
percent/unit · `notation` compact · fraction digits) — delivering the D-T2
"both share the same formatter" promise: a count animates toward a currency,
a percent or a compact value, not just a decimal. Render with
`font-variant-numeric: tabular-nums` inline so digits don't jitter while
counting (no CSS recipe — E-2.2 exception intact).
- Fix a fraction-digits bug: min-fraction inherited the raw value's decimals
(0.999 → "99,900%"); default min to 0 so `maximumFractionDigits` governs.
- Demo: present it as an animated STAT — big/bold/tabular-nums, suffix "+",
a preset row (12.500+ users · $1,2M · 99,9% · ↓3,2s) and format controls.
Verified in real Chrome: "382+" counts to "12.500+"; the $1,2M preset animates
compact EUR ("36,4 mil €" → "1,2 mill €"). Matrix 141/0/0, check clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Estado: F0·F1·F2·F3·F4-C·SEM-4·THM-2 ✅ commiteadas/pusheadas. El bloque
ARRANQUE reescrito: media-player Batch-4 (cierra SOM-4) con el diagnóstico
completo (10 sub-partes hardcodean attrs que el morfo declara; migración
renderProps parte-a-parte; plantilla carousel/table; cierre con ceiling +
navegador) para ejecutar en frío sin re-scopear. Cola posterior: rollout
THM-2 (12) · hotspots THM-4 · F4-D GAP (scoping) · cascada-vs-firmas.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
El mecanismo genérico ya existía (universalPaletteDecls auto-completaba las 33
escalas para recetas con tokens palette-*), pero con PREFIJO de componente
(--button-palette-*) — cada superficie pagaba ~21 KB, por eso solo button/toggle
lo tenían (rollout a las 17 = ~+315 KB). Colapso al modelo compartido:
- renderSharedPaletteLayer: UNA cascada component-agnóstica
[data-color='{role|scale}'] { --palette-{slot}: … } — 8 roles + 33 escalas,
emitida una vez (~19 KB). Roles 1:1 a --color-{role}-*; escalas con el step
map + on-solid contrast, valor idéntico a la cascada per-component retirada.
- renderRecipePaletteForward: toda receta con palette-* (público) o _palette-*
(privado) recibe [data-{c}][data-color] { --{c}-palette-{slot}:
var(--palette-{slot}, host-default) }. La guarda de PRESENCIA es la seguridad
de anidamiento — un hijo sin color dentro de un ancestro coloreado matchea
solo [data-{c}] (su default) y nunca lee el --palette-* heredado.
- Generalización a la paleta PRIVADA: checkbox/radio-group/switch ganan las 33
escalas con CERO cambio de CSS (ya consumen --_{c}-palette-*).
- universalPaletteDecls eliminado; 2 guards migrados al modelo compartido
(recipe-css-contract "shared layer + forward"; active-eidos-config contrast
en la capa compartida).
DONE (per-instance): button, toggle, checkbox, radio-group, switch (5/17).
Rollout de las 12 restantes en docs/process/continue-cleanroom-fixes §THM-2.
Doctrina en theming/reference §25 ("The per-instance palette layer").
Verificado en vivo (button + checkbox): color="teal" → escala teal exacta ·
affirm → rol exacto · primary → primary · nested-nocolor en ancestro teal →
primary (sin contaminación). Peso 345K → 329K. Gates: matriz 141/141 ·
eidos 314 · recipe-css-contract + active-eidos-config 98/98 · contracts 38/38.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- CountUp WAS shipped (as a service component, filed under Utilities) but the
user looked for it among the text animations and the number rendered
invisibly. Two fixes:
- Group it under a "Text effects" nav group with the other five (all 6 of
the seed text/ collection together), and match the page eyebrow. It stays
a FormatNumber sibling in the design doc; the nav groups for discovery.
- The bare number inherited the eidos text color while the demo stage used
the docs-chrome (light) surface → invisible. Give every text/service demo
stage an eidos surface + text color (both from the same theme → contrast
in any mode), the same fix as the ambient stage.
- Verified in real Chrome: CountUp counts 0→1.234.567,89 (es-ES separators)
and is clearly visible; the "Text effects" sidebar group lists all six.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The catalog work shipped but was unreachable and impoverished:
- **Nav**: the sidebar IA (web/routes/uix/+layout@.svelte) is a manual list;
the new components were never added, so nothing linked to them. Add a
"Text effects" group (TextGradient/Circular/Blur/Focus/Scramble), CountUp
under Utilities, and a "Packs" group (Ambient · backgrounds).
- **Ambient demo → real testbed**: rebuild web/routes/uix/packs/ambient as a
proper interactive page — effect selector (32, grouped Agentic/Tier A/B),
live param controls AUTO-GENERATED from each effect's `defaults`
(number→slider, boolean→toggle, colors→editable token list, string→text),
a stage-background toggle (surface/black/white/transparent), reset, and a
copyable usage snippet. The old page only switched effect, no tuning.
- **fog + mesh painted nothing**: their seeded colors were near-invisible on
the dark base theme — fog used neutral-bg2 (L 0.21) + neutral-element
(L 0.25), mesh used four -element slots (L ~0.26) against surface L 0.18.
Reseed with high-contrast tokens (fog: surface bg + neutral-text; mesh:
-solid stops). Verified in a real browser: aurora/mesh/fog all paint.
- Repoint the six demo ledes from the ephemeral plan to
docs/decisions/design-text-effects.md (matches the READMEs).
check 0 own errors. Verified live (real Chrome): all effects paint, controls
tune params, nav reaches every new page.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two streams, split by what the animation touches:
STREAM A — decorative backgrounds → the pack tier
- arts/scene: a consolidated scene runtime ($scene) that owns, once, the
citizenship every ad-hoc background reinvented or skipped (frame loop,
off-view pause, DPR cap, mandatory reduced-motion, WebGL context
loss/restore, scene budget, teardown). SceneDom port (adom satisfies it),
webgl/webgl2/canvas2d drivers + a custom-pipeline extension (vertexShader +
draw + glContext.depth/dprCap) for real geometry (beam, particles, dither,
grid, eter, pixel-blast, hyperspeed). 32 effects as shared resources.
- src/packs/ambient: the first pack — <Ambient effect="…"> mounts a registered
effect; the P contract (P-1..P-6) guarded by scripts/packs-check.ts; colors
are token-aware (P-4). One-way dependency, removable-by-construction.
- resolveToken extended to semantic color slots (--color-{role}-{slot}) so
consumers resolve theme tokens to concrete colors (the P-4 half).
STREAM B — animations over real text → canon
- Six components (count-up + text-{gradient,circular,blur,focus,scramble}):
each a morfo + eidos recipe (where there's styling) + demo. CountUp is a
service component (counts through uix.format.numbers). The five Text* are
passive decoratives. Upgrades over the seeds: SR hardening (real text
visually-hidden + aria-hidden decoration), a11y fix (no fake role=button),
measurement discipline (cached rects via dom.measure, no reflow storm),
reduced-motion, ecosystem citizenship (eidos.dom/timers, no raw platform).
- MorfoElement gains 'p'.
DOCS
- docs/architecture/packs.md (pack tier, admission rule, P contract, Aura
promotion path); docs/decisions/design-text-effects.md (the family design
record) + indexed in decisions.md / README.md; glossary entries
(scene/Ambient/Aura/text effects); scene README custom-pipeline + authoring
bridge; motion-guide content-effects note; strata tables acknowledge packs.
Gates: component:audit 141/0/0 · docs:check 0/0 · scene tests 9/9 · packs:check
0/36 · check 0 own errors. Verified in browser (32 effects mount+compile;
6 text components SSR+hydrate, CountUp re-formats by locale live, TextGradient
resolves token stops to OKLCH via var()).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- book-deviations: los caveats de D.6 (emisión dormida + branch-vs-item) marcados
RESUELTOS con verificación en vivo 2026-07-12 (los 6 providers emiten; packs con
onBranch/onRow casan con los targets reales) — el párrafo stale fue citado por la
clean-room como evidencia de dormancia: lección anotada (el registro se actualiza
en el mismo pase que el cableado). D.11: párrafo de pickers actualizado al cierre
real (delegado closeWith→dismissWith, b55ca6ee).
- continue-cleanroom: SEM-4 sesión 2 cerrada por verificación (stamps
open·emerge / commit-select·commit·affirm en vivo); D.2 (flag emission)
DESCARTADO — el gap que auditaba ya no existe y el check estático sería frágil
(Simplicity First). Arranque siguiente = cola F4 restante (THM-2 diseño universal ·
media-player Batch-4 · hotspots THM-4 · F4-D).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
F2 — lote mecánico (13 ítems):
- DEP-2 ogl eliminado (0 imports) · DEP-1 clsx inlineado como toClassString
propio + suite de contrato (props.test.ts; soma.md §12 cerrado).
- THM-7: los 5 selectores manuales de sema.md reescritos con semaSelector
(los ejemplos [data-toast-root] apuntaban a un part INEXISTENTE — la
deriva que el builder previene, demostrada en el propio doc).
- MOR-1 escape isomorfo + validación de attr-names en semaSelector + 9
tests (selectors.test.ts, matches() real con comillas/corchetes) ·
MOR-2 partMarkerAttr = única fuente compilador↔builder + test de paridad ·
MOR-3 _resetCompileCache borrado (0 usos).
- SOM-2 keydown continue en match sin handler + keyboardFixtureMorfo ·
SOM-1 no-await de handlers (censo async = 0; contrato V1 cumplido) + pin.
- SEM-2 trigger pre-attacha catch con logger (void trigger sin unhandled
rejection; throw intacto para awaiters) + pin · SEM-3 fallback muerto de
applyDominance → skip defensivo + timer tope de awaitExpression cancelado ·
SEC-1 adjudicado YA implementado (assertCssVariableValue desde 2026-05-11)
+ pin del path de VALOR.
- accordion → outline (§32; su outline:none dejaba CERO anillo en HCM) —
verificado en vivo · THM-6 radius-full 9999px · EID-4 recuentos 33.
F3 — censos con guard:
- SOM-3 cerrado: announcer + image-provider migrados a scheduler-preferred
(consumidores cableados: date/time-field vía soma.uix.timers; avatar/image
vía eidos.timers — verificado en vivo); guard de timers ENSANCHADO de
soma/components a TODO soma y pasado a EVIDENCIA (setTimeout exige
.schedule( en el fichero — layers/ y datetime/ escapaban del ámbito viejo).
- THM-5: R-4.7 nueva (válvula same-line /* important: <razón> */, escaneo
comment-blanked) + las 15 declaraciones anotadas con su razón + canon
recipe-contract §3/§4.
- SOM-4 adjudicado: el censo/guard YA existían (49 pins); knob/mask-field/
timeline pinneados (overrides documentados en call-site); media-player
Batch-4 (35 hits, cero renderProps) = único batch restante, registrado.
- THM-4 doctrinado en eidos.md §unused (comportamiento/composición =
legítimo; deuda = eje visual sin consumidor; hotspots por lotes).
F4-C — corpus documental (decisiones de usuario aplicadas):
- DOC-3: los 15 enlaces muertos resueltos (repoint a la edición FINAL
trackeada / des-link históricos) · docs:check I6-links WARN→ERROR.
- DOC-1: tabla «Build contract» MIGRADA a component-guide con estados
modernizados (A3–A5 → LIVE + guards de hoy); banners reapuntados; citas
de CANON/sema.md historificadas; lápida-redirect en el §13 del fósil.
- DOC-4: hold chain → holds.ts · FAQ event:* SUPERSEDED por signatures ·
gradient añadido a los DOS capstones (sextet real) · nota de paleta de
demo-authoring corregida (universalPaletteDecls + decisión THM-2 =
mecanismo universal como sucesor del tracker borrado).
- DOC-5/6: recuentos anti-frágiles datados · §4.11 dup → §4.12 · Known gaps
historificado · N-6/N-7 recuperadas de git (d68d2c45^) y canonizadas en
eidos.md §pickers · authoring E2 → canon/tsc.md · air-old des-linkado ·
EID-3 (placement) en la fila RTL · AUX-2 disabledDom documentado.
SEM-4 sesión 1 — el close polimórfico de los pickers, VIVO (D.11):
- Reconciliación: los morfos ya no declaran close (delegated al Popover,
de-dialoged 06-27); el agujero real era el cierre programático bypaseando
dismissWith → save/cancel/select eran perceptualmente SILENCIOSOS.
- Fix: PickerShellHandle.setPopoverDismiss + closeWith(cause) en los 5
providers (14 sitios; select/commit → 'save' = commit.save+fulfill,
cancel → 'cancel' = emerge; fallback raw para headless) + UN inyector en
el eidos PickerShell root (norma N-8). Picker genérico fuera a propósito
(ya suena commit-set/cancel por diseño S9).
- Verificado en vivo (date-picker): Done → close·commit·fulfill·active ·
Cancel → close·emerge · cierre real.
Gates: matriz 141/141 (los 6 morfos nuevos de la pista de texto paralela
también PASS) · contracts 38/38 · eidos 314 · sema 178 · morfo 94 ·
docs:check 0/0 con I6 en error · baseline propio 57.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- continue-cleanroom: bloque de ARRANQUE para la próxima sesión (F2 en 6
pasos ordenados, barato→delicado, no-cascada) + registro de ejecución de
F1 (EID-1 anillo fundación→outline con :where() — el reset global que lo
justificaba NO existía y el anillo viejo pintaba en paralelo con los de
receta; EID-2 opacidades→tokens; F1.3 3 guards de fundación; SEM-1
prioridad=intent pinneada con liveRegionFixtureMorfo) + cola lateral
nueva: accordion outline:none+box-shadow = cero anillo en HCM (a F2).
- sema.md §Announce: doctrina AUX-1 "who owns what" — 1 sink
(uix.announce), 2 emisores (runtime a11y + AnnounceChannel), <Announce>
= región de app; UNA política de prioridad (SEM-1) pinneada en ambos lados.
Gates al cierre: matriz 135/0/0 · contracts 38/38 · eidos 309/309 ·
sema 178 · baseline 57.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clean-room fixes (2026-07-11, sobre los P1 de la auditoría):
- EID-1: el anillo de foco de la fundación migra a `outline` (§32) — el último
box-shadow del catálogo; :where()-wrapped para que las recetas siempre ganen;
doctrina actualizada en theming/reference + changelog.
- EID-2: opacidades literales de archetypes.css → var(--opacity-disabled/hover).
- SEM-1: política de live-region unificada — la urgencia va SOLO por intent
(threat/loss → assertive), runtime y AnnounceChannel ya coinciden.
- MOR-4: card-group con morfo propio (scope eidos) + guard de enumeración.
- THM-1: component-audit + recipe-css-contract escanean los *.css hermanos
(calendar-select, color-picker-spectrum, date-range-picker-time…); R-2.1
caza también hsl()/oklch(); violaciones de los secundarios corregidas.
- THM-3: canario de censo de toggle volteado (lint.test); commit-block promovido
a firma global block-shake; regen de generated/base.css.
Docs nuevos:
- docs/audit-new-10-july/audit-active-uix.md — auditoría clean-room 2026-07-10
del ecosistema (hallazgos P1–P3 con evidencia ruta:línea, matriz y gap analysis).
- docs/process/PLAN-scene-ambient-pack.md — plan por fases: motor arts/scene +
pack Ambient (45 animaciones de demos) + vía de promoción agéntica (Aura);
gate de decisiones D1–D9.
- docs/Disenando_lo_que_ocurre_FINAL.{docx,pdf} — edición FINAL del libro.
- README.md raíz (esqueleto de paquete).
Excluidos deliberadamente de este commit: words/palabras/chronos (pista
separada), web/routes/alpha (terminado, sin commitear por decisión), rt.css
(volcado de referencia Radix Themes).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- docs/audit/components/_cierre.md — the programme closure: final gates
(matrix 134/0/0, contracts 37/37, vocab 0, baseline 57), the full package
journey with hashes, the canonized method (dossier template, evidence-only
exceptions, no-cascada, machine valves), the findings that outlive the
programme, and what moved to new owners (demo frame, active tracks,
follow-ups).
- docs/process/continue-cleanroom-fixes-2026-07.md — the LIVE turnkey for
the next sessions: the clean-room severity table as the queue, the state
reconciliation (SOM-5 P1 already closed post-snapshot; SOM-3 partial), the
proposed P1 order (machine-extending THM-1/MOR-4 first), the WIDENED
verification protocol (134/0/0 and 37/37 must HOLD), exclusions and the
side queue.
- The old audit-fixes handoff is sealed as historical with a redirect header.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
color-swatch (the S7 passive exemplar gains its Baseline/Comparativa — the
primitive extracted in the ColorPicker redesign; React Aria is the only
headless ref shipping it) · onion-menu (nobody ships a headless radial menu;
Menu Button semantics + depth-tinted drill rings as the differentials; the
English "## Decisions" heading renamed to the canonical "## Decisiones") ·
radio-cards (the S11c delegation exemplar: reuses RadioGroup soma wholesale —
zero duplicated behaviour; multi-select variant DISCARDED, CardGroup+
ToggleGroup own cardinality per the 2026-06-27 decision) · scroll-frames
(+ the missing Passive justification: the frame is a pure function of scroll
progress — the gesture belongs to the page) · timeline (the two-axes
differential documented: data-status drives marker geometry, data-intent
drives valence — decoupled, unlike Ant/MUI/Flowbite; apg declared in C5
none-rationale form; the two 1em literals annotated — they inherit the
item-scaled font, the trf-separator precedent).
Machine: 129 -> **134 PASS / 0 NEEDS-WORK / 0 BROKEN** — the audit
programme runs the full catalogue green. contracts 37/37 · vocab exit 0 ·
type baseline 57.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
badge: the Remove hover joins the MD3 state layer (§38) — background-image
veil with var(--state-hover); the hand-rolled 15% currentColor mix predated
the rollout. Verified in the demo (CSSOM rule + live removable badges).
The other 8 were exceptions WITH READ EVIDENCE, not fixes — each README
documents where the treatment actually paints:
- alert-dialog / fab / split-button / qr-code: every interactive part
composes the canonical <Button> (Action/Cancel wrappers, the fab itself,
both split halves, the DownloadTrigger) — focus + disabled in button.css.
- date-picker: the eidos root overlays data-field and the trigger input is a
composed DateField.Input carrying data-field-control — disabled/readonly
paint via the shared field.css chrome (R-1.2 + R-1.3).
- date-range-field: LAYOUT-ONLY recipe; each endpoint is a real DateField
whose [data-field] gets field.css :focus-within — mirror of the trf twin.
- mask-field: IS-A Field (fieldRole provider/control/input) — the whole
control chrome incl. the focus ring lives in field.css (R-1.2/3/4/5).
- pin-input: the ring ALREADY paints on [data-pin-input-cell][data-active]
(canonical --focus-ring-* tokens) — the soma-written focused-cell flag,
a state-attr vehicle the R-1.5 heuristic does not recognise by name.
Matrix: 120 -> 129 PASS / 5 NEEDS-WORK / 0 BROKEN. Type baseline 57.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The convergence session's second half (with field commit-submit landed in
33f346ed): the three remaining contracts failures are gone and the full
catalogue-guards suite is green for the first time.
float-panel (A-3.7 + the runtime-discipline tail):
- Keyboard move/resize modes now sound through the SAME handle events as the
pointer gesture (the knob doctrine): entering the mode fires drag-start /
resize-start (the pickup cue), committing or cancelling fires drag-end /
resize-end (the release cue lands even on revert, like dragging back to
origin). The kb path had rich AT announcements but zero perceptual events.
- Every direct style write migrated to ActiveDom's per-element
`writeProperty` / `removeProperty` — a SYNC setProperty delegate, so the
deliberately same-task hot path (drag glued to the cursor, no re-render)
keeps its exact timing. The layout effect's empty-string resets became
removeProperty; comments updated where they cited `el.style.*` directly.
- The kb-readout debounce timer moved from `win.setTimeout` to the injected
`uix.timers.schedule` (announce house pattern: keyed + replace + meta).
component-audit A-3.7 refined to count DISTINCT mutating actions (Set) — the
rule's own stated semantics ("Enter and Space both map to the same action"):
float-panel's kb-move rides 13 keys but is ONE gesture; occurrence-counting
flagged complete wiring as under-declared. A-3.7 failures catalog-wide: 0.
media-player: the raw listeners in media-provider.ts are the pluggable
playback-engine PORT's deliberate design (header doctrine: Svelte-agnostic,
"no runes, no $adom" — third-party hls.js/embed engines implement the same
contract). The listeners guard gains the documented port exemption (the same
valve the timers guard already had for announce's global fallback).
Verified live in the float-panel demo (pointer + keyboard): drag follows the
cursor pixel-perfect through the new write path (24,24 -> +60,+40 -> 84,64),
release commits, drag-start stamps on both pointer and keyboard grabs, arrow
nudges snap to the device-pixel grid, Enter commits.
Gates: contracts 37/37 (first full green) · float-panel suite 8/8 · machine
120 PASS / 14 NEEDS-WORK / 0 BROKEN · vocab exit 0 · type baseline 57.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adoption, not design (audit ficha field F-2, refined against password-field):
the family doctrine is WRITTEN in the password-field morfo — per-keystroke
typing is plain data flow; Enter is the terminal gesture. textarea already
had commit-submit; the base Field.Input did not — the text-input pair was
asymmetric, and the machine flagged the shell as interactive-with-0-events
(A-3.1), converging with the clean-room audit finding "field infra-declarado".
- morfo: scope gains sema; expression family-default (the base shell speaks
with the family voice — the concrete fields carry the packs); apg textbox
(the password/textarea cite); commit-submit event (commit.submit, neutral,
post, target input) + Enter in the Input keyboard contract.
- soma FieldInputProvider: onkeydown — plain Enter (no modifiers), gated on
disabled/readonly, triggers commit-submit through the runtime.
Verified live in the field demo: Enter stamps data-event="commit-submit" /
family=commit / intent=neutral / phase=active on the input and the demo trace
logs the event. Machine: field -> PASS (A-3.1 + A-1.4 cleared). Field suite
3/3, vocab exit 0, type baseline 57.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The demos will be exposed through a NEW frame for the whole system, so drift
against the CURRENT page template is not fix-work. checkDemo results are
downgraded to warn at the call site and D-* rules are excluded from the
verdict count entirely — the data stays visible in the report, the component
matrix stops being painted by it. The D-* rules get rewritten against the new
frame when it lands.
Matrix: 102 -> 118 PASS / 16 NEEDS-WORK / 0 BROKEN. The 16 now decompose into
exactly three real families: the R-1.x focus/disabled census (9), the old
dossier-form READMEs (6, the reduced lote 6), and two contract items — field
A-3.1 and float-panel A-3.7 — which converge with the new clean-room audit
finding "field/float-panel infra-declarados".
Type baseline 57.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The "3 ajenos" census. What the 12 pre-existing failures really were: a few
genuine violations + several guards CRASHING on menu-dial's missing
exports.ts (ENOENT) and hiding their true violation lists. All addressed
except the two runtime-discipline files (see tail).
- knob: soma barrel export + the missing soma README (headless contract —
parts/ARIA/absolute angular keyboard/props/published CSS vars/sema table).
- menu-dial + onion-menu: joined SOMA_INTERNAL_PRIMITIVES — both are
documented provider-less bridges (keyboard dispatch + nav maths + emission;
the eidos root owns state and render). The scope guard now subtracts the
internal set from BOTH sides so a bridge may truthfully keep 'soma' in its
morfo scope without being a public namespace. Self-alias imports fixed;
the two morfo docblocks realigned to the implementation ("soma owns open"
was drift — the bridge files own dispatch/emission only; onion-menu's
stale "family-default, no pack" tail also corrected, S3b shipped its pack).
- Public barrels decoupled from provider implementation filenames (the
picker `internals.ts` house pattern) for the 6 offenders: calendar,
cropper, field-langs, gradient-builder, gradient-picker, image-adjustments.
- listSourceFiles now skips ACTIVE_DEV_TRACK paths (words/palabras/chronos)
— the track doctrine already said catalogue guards skip them; the
file-scanning guards just didn't.
- data-archetype added to the known morfo attrs (compiler-emitted from part
archetype declarations); the four field-overlay picker triggers
(color-picker, date-range-picker, time-picker, time-range-picker) declared
archetype 'trigger' while stamping 'field-trigger' at runtime — morfos
aligned to the date-picker/ntp precedent (contract now matches the DOM;
zero runtime change, the stamp already won).
- float-panel: the consumer-placed data-float-panel-no-drag opt-out marker
is now declared in the morfo (presence entry with the consumer-marker
note) — the NON_DRAG_SELECTOR contract stops being invisible.
Remaining tail (3 failures, deliberately deferred to a dedicated
runtime-discipline session with browser gesture verification):
float-panel-provider direct style writes + raw timer (drag/resize hot path
-> dom.apply/uix.timers migration) and media-player media-provider raw
listeners (-> dom.listen).
Gates: contracts 34/37 (was 25/37) · component-audit 102 PASS · vocab exit 0
· type baseline 57 · eidos-lint invalid 0 on the four touched pickers ·
compile + eidos contract tests 42/42.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- contracts.test: metrics joins SOMA_INTERNAL_PRIMITIVES (with picker-shell) —
its soma layer is a deliberate provider-less runtime bridge (documented
in-place: "no provider/state class"; morfo scope ['sema','eidos'] on
purpose), NOT a public component namespace. Classification fix, not an
exemption of debt: the barrel/exports/README guards stop mis-demanding a
canonical Provider shape it was designed not to have. Also fixes the bridge's
$soma self-alias import (the internals guard). Contracts: 13 -> 12 failures,
ZERO metrics mentions (the remaining 12 belong to knob/menu-dial/onion-menu).
- morfo: apg 'none — data display readout' (C5 form) — clears A-1.4; the
README's stale "A-1.4 N/A" audit note updated to point at the declaration.
- README upgraded to dossier form (Baseline Untitled-UI/Tremor/Chakra Stat,
Comparativa with the goodTrend decoupling as the differentiator, Decisiones
incl. the internal-bridge classification, Gaps with the D-1.2 demo union
routed to the cross-catalog demo census).
- Suite (the ficha's F-2): resolveDeltaIntent extracted to a pure helper
(delta-intent.ts, consumed by Metrics.Delta) + delta-intent.test.ts 4/4
(direction/valence decoupling, goodTrend flip, flat neutral, explicit
override) + metrics.svelte.test.ts (the live-update bridge: signal.notify
carries the prop-source intent; the morfo's requiresLiveRegion contract).
Gates: component-audit metrics clean except D-1.2 (demo census) · eidos-lint
invalid 0/class-hooks 0 · type baseline 57 · contracts 25 pass/12 pre-existing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The package's headline item — the generic Picker's transactional events —
turned out ALREADY PAID at checkpoint S3b (commit-set fulfill / commit-cancel
/ commit-reset declared, pack shipped, soma triggers wired, suite green): the
2026-07-07 ficha claim was stale and the ntp dossier had propagated it; the
dossier row is now corrected with the verification.
What this session actually adds:
- component-audit R-2.1 learns the `/* literal: <reason> */` escape valve
(same declarationWindow mechanism the R-4.x rules already use) — the tokens
doctrine's physically-fixed exception finally has its machine valve. Full
run confirms no other component silently passes (same 102/32).
- natural-time-picker.css: all 9 raw colors annotated line-by-line (5 skies +
knob ink + line/ticks/shadow — sky ARTWORK, not theme roles; identical in
light and dark). NOT tokenized, per the ficha's F-2 disposition. R-2.1
clears for ntp.
- soma/components/natural-time-picker/README.md: the headless contract — the
domain coordinator's state surface (minutes bridge, sliderValue, isDay,
moments, steppers, display) + the fully-delegated perceptual chain table
(TimeField / Slider / generic Picker / Popover).
- natural-time-picker-provider.svelte.test.ts: 12 tests green (band bridge
with wrap + seconds preservation, steppers incl. second non-rolling wrap,
moment jumps + exact-match chips, readonly lock, daylight window bounds,
12/24h display incl. the no-soma.dates fallback, granularity displayTime).
Gates: component-audit 102 PASS (ntp R-2.1 cleared) · type baseline 57 ·
new suite 12/12.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The initiative's real remaining scope (verified 2026-07-10 against the repo;
the "uncommitted work" memory was stale — builder landed in b3d0e290, picker
in f5eb8acb):
- contracts.test: remove gradient-builder/gradient-picker from
ACTIVE_DEV_TRACK. The catalogue guards found exactly ONE violation — the
missing soma barrel exports — now added (GradientBuilder, GradientPicker).
Post-graduation: same 13 pre-existing failures (knob/menu-dial/metrics/
onion-menu debris from other WIP), zero gradient mentions.
- apg declared on both morfos: builder cites slider (every stop + the angle
dial IS a slider thumb — the keyboard-a11y differentiator); picker cites
dialog-modal via the composed Popover (same rationale as date-picker/ntp).
- Both eidos READMEs upgraded to dossier form (Baseline / Comparativa /
Decisiones / Gaps) transplanting the CONTINUE.md competitive research
(OKLCH model shared with the token engine; keyboard-editable stops — the
field is mouse-only RGBA exporters). Stale "active dev track" recipe notes
corrected.
- gradient-builder demo: D-1.2 was a false negative — the tab union was the
correct v2 9-tab set, just formatted multi-line; joined to one line
(canary format). SSR smoke: 200 + 40 data-gradient-builder attrs.
Remaining on both: D-1.5/D-3.1/D-4.3 — the catalog-wide demo-census (fails
on 10/7 components INCLUDING the button canary), tracked in the dossiers'
Gaps, not gradient-specific.
Gates: component-audit 102 PASS · contracts 24 pass/13 pre-existing ·
vocab exit 0 · type baseline 57.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dialog-001 a11y-race fix (53b6f629) removed the literal role from dialog
Content on purpose — variant-dependent dialog/alertdialog, DialogContentProvider
is the sole authority — but the compile test kept asserting the static hoist on
that part, red on HEAD since then. Adjudicated: stale test, not a compiler
regression (mechanism verified intact via Title, which does declare a literal
role: heading).
- Re-point the hoist mechanism test at Title (heading).
- New guard: Content emits NO static role, locking dialog-001 against a
re-declared literal reintroducing the syncAttrs overwrite race.
Suite 35/35 (was 33+1 failed); type baseline 57.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Option (a) with riders: the ::before slop stands for bare markers (the
Material mdc-touch-target / Android touch-delegate / iOS hit-inset lineage).
Rider 1: dense coarse stacks must keep pitch >= --touch-target (WCAG excludes
overlapped area; bare boxes still hold AA via 2.5.8 Spacing worst-case).
Rider 2: the Field labeled-row task stays open as the ADDITIVE improvement —
the row becomes the real AAA target (2.5.5 Equivalent) and the slop remains a
harmless net. Chronicle updated in changelog §37; standing in reference §37;
handoff block resolved.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- natural-time-picker: expression 'delegated' (canon S11; composed children
own every event — clears A-3.1 truthfully; the Picker-generico event debt
stays tracked in its dossier Gaps for the S9 package).
- s-text-virtual-list: drop archetype 'item' from Row (0-event display
surface; item pulled cursor/user-select/hover + a height floor fighting
the canvas-computed row heights, and flipped the classifier to
interactive -> spurious R-1.5). Verified live: rows keep canvas heights,
no overlap, text selectable. Machine now classifies passive (F-1.5
justification already in the dossier).
- time-range-field / field-langs / link-preview: apg declared (spinbutton /
C5 'none — rationale' x2) — clears the three A-1.4 warns.
- button: soma README realigned to the real types (loading/intent/color —
the old pending/pressed/expanded/href surface no longer exists) + the two
stale docblocks from the audit ficha (types aria-label layer leak, wrapper
data-state mention).
- password-field: morfo StrengthMeter comment aligned with types (default
$libs/secs scoring, overridable) + index.ts example updated to the
post-S6 Control composition.
- Affected dossiers' Gaps tables updated (implemented rows removed).
Verified: component-audit 102 PASS (A-3.1/R-1.5-artifact/A-1.4 x3 cleared),
vocab guard exit 0, type baseline 57, eidos contract tests 7/7, stvl checked
in browser. Note: compile.test.ts 'hoists role into staticAttrs' (dialog)
fails on HEAD pre-existing — unrelated to this pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The S7 doctrine already landed in P0/P1 (guide §5 classes, machine classifier
via morfo evidence, F-1.5 marker rule, canonical exemplars cited). This closes
the two missing artifacts:
- color-swatch: re-anchor the existing "Why a primitive" rationale under the
canonical ## Passive justification heading (machine rule F-1.5) with the
formal classification paragraph. Verified against the machine: the F-1.5
failure is gone from the audit report (remaining F-1.1..1.4 warnings are the
grandfathered dossier — the S4 pass).
- spin-field: layer README formalizing the shared-layer contract per guide §5
(consumer-stamped selectors, sizing sourced from Field's resolved control
privates, stepper-only recipe vocabulary, the two compound-specificity box
overrides, foundation loading, consumer list). radio-cards needs no F-1.5
(machine classifies it interactive); its canonical citation lives in the
morfo header (verified).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both were type-only: the assertions read morfo-declared keys (data-editing,
role) that DO reach the provider props at runtime through the renderProps()
spread, but the static type of runtimePart.assert erases them. Read them
through an explicit indexed cast instead; suites stay green (6/6). Baseline
drops 59 -> 57 — protocol number updated in the handoff, with the remaining
out-of-mandate errors inventoried (9 src/: file-upload x4, navigation-menu,
arts/connection x4; ~48 web/ demos).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>