docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
---
|
|
|
|
|
|
title: Sema — the perceptual engine and channels
|
|
|
|
|
|
type: reference
|
|
|
|
|
|
audience: human + agent
|
|
|
|
|
|
authority: E1 architecture — the semantic domain, the emit contract, the resolution cascade and the channels
|
|
|
|
|
|
status: current
|
|
|
|
|
|
source: migrated from src/uix/sema/README.md (2026-07-02, docs-book F7.2)
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
# Sema
|
|
|
|
|
|
|
|
|
|
|
|
`Sema` defines UIX's canonical semantic domain and orchestrates the emission
|
|
|
|
|
|
of perceptual signals.
|
|
|
|
|
|
|
|
|
|
|
|
## What it is
|
|
|
|
|
|
|
|
|
|
|
|
- canonical families (8): `contact`, `commit`, `signal`, `handle`, `emerge`,
|
|
|
|
|
|
`shift`, `sustain`, `delegate`
|
|
|
|
|
|
- canonical intents: `neutral`, `affirm`, `fulfill`, `risk`, `threat`, `loss`
|
|
|
|
|
|
- a per-family intent policy (`SEMA_FAMILY_POLICY`) with **two axes**:
|
|
|
|
|
|
`intentRequirement` (`'required'` | `'optional'` | `'forbidden'`) — the
|
|
|
|
|
|
compile-time gate that shapes the discriminated union — and
|
|
|
|
|
|
`intentGuidance` (`'expected'` | `'contextual'` | `'discouraged'`) — a
|
|
|
|
|
|
doctrinal hint for lint/tooling
|
|
|
|
|
|
- normalization between the structured shape and the canonical label
|
|
|
|
|
|
- minimal domain validation
|
|
|
|
|
|
- `EngineSemantic` as the channel registry + occurrence dispatch
|
|
|
|
|
|
|
|
|
|
|
|
`Sema` does not decide which event happened. The provider decides.
|
|
|
|
|
|
`EngineSemantic` receives the occurrence and dispatches it to the registered
|
|
|
|
|
|
perceptual channels. Each channel materializes the signal in its modality
|
|
|
|
|
|
(DOM, audio, vibration).
|
|
|
|
|
|
|
|
|
|
|
|
## What it no longer is
|
|
|
|
|
|
|
|
|
|
|
|
`Sema` is no longer a monolithic multimodal runtime.
|
|
|
|
|
|
|
|
|
|
|
|
`EngineSemantic` does not contain:
|
|
|
|
|
|
|
|
|
|
|
|
- a global accessibility policy
|
|
|
|
|
|
- a cross-channel perceptual map
|
|
|
|
|
|
- decisions about which modal effect to apply
|
|
|
|
|
|
|
|
|
|
|
|
Those live in each channel separately:
|
|
|
|
|
|
|
|
|
|
|
|
- `EngineSemantic` keeps a channel registry and dispatches each signal
|
|
|
|
|
|
- the DOM projector materializes the signal as `data-event*` in the DOM
|
|
|
|
|
|
- `SoundChannel`, `HapticChannel` and future modal engines register as
|
|
|
|
|
|
independent channels that receive the signal and decide how to materialize
|
|
|
|
|
|
it on their plane
|
|
|
|
|
|
|
|
|
|
|
|
### Channel registry — open
|
|
|
|
|
|
|
|
|
|
|
|
The channel set is **NOT closed**. The framework ships canonical signatures
|
|
|
|
|
|
for `sound` and `haptic`. The `visual` channel exists as the projection/hold
|
|
|
|
|
|
meta-channel but has no slice of its own in `EffectiveSignature`. Apps can add
|
|
|
|
|
|
channels with a signature via declaration merging:
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
// app bootstrap
|
|
|
|
|
|
declare module '$uix/sema' {
|
|
|
|
|
|
interface SemaChannelSignatures {
|
|
|
|
|
|
a11y: A11ySignature; // narrator / live-region
|
|
|
|
|
|
voice: VoiceSignature; // text-to-speech
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Only the visual channel is mandatory (with the `visual: false` escape).
|
|
|
|
|
|
Sound and haptic are opt-in. Any new channel registers its `Channel` and
|
|
|
|
|
|
receives the dispatch.
|
|
|
|
|
|
|
|
|
|
|
|
## The `emit` contract
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
docs(sema): la doctrina deja de mentir — deriva propia, copias podridas y dos leyes muertas
Pasada de saneamiento documental tras los tres commits de sonido, con el
informe de AUDIT-sema-2026-08-05 como mapa. Tres clases de defecto.
1) DERIVA QUE YO MISMO DEJE (lo mas urgente)
El 05 renombre las claves silenciadoras a `commit.silent` / `emerge.silent` y
el 06 las elimine del catalogo — dejando media docena de docs citando claves
que ya no existen, y afirmando ademas comportamientos que ya no ocurren:
- switch / toggle / toggle-group README: decian «silent-by-default
(`commit.silent`)». Hoy es `commit.medium` (gain 0.1) y suenan. Corregidos
con el nivel real y su razon (un tercio de una pulsacion de boton).
- tooltip README + docblock del pack: decian que el tuning «resta el gain de
la familia, asi que neutral emite a 0» y que «threat / fulfill siguen
aflorando». Ambas cosas son falsas desde el 06: es `SILENT`, el resolver
retira el canal y NADA aflora, porque no queda ganancia que subir.
- toggle-group apuntaba a `LIBRO_VARIACIONES_Y_EXTENSIONES.md`, que es un stub
movido; ahora apunta a book-deviations.
- La nota del renombrado en D.5 decia «hoy es `commit.silent`»: una clave que
vivio UN DIA. Marcada como tal, con la lista de las que siguen vivas.
2) COPIAS PODRIDAS — la ley del corpus es enlazar, no copiar, y estas dos
entradas la incumplian
- D.9 transcribia `SEMA_HOLDS_BY_INTENT` entera y se habia quedado atras: D.12
corrigio DOS valores el 2026-07-06 (`commit.fulfill` noticed→settled,
`signal.loss` noticed→brief, ambos contra el texto del libro) y la copia
siguio afirmando los viejos un mes. Sustituida por el puntero a holds.ts +
el enumerado generado, con la leccion escrita en el sitio.
- sema.md transcribia `SEMA_VERBS` y le faltaban DOS verbos vivos:
`commit.unselect` y `handle.zoom`. Retirada; queda el puntero a verbs.ts y a
vocabularies.md, que si se genera y tiene guard de frescura.
3) LEYES QUE LA PRACTICA YA HABIA DEROGADO, Y NADIE REGISTRO
- El contrato `emit` publicaba `Promise<void>`; devuelve `Promise<string>`
desde D.9. Corregido, y explicado que ese string es el id de la ocurrencia —
el unico asidero para cerrar una senal persistente con `clear`.
- channels.md fijaba «3 canales runtime» y D.8 cerraba la puerta a Announce
(«hoy no»). El `AnnounceChannel` existe desde el 2026-07-04: built-in,
opt-in y exportado. channels.md pasa a 4 con la distincion que importa
(visual/sound/haptic EXPRESAN; announce SUSTITUYE) y D.8 queda marcada
PARCIALMENTE SUPERSEDED.
- sema.md prescribia `{ announce: uix.announce }` — y eso NO COMPILA: las dos
firmas no casan (bolsa de opciones vs posicional). Ahora ensena el adaptador
de una linea que si compila, y declara que ninguna raiz cablea el canal hoy,
asi que activarlo cae en el fallback que anade un SEGUNDO par de live
regions. El arreglo de codigo queda sin tomar: es decision de diseno.
- La cabecera de engine-sound.ts y la fila de arts/README seguian afirmando
como MECANISMO que «`prefs.sound` mapea al bus ui», que la auditoria AU-4 ya
habia corregido en el README del propio arte: lo garantizado por
construccion es el NEGATIVO (ninguna politica de UI escribe el bus content).
AMBIGUEDADES QUE NO RESUELVO PORQUE SON TUYAS, pero que dejan de estar
escondidas: D.7 prohibe canonizar samples fuera de `signal` y
`proof-of-human` los usa en dos eventos `commit`, aplastando la modulacion por
intent que esa misma entrada existe para proteger —y el comentario del pack
afirma literalmente lo contrario de lo que hace—; y D.8 declara que los packs
deben respetar el `activeChannels` de la familia mientras sema.md prescribe lo
contrario y el pack de dialog deja dos reglas inertes. Ambas quedan marcadas
con su estado real y los dos caminos excluyentes, pendientes de tu firma.
VERIFICADO: docs:check 0/616 · sonido + sema 244/244 · cero referencias vivas a
las tres claves muertas (las que quedan en book-deviations son historia
declarada como tal, y las de cronica no se reescriben) · prettier: los 6 docs
con avisos ya estaban sucios en HEAD, no los toco.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
semantic.emit(signal: SemanticSignal): Promise<string>
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
```
|
|
|
|
|
|
|
docs(sema): la doctrina deja de mentir — deriva propia, copias podridas y dos leyes muertas
Pasada de saneamiento documental tras los tres commits de sonido, con el
informe de AUDIT-sema-2026-08-05 como mapa. Tres clases de defecto.
1) DERIVA QUE YO MISMO DEJE (lo mas urgente)
El 05 renombre las claves silenciadoras a `commit.silent` / `emerge.silent` y
el 06 las elimine del catalogo — dejando media docena de docs citando claves
que ya no existen, y afirmando ademas comportamientos que ya no ocurren:
- switch / toggle / toggle-group README: decian «silent-by-default
(`commit.silent`)». Hoy es `commit.medium` (gain 0.1) y suenan. Corregidos
con el nivel real y su razon (un tercio de una pulsacion de boton).
- tooltip README + docblock del pack: decian que el tuning «resta el gain de
la familia, asi que neutral emite a 0» y que «threat / fulfill siguen
aflorando». Ambas cosas son falsas desde el 06: es `SILENT`, el resolver
retira el canal y NADA aflora, porque no queda ganancia que subir.
- toggle-group apuntaba a `LIBRO_VARIACIONES_Y_EXTENSIONES.md`, que es un stub
movido; ahora apunta a book-deviations.
- La nota del renombrado en D.5 decia «hoy es `commit.silent`»: una clave que
vivio UN DIA. Marcada como tal, con la lista de las que siguen vivas.
2) COPIAS PODRIDAS — la ley del corpus es enlazar, no copiar, y estas dos
entradas la incumplian
- D.9 transcribia `SEMA_HOLDS_BY_INTENT` entera y se habia quedado atras: D.12
corrigio DOS valores el 2026-07-06 (`commit.fulfill` noticed→settled,
`signal.loss` noticed→brief, ambos contra el texto del libro) y la copia
siguio afirmando los viejos un mes. Sustituida por el puntero a holds.ts +
el enumerado generado, con la leccion escrita en el sitio.
- sema.md transcribia `SEMA_VERBS` y le faltaban DOS verbos vivos:
`commit.unselect` y `handle.zoom`. Retirada; queda el puntero a verbs.ts y a
vocabularies.md, que si se genera y tiene guard de frescura.
3) LEYES QUE LA PRACTICA YA HABIA DEROGADO, Y NADIE REGISTRO
- El contrato `emit` publicaba `Promise<void>`; devuelve `Promise<string>`
desde D.9. Corregido, y explicado que ese string es el id de la ocurrencia —
el unico asidero para cerrar una senal persistente con `clear`.
- channels.md fijaba «3 canales runtime» y D.8 cerraba la puerta a Announce
(«hoy no»). El `AnnounceChannel` existe desde el 2026-07-04: built-in,
opt-in y exportado. channels.md pasa a 4 con la distincion que importa
(visual/sound/haptic EXPRESAN; announce SUSTITUYE) y D.8 queda marcada
PARCIALMENTE SUPERSEDED.
- sema.md prescribia `{ announce: uix.announce }` — y eso NO COMPILA: las dos
firmas no casan (bolsa de opciones vs posicional). Ahora ensena el adaptador
de una linea que si compila, y declara que ninguna raiz cablea el canal hoy,
asi que activarlo cae en el fallback que anade un SEGUNDO par de live
regions. El arreglo de codigo queda sin tomar: es decision de diseno.
- La cabecera de engine-sound.ts y la fila de arts/README seguian afirmando
como MECANISMO que «`prefs.sound` mapea al bus ui», que la auditoria AU-4 ya
habia corregido en el README del propio arte: lo garantizado por
construccion es el NEGATIVO (ninguna politica de UI escribe el bus content).
AMBIGUEDADES QUE NO RESUELVO PORQUE SON TUYAS, pero que dejan de estar
escondidas: D.7 prohibe canonizar samples fuera de `signal` y
`proof-of-human` los usa en dos eventos `commit`, aplastando la modulacion por
intent que esa misma entrada existe para proteger —y el comentario del pack
afirma literalmente lo contrario de lo que hace—; y D.8 declara que los packs
deben respetar el `activeChannels` de la familia mientras sema.md prescribe lo
contrario y el pack de dialog deja dos reglas inertes. Ambas quedan marcadas
con su estado real y los dos caminos excluyentes, pendientes de tu firma.
VERIFICADO: docs:check 0/616 · sonido + sema 244/244 · cero referencias vivas a
las tres claves muertas (las que quedan en book-deviations son historia
declarada como tal, y las de cronica no se reescriben) · prettier: los 6 docs
con avisos ya estaban sucios en HEAD, no los toco.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
The resolved value is the **occurrence id**. Transient signals can ignore it;
|
|
|
|
|
|
a non-transient one (`untilFix` / `untilAction` / `stateBound`, see
|
|
|
|
|
|
[persistence](#persistence)) must be held so the caller can end it with
|
|
|
|
|
|
`clear(id)` or `clearTarget(el)` — there is no other handle on it.
|
|
|
|
|
|
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
One signature. It covers the three scenarios when composed with `dom.apply`:
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
// Structural change without a signal
|
|
|
|
|
|
dom.apply(change);
|
|
|
|
|
|
|
|
|
|
|
|
// Structural change with a signal
|
|
|
|
|
|
await semantic.emit(signal);
|
|
|
|
|
|
dom.apply(change);
|
|
|
|
|
|
|
|
|
|
|
|
// Signal without structural change
|
|
|
|
|
|
void semantic.emit(signal);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Promise semantics — sequential strict
|
|
|
|
|
|
|
|
|
|
|
|
`emit(signal)` resolves when the `VisualChannel` has completed its whole
|
|
|
|
|
|
materialization:
|
|
|
|
|
|
|
|
|
|
|
|
1. `VisualChannel.prepare()` projected `data-event*` onto the DOM
|
|
|
|
|
|
2. the attributes lived in the DOM for the configured `hold`
|
|
|
|
|
|
3. the attributes were already removed (cleanup complete)
|
|
|
|
|
|
4. the Promise resolves
|
|
|
|
|
|
|
|
|
|
|
|
This is **sequential strict**: the caller applies the structural commit
|
|
|
|
|
|
AFTER the perceptual signal has finished. There is no parallelism between the
|
|
|
|
|
|
event and the state change.
|
|
|
|
|
|
|
|
|
|
|
|
Non-visual channels (sound, haptic) are fire-and-forget: they start in
|
|
|
|
|
|
parallel with the visual one but do not affect the Promise's timing.
|
|
|
|
|
|
|
|
|
|
|
|
### `emit`'s internal lifecycle
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
1. The engine generates the occurrence's id/session
|
|
|
|
|
|
2. The engine runs `channel.prepare(...)` on the registered channels
|
|
|
|
|
|
- `VisualChannel.prepare()` projects `data-event*` for the cascade
|
|
|
|
|
|
3. The engine resolves the cascade and dispatches the signal to ALL registered channels
|
|
|
|
|
|
- non-visual channels (sound, haptic) → fire-and-forget (not awaited)
|
|
|
|
|
|
- the visual channel → awaited
|
|
|
|
|
|
4. The engine resolves the Promise when the visual channel has finished
|
|
|
|
|
|
(strict sequential semantics: cleanup BEFORE the resolve)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Channels as modules
|
|
|
|
|
|
|
|
|
|
|
|
Sema is organized in symmetric perceptual channels:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
src/uix/sema/
|
|
|
|
|
|
├── engine.ts registry + channel prepare/dispatch + cascade composition
|
|
|
|
|
|
├── resolver.ts resolveSignature(signal, opts): EffectiveSignature
|
|
|
|
|
|
├── stamp.ts stampEventAttrs / unstampEventAttrs (data-event-*)
|
|
|
|
|
|
├── channels.ts channel ids, signatures and override types
|
|
|
|
|
|
├── sounds.ts nominal sound repository + dynamic recipes
|
|
|
|
|
|
├── sema-map.ts SEMA_MAP data + per-component Sema packs
|
|
|
|
|
|
├── components/ per-component perceptual packs (CSEM)
|
|
|
|
|
|
│ ├── dialog.ts dialogSema — cascade rules + preloadSamples
|
|
|
|
|
|
│ ├── toast.ts (future)
|
|
|
|
|
|
│ └── …
|
|
|
|
|
|
└── chans/
|
|
|
|
|
|
├── types.ts Channel interface — handle(signal, effective)
|
|
|
|
|
|
├── visual.ts VisualChannel (data-event projection + hold)
|
refactor(sound): extraer el motor Web Audio de sema al art `$sound`
`sema/chans/sound.ts` tenía 407 líneas de las que ~255 (≈63%) eran maquinaria
Web Audio —ciclo de vida del AudioContext, síntesis, samples, desbloqueo por
gesto— mezclada con doctrina perceptiva. Deuda arrastrada, con tres síntomas
medidos: el import era estático, así que toda app con sema metía el
sintetizador en el bundle aunque el sonido estuviera apagado (que es el
default); faltaba ciudadanía que `$scene` ya resuelve; y la costura de
inyección (`audioContextFactory`) llevaba ahí sin usar desde el principio.
Mismo movimiento que `$motion` hizo desde eidos: el art se lleva el RUNTIME, la
capa conserva sus DATOS y su doctrina.
- `$sound` / `EngineSound`: UN AudioContext por documento (los navegadores los
limitan y el gesto de desbloqueo es por contexto), síntesis de earcon,
samples con caché y fallback a síntesis, `autoSuspend` OPT-IN —suspender con
la pestaña oculta es correcto para earcons y erróneo para contenido, así que
es decisión de quien compone— y aviso cuando un segundo contexto va vivo.
Puertos `SoundDom` / `SoundTimers` inyectados; no importa ningún otro art ni
nada de `$uix/sema`, que es la prueba objetiva del corte.
- `SoundChannel`: 407 → 136 líneas. Solo doctrina: el gate de `prepare`, la
política de reducción y el reparto «el canal resuelve el NIVEL, el motor
aplica la ganancia». Sema no gana ni un import: recibe el motor por puerto.
- `uix.sound` en standalone y attach con `ownsSound` (idioma ya shipped:
`ownsMotion` / `ownsScene`), fila `sound` en la tabla ejecutable
`contracts.ts`, y `defineEngineSound()` para el camino de app.
- Tests nuevos: `engine-sound.test.ts` (11), `sound-port.test.ts` (guard de
deriva de tipos + la regla de propiedad) y `sound-e2e.test.ts`, que recorre
`emit -> cascada -> canal -> art -> grafo real`: el camino que las 16 suites
previas no cubrían porque paraban en canales falsos.
Sin `diagnostics.ts` ni `errors.ts`, y es decisión: espejo de `$scene`, aquí
todo fallo es degradación documentada, no error de programador.
Verificación: 17 suites / 198 tests · `check` en la baseline exacta (73
errores, 0 propios) · `sound.test.ts` verde SIN tocar un solo assert, que era
el criterio de que el movimiento fue value-preserving.
Planes: `PLAN-sound-engine.md` (completo, con el registro de la revisión
adversarial E-1..E-7), `PLAN-audio-player.md` (aparcado tras el análisis del
reproductor, con sus correcciones en cabecera) y `CONTINUE-sound-engine.md`
(handoff).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
├── sound.ts SoundChannel (gate + reduction policy; the Web Audio
|
|
|
|
|
|
│ runtime lives in the `$sound` art, injected)
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
└── haptic.ts HapticChannel (Vibration API + categorical kinds)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The engine does not mutate DOM attributes directly: it runs the generic
|
|
|
|
|
|
`channel.prepare(...)` hook. In the visual channel that hook delegates the
|
|
|
|
|
|
projection to a `SignalProjector`. When `ActiveUix` builds it, that projector
|
|
|
|
|
|
writes through UIX's `ActiveDom`. The engine resolves each signal into an
|
|
|
|
|
|
`EffectiveSignature` with `hold`, `sound`, `haptic` and future typed
|
|
|
|
|
|
channels, and dispatches `(signal, effective)` to each channel. Each channel
|
|
|
|
|
|
reads its slice (`effective.sound` for audio, `effective.haptic` for
|
|
|
|
|
|
vibration, etc.) or ignores the signature if it doesn't use it. Only the
|
|
|
|
|
|
visual channel blocks the caller with the perceptual hold; the rest are
|
|
|
|
|
|
fire-and-forget.
|
|
|
|
|
|
|
|
|
|
|
|
### Resolver and sema-map — the resolution cascade
|
|
|
|
|
|
|
|
|
|
|
|
On every `emit`, the engine:
|
|
|
|
|
|
|
|
|
|
|
|
1. Runs the channels' `prepare` hooks. The `VisualChannel` projects the
|
|
|
|
|
|
semantic tokens `data-event`, `data-event-family`, `data-event-intent`,
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`data-event-direction`, `data-event-phase`, `data-event-id` onto
|
|
|
|
|
|
`signal.target`. These are the tokens the cascade and eidos's CSS read.
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
2. Calls `resolveSignature(signal, opts)`, which applies the cascade
|
|
|
|
|
|
(canonical numbering **1 · 2 · 3 · 4 · 5a · 5b** — the same in
|
|
|
|
|
|
`engine.ts`, `resolver.ts` and CLAUDE.md; each layer overrides the
|
|
|
|
|
|
previous):
|
|
|
|
|
|
|
|
|
|
|
|
```
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
THE SOUND — two lookups, and nothing modulates:
|
|
|
|
|
|
|
|
|
|
|
|
nombre = per-emit ?? cascada ?? pack ?? morfo ?? familia[verbo] ?? familia.default
|
|
|
|
|
|
sonido = pack[`${nombre}.${intent}`] ?? pack[nombre] ?? nada
|
|
|
|
|
|
|
|
|
|
|
|
EVERYTHING ELSE — a CSS-like cascade, each layer over the previous:
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
1. FAMILY base — SEMA_MAP.families[f].base (haptic + activeChannels + hold)
|
|
|
|
|
|
2. INTENT deltas — SEMA_MAP.intents[i].deltas; HAPTIC ONLY since 2026-08-06
|
|
|
|
|
|
3. MORFO overrides — signal.overrides + signal.channels (minus `sound`)
|
|
|
|
|
|
4. RUNTIME overrides — engineOpts.overrides.runtime, baked into the map
|
|
|
|
|
|
5a. PACK cascade — engineOpts.components (minus their `sound`)
|
|
|
|
|
|
5b. APP cascade — engineOpts.overrides.cascade
|
|
|
|
|
|
```
|
docs(sema,theming): el orden real, como se autora cada canal, y el hueco del theming
Tres cosas que el cambio del sonido dejo sin plasmar.
1. EL ORDEN CANONICO MENTIA. La numeracion 1·2·3·4·5a·5b esta citada como
canonica en sema.md, resolver.ts y engine.ts, y despues del reorden era
falsa para `sound`: un pack ya no autora en 5a, lo hace en 1.5. Corregido
en los tres sitios a la vez, con el porque — todo lo que AUTORA un sonido
corre ahi conservando su precedencia relativa; solo cambio su posicion
respecto al intent. El resto de la regla (channels/haptic/hold) mantiene
el «gana el ultimo» porque no son ejes evaluativos.
2. COMO SE AUTORA CADA CANAL (CANON §7). El reparto por dueño estaba
escrito; lo que un componente ESCRIBE, no. Tabla nueva: el canal visual
no se escribe (se declara el evento y eidos reacciona), `sound` es UN
NOMBRE, `haptic` es un `kind`. La regla es la misma en las tres filas y
ese es el punto: un componente dice QUE ocurre, nunca cuan fuerte, cuan
brillante ni cuanto dura. El sonido era la excepcion hasta ayer.
3. EL ANALISIS DEL THEMING que el autor pidio (theming/channels.md §5b).
Lo que el cambio NO toco: nada de eidos. El canal visual se proyecta
estampando data-event-*, y esa ruta quedo intacta — ni una receta, ni un
token, ni un selector. Eidos no sabe que existe el sonido y no le hizo
falta. Lo que cambio fue DONDE se autora (un catalogo en vez de 71
ficheros) y CUANDO se aplica (antes del intent), ambos dentro de sema.
Lo que si cambio, y es lo util: `applyTheme(seed)` retunea SEIS ejes
visuales (color·type·depth·shape·space·gradient) y el sonido tiene CERO.
Antes esa asimetria se justificaba sola — con 214 reglas autorando 33
firmas a mano no habia objeto que retunear. Hoy hay exactamente uno:
16 nombres en un const. Un eje `sound` en ThemeSeed seria la misma forma
que los otros seis.
Y las tres puertas de personalizacion, medidas, ninguna llega al
catalogo: `overrides.runtime` recorre rutas de SEMA_MAP y el catalogo no
esta en el mapa (ademas se traga las erratas, S-09); `overrides.cascade`
es por selector, no un tema; `masterGain` se descarta en SILENCIO
(S-05/S-32). Un producto puede silenciar y puede pisar una ocurrencia,
pero NO puede re-voceear el sistema. Queda escrito en vez de ser
folclore.
⚠️ chronos: `src/uix/sema/components/chronos.ts` entro en la migracion de
`769e426c5` pese a ser de escritura excluida. Era forzoso — con el tipo
estrechado, dejarlo sin migrar rompe la compilacion del arbol entero — y
el cambio es mecanico (soundTuning(...) -> nombre), sin decision de diseño.
Su SPEC.md NO se ha tocado y sigue citando `soundTuning('commit.soft')`.
VERIFICADO: sema+morfo+sound 437/437 · check 75 · docs:check 0/618.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
**The sound does not participate in that cascade, and that is the design.**
|
|
|
|
|
|
An intent SELECTS a whole sound; it never bends one. A pack NAMES a sound; it
|
|
|
|
|
|
never authors one. There is nothing to override because there are no
|
|
|
|
|
|
parameters to override — a rule carries a name, and a name replaces a name.
|
|
|
|
|
|
|
|
|
|
|
|
What that removed, and why it is worth knowing before you go looking for the
|
|
|
|
|
|
machinery that used to be here: sound used to be resolved through all six
|
|
|
|
|
|
layers, with intent deltas adding to a family base signature and pack rules
|
|
|
|
|
|
replacing primitives afterwards. Measured across the 71 packs, that produced
|
|
|
|
|
|
214 rules authoring 33 distinct signatures, of which five were the same 700 Hz
|
|
|
|
|
|
note at five volumes and the «direction» variants differed by 20 Hz. The theory
|
|
|
|
|
|
was expressive; the output was mush. It also generated a whole class of defect
|
|
|
|
|
|
(D.7, the S-07 finding, three guards) whose only job was to police arithmetic
|
|
|
|
|
|
that should never have been in a component.
|
|
|
|
|
|
|
|
|
|
|
|
**Precedence among the things that NAME.** Most specific wins: a name passed at
|
|
|
|
|
|
trigger-time beats the app cascade, which beats a pack rule, which beats the
|
|
|
|
|
|
morfo event, which beats the family's verb table. This INVERTED the old order,
|
|
|
|
|
|
in which the cascade beat the per-emit override — whoever fires the occurrence
|
|
|
|
|
|
knows it best.
|
|
|
|
|
|
|
|
|
|
|
|
**The verb tier is what empties the packs.** `SEMA_MAP.families[f].sounds` is
|
|
|
|
|
|
keyed by the event's canonical VERB, with `default` as the fallback cell, so
|
|
|
|
|
|
`emerge` + `close` finds `close` without one line in any overlay's pack. The
|
|
|
|
|
|
verb travels in the signal for exactly this reason (it used to be computed and
|
|
|
|
|
|
discarded — audit S-40). A pack only speaks when it DIFFERS from the default:
|
|
|
|
|
|
the framework's 71 packs carry 30 sound rules between them.
|
docs(sema,theming): el orden real, como se autora cada canal, y el hueco del theming
Tres cosas que el cambio del sonido dejo sin plasmar.
1. EL ORDEN CANONICO MENTIA. La numeracion 1·2·3·4·5a·5b esta citada como
canonica en sema.md, resolver.ts y engine.ts, y despues del reorden era
falsa para `sound`: un pack ya no autora en 5a, lo hace en 1.5. Corregido
en los tres sitios a la vez, con el porque — todo lo que AUTORA un sonido
corre ahi conservando su precedencia relativa; solo cambio su posicion
respecto al intent. El resto de la regla (channels/haptic/hold) mantiene
el «gana el ultimo» porque no son ejes evaluativos.
2. COMO SE AUTORA CADA CANAL (CANON §7). El reparto por dueño estaba
escrito; lo que un componente ESCRIBE, no. Tabla nueva: el canal visual
no se escribe (se declara el evento y eidos reacciona), `sound` es UN
NOMBRE, `haptic` es un `kind`. La regla es la misma en las tres filas y
ese es el punto: un componente dice QUE ocurre, nunca cuan fuerte, cuan
brillante ni cuanto dura. El sonido era la excepcion hasta ayer.
3. EL ANALISIS DEL THEMING que el autor pidio (theming/channels.md §5b).
Lo que el cambio NO toco: nada de eidos. El canal visual se proyecta
estampando data-event-*, y esa ruta quedo intacta — ni una receta, ni un
token, ni un selector. Eidos no sabe que existe el sonido y no le hizo
falta. Lo que cambio fue DONDE se autora (un catalogo en vez de 71
ficheros) y CUANDO se aplica (antes del intent), ambos dentro de sema.
Lo que si cambio, y es lo util: `applyTheme(seed)` retunea SEIS ejes
visuales (color·type·depth·shape·space·gradient) y el sonido tiene CERO.
Antes esa asimetria se justificaba sola — con 214 reglas autorando 33
firmas a mano no habia objeto que retunear. Hoy hay exactamente uno:
16 nombres en un const. Un eje `sound` en ThemeSeed seria la misma forma
que los otros seis.
Y las tres puertas de personalizacion, medidas, ninguna llega al
catalogo: `overrides.runtime` recorre rutas de SEMA_MAP y el catalogo no
esta en el mapa (ademas se traga las erratas, S-09); `overrides.cascade`
es por selector, no un tema; `masterGain` se descarta en SILENCIO
(S-05/S-32). Un producto puede silenciar y puede pisar una ocurrencia,
pero NO puede re-voceear el sistema. Queda escrito en vez de ser
folclore.
⚠️ chronos: `src/uix/sema/components/chronos.ts` entro en la migracion de
`769e426c5` pese a ser de escritura excluida. Era forzoso — con el tipo
estrechado, dejarlo sin migrar rompe la compilacion del arbol entero — y
el cambio es mecanico (soundTuning(...) -> nombre), sin decision de diseño.
Su SPEC.md NO se ha tocado y sigue citando `soundTuning('commit.soft')`.
VERIFICADO: sema+morfo+sound 437/437 · check 75 · docs:check 0/618.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
3. Dispatches to each channel with the resolved signature.
|
|
|
|
|
|
4. Awaits the VisualChannel (which contributes the hold).
|
|
|
|
|
|
5. Runs the cleanup of the handles returned by `prepare`.
|
|
|
|
|
|
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
**Overrides vs deltas convention — numbers.** Applies to the HAPTIC channel
|
|
|
|
|
|
and to `hold`; the sound channel has no numbers to converge on any more.
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
- **Layer 2 (intent.deltas)**: `intensity: 0.2` adds to the base. Modifiers.
|
|
|
|
|
|
- **Layers 3, 4, 5a/5b (overrides)**: `intensity: 0.7` sets. Like CSS.
|
|
|
|
|
|
- To add explicitly from an override layer: `{ op: 'add', value: 0.1 }`.
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
- To multiply: `{ op: 'multiply', factor: 1.2 }`.
|
|
|
|
|
|
- To replace non-numeric primitives: `{ op: 'replace', value: ... }`.
|
|
|
|
|
|
|
|
|
|
|
|
If `signal.family` is missing or not in the map, it returns an empty
|
|
|
|
|
|
`EffectiveSignature` — the channels no-op.
|
|
|
|
|
|
|
|
|
|
|
|
### Semantic tokens — `data-event-*`
|
|
|
|
|
|
|
|
|
|
|
|
`VisualChannel.prepare()` projects the following attrs onto `signal.target`
|
|
|
|
|
|
BEFORE the cascade resolves. Rules with selectors over these attrs match
|
|
|
|
|
|
natively via `target.matches()` / `target.closest()`:
|
|
|
|
|
|
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
| Attr | Value | Origin |
|
|
|
|
|
|
| ---------------------- | -------------------- | --------------------------------- |
|
|
|
|
|
|
| `data-event` | `'signal-alert-close-fail'` | `signal.name` |
|
|
|
|
|
|
| `data-event-family` | `'signal'` | `signal.family` |
|
|
|
|
|
|
| `data-event-intent` | `'threat'` | `signal.intent` (when present) |
|
|
|
|
|
|
| `data-event-direction` | `'forward'` | `signal.direction` (when present) |
|
|
|
|
|
|
| `data-event-phase` | `'active'` | while the hold lasts |
|
|
|
|
|
|
| `data-event-id` | `'sig-42'` | occurrence id |
|
|
|
|
|
|
|
|
|
|
|
|
`data-event-direction` (`forward` / `backward`, `SemaDirection`) is the SENSE of
|
|
|
|
|
|
a traversal, decided per emit: the event name already separates
|
|
|
|
|
|
`shift-enter-mode` from `shift-exit-mode`, but one `shift-navigate` goes to the
|
|
|
|
|
|
previous month and the next one to the following month under the same name. It
|
|
|
|
|
|
is a sense, never an axis — eidos maps it onto the inline axis so `:dir(rtl)`
|
|
|
|
|
|
flips it. A route with no clear sense (a month picked from a select) stamps
|
|
|
|
|
|
nothing.
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
Those tokens are the **cross-channel contact surface**: sema's cascade
|
|
|
|
|
|
(`sound`, `haptic` and future channels) reads them with CSS selectors, the
|
|
|
|
|
|
same way eidos's CSS reads them to tint borders / animate states during the
|
|
|
|
|
|
hold. One perceptual surface, separate owners.
|
|
|
|
|
|
|
fix(sema,morfo,soma): una superficie no admite dos ocurrencias, y el nombre ya no miente
`data-event-*` es UNA RANURA por elemento. Tres auditorias independientes
encontraron el mismo defecto y ninguna lo cerro: fable S1 (2026-07-01, con el
README diciendo «findings executed»), sema S-17 (2026-08-05, midio el estampado
del knob muriendo a los 24ms de un hold de 240) y blocks A-36/A-65 (reproducido
en navegador, dos estampados a 1,1ms). Lo que faltaba no era diagnostico: nadie
podia distinguir una redireccion legitima de una deriva, porque la opcion que
redirigia se llamaba `fallbackTarget` y hacia lo contrario de lo que decia.
EL NOMBRE PRIMERO. `fallbackTarget` -> `targetOverride` (202 apariciones, 64
ficheros, dirigido con `git ls-files`). Siempre GANO sobre el ref registrado; el
nombre honesto es la precondicion para auditarlo. Las cronicas conservan el viejo
por diseño.
LA PROPIEDAD. `unstampEventAttrs` recibia el signal y lo DESCARTABA, asi que la
ocurrencia que terminaba antes borraba a la que tenia la ranura. Ahora comprueba
`data-event-id`. Con eso, `replace` deja de ser el comportamiento roto y pasa a
ser el suelo correcto.
A-36, SIN `regime`. Los cuatro overlays cedian el estampado del `open` al
trigger por un workaround de la era `sequence: 'pre'`; con `post` el content ya
esta montado. Retirado el override (float-panel migrado `pre`->`post`, ultimo
fuera de la doctrina que sema.md escribe). Medido en /blocks/site-header/preview
a 375px: contact-activate en el TRIGGER +18,7ms y open en el CONTENT +20,6ms,
con press-squeeze y slide-from-right-full corriendo. Antes: los dos en el
trigger, press-squeeze jamas.
`regime` DEFINIDO — y son dos valores, no cuatro. `replace` (default) y `queue`,
este solo para las 4 parejas irreducibles: los tres toggles (el provider ES el
boton) y el knob. `collapse` retirado (su caso murio con la propiedad: medido, 0
huecos en 5 emisiones a 72ms) y `lock` retirado (significaria «un cierre que no
se anuncia»), con sus 4 declaraciones muertas.
El guard de `queue` PASO EN VERDE SIENDO INCORRECTO: con timers falsos no hay
animaciones, asi que awaitExpression volvia al instante. El navegador midio el
commit encolado llegando 1,6s tarde. `queue` espera el HOLD, no la expresion.
Medir la envolvente no es medir la salida.
`renderAttrs` — los attrs que no son partes. Vaciar ACTIVE_DEV_TRACK (palabras y
chronos ya no estan excluidos) destapo 23 `data-palabras-*` que ningun morfo
declaraba y que palabras.css SI estiliza: aterrizan en el arbol que el usuario
escribio, asi que no pueden ser partes. Campo nuevo con la linea afilada —si el
consumidor puede componerlo, es una PARTE— y 3 consumidores (palabras, waveform,
aura). Declarado en types.ts Y en el esquema sium: la leccion de MorfoElement.
Ademas: 5 selectores muertos en el predicado del focus-scope de palabras
(barrido de todo el repo: aparecian solo ahi) · RTL-1 real en palabras-chrome
(inset logico + translate fisico = doble volteo; rtl:check 1->0) · el union
inline al `Direction` canonico, que destapo que el censo de direccion grepea el
NOMBRE del tipo · deuda de chronos (scope, barrel, README).
Y de la cola: S-36 (barrel 68->71 + guard), S-31 (vibrate(NaN)), S5 (la
preferencia de reduced-motion del usuario ya gana a los channels del morfo), SO2
(el warn que el JSDoc prometia), SO4 (validar el target antes del prewrite).
Todos los guards nuevos vistos fallar antes de arreglar nada.
Base: check 74 (= base) · sema+morfo+contracts 454 verdes / 6 ajenos
preexistentes · soma navegador 1258/1259 (el rojo es un timeout ajeno,
reproducido con los cambios en stash) · docs:check 0/618 · rtl:check 0/177.
Handoff: docs/process/CONTINUE-perceptual-surface.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
### The surface is ONE SLOT — ownership and `regime`
|
|
|
|
|
|
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
Those six attrs are a **single slot per element**. Two occurrences on one node
|
fix(sema,morfo,soma): una superficie no admite dos ocurrencias, y el nombre ya no miente
`data-event-*` es UNA RANURA por elemento. Tres auditorias independientes
encontraron el mismo defecto y ninguna lo cerro: fable S1 (2026-07-01, con el
README diciendo «findings executed»), sema S-17 (2026-08-05, midio el estampado
del knob muriendo a los 24ms de un hold de 240) y blocks A-36/A-65 (reproducido
en navegador, dos estampados a 1,1ms). Lo que faltaba no era diagnostico: nadie
podia distinguir una redireccion legitima de una deriva, porque la opcion que
redirigia se llamaba `fallbackTarget` y hacia lo contrario de lo que decia.
EL NOMBRE PRIMERO. `fallbackTarget` -> `targetOverride` (202 apariciones, 64
ficheros, dirigido con `git ls-files`). Siempre GANO sobre el ref registrado; el
nombre honesto es la precondicion para auditarlo. Las cronicas conservan el viejo
por diseño.
LA PROPIEDAD. `unstampEventAttrs` recibia el signal y lo DESCARTABA, asi que la
ocurrencia que terminaba antes borraba a la que tenia la ranura. Ahora comprueba
`data-event-id`. Con eso, `replace` deja de ser el comportamiento roto y pasa a
ser el suelo correcto.
A-36, SIN `regime`. Los cuatro overlays cedian el estampado del `open` al
trigger por un workaround de la era `sequence: 'pre'`; con `post` el content ya
esta montado. Retirado el override (float-panel migrado `pre`->`post`, ultimo
fuera de la doctrina que sema.md escribe). Medido en /blocks/site-header/preview
a 375px: contact-activate en el TRIGGER +18,7ms y open en el CONTENT +20,6ms,
con press-squeeze y slide-from-right-full corriendo. Antes: los dos en el
trigger, press-squeeze jamas.
`regime` DEFINIDO — y son dos valores, no cuatro. `replace` (default) y `queue`,
este solo para las 4 parejas irreducibles: los tres toggles (el provider ES el
boton) y el knob. `collapse` retirado (su caso murio con la propiedad: medido, 0
huecos en 5 emisiones a 72ms) y `lock` retirado (significaria «un cierre que no
se anuncia»), con sus 4 declaraciones muertas.
El guard de `queue` PASO EN VERDE SIENDO INCORRECTO: con timers falsos no hay
animaciones, asi que awaitExpression volvia al instante. El navegador midio el
commit encolado llegando 1,6s tarde. `queue` espera el HOLD, no la expresion.
Medir la envolvente no es medir la salida.
`renderAttrs` — los attrs que no son partes. Vaciar ACTIVE_DEV_TRACK (palabras y
chronos ya no estan excluidos) destapo 23 `data-palabras-*` que ningun morfo
declaraba y que palabras.css SI estiliza: aterrizan en el arbol que el usuario
escribio, asi que no pueden ser partes. Campo nuevo con la linea afilada —si el
consumidor puede componerlo, es una PARTE— y 3 consumidores (palabras, waveform,
aura). Declarado en types.ts Y en el esquema sium: la leccion de MorfoElement.
Ademas: 5 selectores muertos en el predicado del focus-scope de palabras
(barrido de todo el repo: aparecian solo ahi) · RTL-1 real en palabras-chrome
(inset logico + translate fisico = doble volteo; rtl:check 1->0) · el union
inline al `Direction` canonico, que destapo que el censo de direccion grepea el
NOMBRE del tipo · deuda de chronos (scope, barrel, README).
Y de la cola: S-36 (barrel 68->71 + guard), S-31 (vibrate(NaN)), S5 (la
preferencia de reduced-motion del usuario ya gana a los channels del morfo), SO2
(el warn que el JSDoc prometia), SO4 (validar el target antes del prewrite).
Todos los guards nuevos vistos fallar antes de arreglar nada.
Base: check 74 (= base) · sema+morfo+contracts 454 verdes / 6 ajenos
preexistentes · soma navegador 1258/1259 (el rojo es un timeout ajeno,
reproducido con los cambios en stash) · docs:check 0/618 · rtl:check 0/177.
Handoff: docs/process/CONTINUE-perceptual-surface.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
cannot both express, and the framework spent a year not saying so: three
|
|
|
|
|
|
independent audits found the same defect and none closed it (fable **S1**
|
|
|
|
|
|
2026-07-01 · sema **S-17** 2026-08-05 · blocks **A-36 / A-65**, reproduced in
|
|
|
|
|
|
the browser). Two rules now hold it shut.
|
|
|
|
|
|
|
|
|
|
|
|
**1 · The unstamp checks ownership.** `unstampEventAttrs` retires the
|
|
|
|
|
|
projection only when `data-event-id` still matches the signal that wrote it.
|
|
|
|
|
|
Before 2026-08-10 it took the signal and discarded it, so the occurrence
|
|
|
|
|
|
finishing FIRST wiped whichever one currently held the slot — measured on the
|
|
|
|
|
|
knob, a `commit-set` projection died 24 ms into a 240 ms hold.
|
|
|
|
|
|
|
|
|
|
|
|
**2 · `regime` says what an ARRIVING occurrence does to a busy surface**
|
|
|
|
|
|
(`SemaRegime`, declared per morfo event, default `replace`):
|
|
|
|
|
|
|
|
|
|
|
|
| Value | Behaviour |
|
|
|
|
|
|
| --- | --- |
|
|
|
|
|
|
| `replace` | Takes the surface at once, displacing the live projection. **Default** — and correct only since rule 1. |
|
|
|
|
|
|
| `queue` | Waits for the live occurrence's HOLD to elapse, then takes it. |
|
|
|
|
|
|
|
|
|
|
|
|
`queue` waits for the **hold**, never for the whole expression.
|
|
|
|
|
|
`awaitExpression` keeps the projection alive until the target's animations
|
|
|
|
|
|
finish (capped at `MAX_EXPRESSION_WAIT_MS`), which is right for unstamping and
|
|
|
|
|
|
wrong for queueing: gating on it delayed a Toggle's queued `commit-toggle` by
|
|
|
|
|
|
**1.6 s**, because unrelated transitions kept the node busy. The engine and the
|
|
|
|
|
|
channel resolve that number through one path (`VisualChannel.holdMsFor`).
|
|
|
|
|
|
|
|
|
|
|
|
**Reach for `regime` last.** It is for pairs the doctrine REQUIRES on one node
|
|
|
|
|
|
and no re-targeting can separate — a toggle's `contact-press` + `commit-toggle`
|
|
|
|
|
|
(its provider IS the button), the knob's `handle-drop` + `commit-set`. When the
|
|
|
|
|
|
collision comes from a **redirection** instead, the fix is to stop redirecting:
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
that is how A-36 closed, with the overlays' `emerge-open` giving up a
|
|
|
|
|
|
`targetOverride` left over from when they were `sequence: 'pre'`. Measured
|
|
|
|
|
|
after: the Button's `contact-activate` stamps the trigger and the Drawer's
|
|
|
|
|
|
`emerge-open` stamps its content — two surfaces, both expressing.
|
|
|
|
|
|
|
|
|
|
|
|
The redirection those overlays DID need — landing `emerge-close` on the trigger
|
|
|
|
|
|
once the content has unmounted — is not a `targetOverride` either: it is
|
|
|
|
|
|
**mount-state resolution, declared in the morfo as `targetFallback`** and
|
|
|
|
|
|
resolved by the runtime through the same single path that moves a11y focus
|
|
|
|
|
|
(`resolveEmitTarget`). A rule may select a fallback part — the census counts it
|
|
|
|
|
|
stampable — but it only fires in the degraded mount; the routine surface is
|
|
|
|
|
|
still the declared target. The field, its invariants and its split from
|
|
|
|
|
|
`allowedTargets`: [`architecture/morfo.md` §Step 5.5](./morfo.md).
|
fix(sema,morfo,soma): una superficie no admite dos ocurrencias, y el nombre ya no miente
`data-event-*` es UNA RANURA por elemento. Tres auditorias independientes
encontraron el mismo defecto y ninguna lo cerro: fable S1 (2026-07-01, con el
README diciendo «findings executed»), sema S-17 (2026-08-05, midio el estampado
del knob muriendo a los 24ms de un hold de 240) y blocks A-36/A-65 (reproducido
en navegador, dos estampados a 1,1ms). Lo que faltaba no era diagnostico: nadie
podia distinguir una redireccion legitima de una deriva, porque la opcion que
redirigia se llamaba `fallbackTarget` y hacia lo contrario de lo que decia.
EL NOMBRE PRIMERO. `fallbackTarget` -> `targetOverride` (202 apariciones, 64
ficheros, dirigido con `git ls-files`). Siempre GANO sobre el ref registrado; el
nombre honesto es la precondicion para auditarlo. Las cronicas conservan el viejo
por diseño.
LA PROPIEDAD. `unstampEventAttrs` recibia el signal y lo DESCARTABA, asi que la
ocurrencia que terminaba antes borraba a la que tenia la ranura. Ahora comprueba
`data-event-id`. Con eso, `replace` deja de ser el comportamiento roto y pasa a
ser el suelo correcto.
A-36, SIN `regime`. Los cuatro overlays cedian el estampado del `open` al
trigger por un workaround de la era `sequence: 'pre'`; con `post` el content ya
esta montado. Retirado el override (float-panel migrado `pre`->`post`, ultimo
fuera de la doctrina que sema.md escribe). Medido en /blocks/site-header/preview
a 375px: contact-activate en el TRIGGER +18,7ms y open en el CONTENT +20,6ms,
con press-squeeze y slide-from-right-full corriendo. Antes: los dos en el
trigger, press-squeeze jamas.
`regime` DEFINIDO — y son dos valores, no cuatro. `replace` (default) y `queue`,
este solo para las 4 parejas irreducibles: los tres toggles (el provider ES el
boton) y el knob. `collapse` retirado (su caso murio con la propiedad: medido, 0
huecos en 5 emisiones a 72ms) y `lock` retirado (significaria «un cierre que no
se anuncia»), con sus 4 declaraciones muertas.
El guard de `queue` PASO EN VERDE SIENDO INCORRECTO: con timers falsos no hay
animaciones, asi que awaitExpression volvia al instante. El navegador midio el
commit encolado llegando 1,6s tarde. `queue` espera el HOLD, no la expresion.
Medir la envolvente no es medir la salida.
`renderAttrs` — los attrs que no son partes. Vaciar ACTIVE_DEV_TRACK (palabras y
chronos ya no estan excluidos) destapo 23 `data-palabras-*` que ningun morfo
declaraba y que palabras.css SI estiliza: aterrizan en el arbol que el usuario
escribio, asi que no pueden ser partes. Campo nuevo con la linea afilada —si el
consumidor puede componerlo, es una PARTE— y 3 consumidores (palabras, waveform,
aura). Declarado en types.ts Y en el esquema sium: la leccion de MorfoElement.
Ademas: 5 selectores muertos en el predicado del focus-scope de palabras
(barrido de todo el repo: aparecian solo ahi) · RTL-1 real en palabras-chrome
(inset logico + translate fisico = doble volteo; rtl:check 1->0) · el union
inline al `Direction` canonico, que destapo que el censo de direccion grepea el
NOMBRE del tipo · deuda de chronos (scope, barrel, README).
Y de la cola: S-36 (barrel 68->71 + guard), S-31 (vibrate(NaN)), S5 (la
preferencia de reduced-motion del usuario ya gana a los channels del morfo), SO2
(el warn que el JSDoc prometia), SO4 (validar el target antes del prewrite).
Todos los guards nuevos vistos fallar antes de arreglar nada.
Base: check 74 (= base) · sema+morfo+contracts 454 verdes / 6 ajenos
preexistentes · soma navegador 1258/1259 (el rojo es un timeout ajeno,
reproducido con los cambios en stash) · docs:check 0/618 · rtl:check 0/177.
Handoff: docs/process/CONTINUE-perceptual-surface.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
|
|
|
|
|
`collapse` and `lock` were declared here from the founding commit and never
|
|
|
|
|
|
meant anything; both were retired on 2026-08-10 rather than left as a contract
|
|
|
|
|
|
that lies. The reasons are in `SemaRegime`'s own docblock.
|
|
|
|
|
|
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
### Cascade rules — flat CSS-like shape
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
interface SemaCascadeRule {
|
|
|
|
|
|
selector: string // CSS selector — matches state attrs + event tokens
|
|
|
|
|
|
priority?: number // CSS-specificity override (optional)
|
|
|
|
|
|
channels?: readonly SemaChannelId[] // restricts / silences active channels
|
|
|
|
|
|
sound?: …
|
|
|
|
|
|
haptic?: …
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
One rule = one selector + one block of deltas. No intermediate
|
|
|
|
|
|
`overrides: { eventLabel: ... }` layer — the event's identity is read from
|
|
|
|
|
|
the selector via the `[data-event*]` tokens.
|
|
|
|
|
|
|
|
|
|
|
|
### Cascade selectors — typed builder, no hand-written strings
|
|
|
|
|
|
|
|
|
|
|
|
Cascade rules in `sema/components/*.ts` MUST build their `selector` via
|
|
|
|
|
|
`semaSelector(morfo, partKebab, matchers?)` from `$uix/morfo`. The helper
|
|
|
|
|
|
closes the loop between morfo's part/event contract and the selectors the
|
|
|
|
|
|
cascade evaluates.
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
import { semaSelector } from '$uix/morfo';
|
|
|
|
|
|
import { dialogMorfo } from '$uix/morfo/components/dialog';
|
|
|
|
|
|
|
|
|
|
|
|
const onContent = (matchers?: Parameters<typeof semaSelector<typeof dialogMorfo>>[2]) =>
|
|
|
|
|
|
semaSelector(dialogMorfo, 'content', matchers);
|
|
|
|
|
|
|
|
|
|
|
|
cascade: [
|
|
|
|
|
|
// [data-dialog-content][data-event-family="commit"]
|
|
|
|
|
|
{ selector: onContent({ eventFamily: 'commit' }), haptic: { kind: 'tap' } },
|
|
|
|
|
|
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
// [data-dialog-content][data-event="signal-alert-close-fail"]
|
|
|
|
|
|
{ selector: onContent({ eventName: 'signal-alert-close-fail' }), sound: { sampleUrl: '/fail.wav' } },
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
// [data-dialog-content][data-event^="emerge-close"][data-event-family="emerge"]
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
{
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
selector: onContent({ eventNamePrefix: 'emerge-close', eventFamily: 'emerge' }),
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
sound: { contour: 'descending', pitch: { op: 'add', value: -150 } }
|
|
|
|
|
|
}
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Compile-time guarantees:
|
|
|
|
|
|
|
|
|
|
|
|
- `partKebab` is checked against `morfo.parts[].kebab`.
|
|
|
|
|
|
- `eventName` is checked against `morfo.events[].name`.
|
|
|
|
|
|
- `eventFamily` / `eventIntent` are typed against the canonical sema unions.
|
|
|
|
|
|
- `state` / `aria` / `pseudo` accept plain strings (the data-attr vocabulary
|
|
|
|
|
|
is per-component and not yet typed-derived).
|
|
|
|
|
|
|
|
|
|
|
|
Renaming a part or event in morfo breaks the cascade at type-check time, not
|
|
|
|
|
|
silently in production. **Hand-written selector strings in cascade rules are
|
|
|
|
|
|
a code smell** — review them as drift.
|
|
|
|
|
|
|
|
|
|
|
|
### Per-component packs — `sema/components/{name}.ts`
|
|
|
|
|
|
|
|
|
|
|
|
Each component ships its perceptual-defaults pack in
|
|
|
|
|
|
`src/uix/sema/components/{name}.ts`, symmetric to soma and eidos:
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
import { semaSelector } from '$uix/morfo';
|
|
|
|
|
|
import { dialogMorfo } from '$uix/morfo/components/dialog';
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
import type { Sema } from '../sema-map';
|
|
|
|
|
|
import { sound, soundSampleUrls } from '../sounds';
|
|
|
|
|
|
|
|
|
|
|
|
export const dialogSema: Sema = {
|
|
|
|
|
|
name: 'dialog',
|
|
|
|
|
|
preloadSamples: soundSampleUrls(['notification.ping']),
|
|
|
|
|
|
cascade: [
|
|
|
|
|
|
{
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
// `[data-dialog-content][data-event-intent="threat"]`, built from
|
|
|
|
|
|
// the morfo contract — a part rename breaks at compile time.
|
|
|
|
|
|
selector: semaSelector(dialogMorfo, 'content', { eventIntent: 'threat' }),
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
sound: sound('notification.ping'),
|
|
|
|
|
|
haptic: { kind: 'error', pattern: [50, 80, 50, 80, 50] }
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
};
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The app imports the packs it uses (tree-shakable):
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
import { dialogSema } from '$uix/sema/components/dialog';
|
|
|
|
|
|
|
|
|
|
|
|
defineEngineSemantic({
|
|
|
|
|
|
components: [dialogSema],
|
|
|
|
|
|
overrides: {
|
|
|
|
|
|
cascade: [
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
// App-level rules win over packs on specificity ties. Apps use the
|
|
|
|
|
|
// SAME typed builder; instance scoping goes in `ancestor`.
|
|
|
|
|
|
{
|
|
|
|
|
|
selector: semaSelector(dialogMorfo, 'content', { ancestor: '#critical' }),
|
|
|
|
|
|
sound: { sampleUrl: '/x.wav' }
|
|
|
|
|
|
}
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`preloadSamples` is concatenated across all packs and passed to
|
feat(sema,sound): un pack se entrega como quieras — y un `data:` no se pide, se descodifica
La entrega deja de ser parte del contrato. Un pack de ficheros puede llegar
como quince URLs o como UN JSON de base64 (`packFromBase64`): mismo tipo, mismo
intercambio en caliente, misma reserva sintética por entrada, y un nombre que
no existe sigue sin compilar. Medido sobre `static/sounds/ui-inline.json`: una
petición en vez de quince, y 69.082 B con brotli frente a 79.332 B de los
ficheros sueltos — el +33 % del base64 lo deshace la compresión, y el JSON gana
además porque nadie comprime `audio/mpeg` y todos comprimen `application/json`.
## `step` no se oía
Era a la vez el MÁS CORTO (18 ms) y el MÁS FLOJO (gain 0.025), y esas dos cosas
se multiplican: el oído integra energía durante ~100-200 ms, así que un tono
corto necesita MÁS amplitud, no menos. Medido, rendía a −29,8 dBFS con la
novena parte de la energía de `touch`. Ahora 0.06 a los mismos 18 ms.
Lo que no había era el guard: la distinguibilidad es una RELACIÓN, y dos
sonidos pueden ser perfectamente distintos entre sí y ser los dos inaudibles.
`sound-names.test.ts` gana un suelo absoluto sobre `gain² × duración`.
## El precalentamiento no precalentaba
- `preload` pedía el contexto con `getOrCreateContext()`, que hace
`await resume()` — y antes del primer gesto esa promesa se queda PENDIENTE en
Chrome, no se rechaza. No descargaba nada hasta que el usuario ya había
pulsado, que es justo la latencia que el preload existe para quitar.
`decodeAudioData` funciona en un contexto suspendido.
- Aplicar un pack en caliente no calentaba la caché: cada nombre pagaba su
viaje la primera vez que sonaba. Ahora `rebuildMap()` llama a `warmSamples()`.
- Con `preferences.sound === 'off'` no se descarga NADA — un pack que no se
puede oír son bytes gastados en silencio. Pero la petición se RECUERDA en vez
de tirarse: el nivel se lee en el dispatch, así que la primera reproducción
audible vacía la cola y encender el sonido no devuelve una caché fría.
## Un `data:` se descodifica en el sitio
`connect-src 'self'` BLOQUEA `fetch('data:…')` — la directiva casa por ESQUEMA
y `'self'` no cubre `data:` — mientras deja pasar una ruta del mismo origen. Un
pack inline enrutado por `fetch` caía a síntesis EN SILENCIO justo en el
entorno que llevó a alguien a hacerlo inline. Y es ~6x más lento. `bytesFor()`
lo resuelve con `atob`.
## De la revisión adversarial
- Las claves del JSON se validan: una que no sea `SoundName` LANZA, igual que
una ruta mala en `assertMapPaths` y por la misma razón — tragarse la errata
da el síntoma «parte de mi pack no se aplicó» sin nada a lo que apuntar.
- `isSoundName` preguntaba `name in SEMA_MAP.sounds`, y `in` recorre el
prototipo: `isSoundName('toString')` devolvía `true`. Inofensivo mientras
todos los llamantes tecleaban el nombre; nada inofensivo al validar red.
- `warmSamples` sólo tenía una de las dos ramas que sí tiene el constructor, así
que una app con canal de sonido propio se calentaba al arrancar y nunca más;
y esa rama leía la preferencia UNA vez, en construcción. Las dos se caían por
lo mismo: ahora comparten `warmUrls()` en vez de duplicarse.
- El demo del catálogo cancela su fetch: elegir `inline` y saltar a `synth`
antes de que llegara reinstalaba el pack sobre un `clearMap()` ya hecho.
- `fallbackFor(name)` borra los dos casts que copiaba todo el que autorase un
pack de ficheros.
## Documentación
`architecture/sema.md` gana la sección de las dos formas de entrega y el
párrafo de `preloadSamples` reescrito — describía un precalentamiento que ya no
es el que ocurre. El README del arte conoce la ruta `data:`. La página de packs
gana su sección equivalente y deja de señalar unos `.wav` sueltos como «el
ejemplo».
Y un fantasma: `soft` no existe — es un nombre del catálogo viejo que quedaba
como ejemplo en ocho sitios, incluido el docstring de `applySounds`, cuyo
ejemplo copiado literalmente LANZABA.
`static/sounds/ui-inline.json` se genera desde `packs/ui-mp3.ts`; el comando
está documentado ahí y reproduce el fichero byte a byte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`SoundChannel.preloadSamples()` when the engine is created, together with every
|
|
|
|
|
|
sample URL the map itself can reach — so installing a pack at runtime
|
|
|
|
|
|
(`applySoundPack`) warms it too, instead of leaving the first play of each name
|
|
|
|
|
|
to pay its own round trip. Preloading does NOT wait for the unlock gesture:
|
|
|
|
|
|
`decodeAudioData` works on a suspended context, while awaiting `resume()` before
|
|
|
|
|
|
the first click stays pending forever and downloaded nothing.
|
|
|
|
|
|
|
|
|
|
|
|
With `preferences.sound === 'off'` it downloads nothing at all — a pack that
|
|
|
|
|
|
cannot be heard is bytes spent on silence. The request is REMEMBERED, not
|
|
|
|
|
|
dropped: the level is read at dispatch, so the first audible play flushes the
|
|
|
|
|
|
deferred warm, and turning sound on does not hand back a cold cache.
|
|
|
|
|
|
|
|
|
|
|
|
The global unlock listener is not registered in the channel's constructor; it is
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
installed only once there is an `AudioContext` to unlock.
|
|
|
|
|
|
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
### When a component deserves a pack — participation doctrine (2026-07-07)
|
|
|
|
|
|
|
|
|
|
|
|
`Morfo.expression` (`SemaExpressionMode`, [`morfo/types.ts`](../../src/uix/morfo/types.ts),
|
|
|
|
|
|
author decision 2026-05-26) declares HOW a sema-scoped morfo contributes its
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
perceptual signature. THIS section is the canonical doctrine; it was
|
|
|
|
|
|
canonized at the component-audit checkpoint (verdicts S3a/S11 — historical
|
|
|
|
|
|
record in [`docs/audit/components/_veredictos.md`](../audit/components/_veredictos.md)):
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
four legitimate stances, each with shipped exemplars —
|
|
|
|
|
|
|
docs(sema,theming): el orden real, como se autora cada canal, y el hueco del theming
Tres cosas que el cambio del sonido dejo sin plasmar.
1. EL ORDEN CANONICO MENTIA. La numeracion 1·2·3·4·5a·5b esta citada como
canonica en sema.md, resolver.ts y engine.ts, y despues del reorden era
falsa para `sound`: un pack ya no autora en 5a, lo hace en 1.5. Corregido
en los tres sitios a la vez, con el porque — todo lo que AUTORA un sonido
corre ahi conservando su precedencia relativa; solo cambio su posicion
respecto al intent. El resto de la regla (channels/haptic/hold) mantiene
el «gana el ultimo» porque no son ejes evaluativos.
2. COMO SE AUTORA CADA CANAL (CANON §7). El reparto por dueño estaba
escrito; lo que un componente ESCRIBE, no. Tabla nueva: el canal visual
no se escribe (se declara el evento y eidos reacciona), `sound` es UN
NOMBRE, `haptic` es un `kind`. La regla es la misma en las tres filas y
ese es el punto: un componente dice QUE ocurre, nunca cuan fuerte, cuan
brillante ni cuanto dura. El sonido era la excepcion hasta ayer.
3. EL ANALISIS DEL THEMING que el autor pidio (theming/channels.md §5b).
Lo que el cambio NO toco: nada de eidos. El canal visual se proyecta
estampando data-event-*, y esa ruta quedo intacta — ni una receta, ni un
token, ni un selector. Eidos no sabe que existe el sonido y no le hizo
falta. Lo que cambio fue DONDE se autora (un catalogo en vez de 71
ficheros) y CUANDO se aplica (antes del intent), ambos dentro de sema.
Lo que si cambio, y es lo util: `applyTheme(seed)` retunea SEIS ejes
visuales (color·type·depth·shape·space·gradient) y el sonido tiene CERO.
Antes esa asimetria se justificaba sola — con 214 reglas autorando 33
firmas a mano no habia objeto que retunear. Hoy hay exactamente uno:
16 nombres en un const. Un eje `sound` en ThemeSeed seria la misma forma
que los otros seis.
Y las tres puertas de personalizacion, medidas, ninguna llega al
catalogo: `overrides.runtime` recorre rutas de SEMA_MAP y el catalogo no
esta en el mapa (ademas se traga las erratas, S-09); `overrides.cascade`
es por selector, no un tema; `masterGain` se descarta en SILENCIO
(S-05/S-32). Un producto puede silenciar y puede pisar una ocurrencia,
pero NO puede re-voceear el sistema. Queda escrito en vez de ser
folclore.
⚠️ chronos: `src/uix/sema/components/chronos.ts` entro en la migracion de
`769e426c5` pese a ser de escritura excluida. Era forzoso — con el tipo
estrechado, dejarlo sin migrar rompe la compilacion del arbol entero — y
el cambio es mecanico (soundTuning(...) -> nombre), sin decision de diseño.
Su SPEC.md NO se ha tocado y sigue citando `soundTuning('commit.soft')`.
VERIFICADO: sema+morfo+sound 437/437 · check 75 · docs:check 0/618.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
1. **`'pack'`** — a cascade in `sema/components/{kebab}.ts` NAMES the sound
|
|
|
|
|
|
per event. Justified when the pattern ADDS meaning beyond family + intent
|
|
|
|
|
|
deltas (date-field naming a fall for its clear; menubar's in-place note:
|
|
|
|
|
|
"subtle commit + tap haptic for high-frequency top-level triggers"). A pack
|
|
|
|
|
|
that only restates the family default is not a pack — it is noise, and the
|
|
|
|
|
|
type makes that cheap to see: one word, or nothing.
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
2. **`'family-default'`** — family base + intent deltas suffice. Legitimate
|
|
|
|
|
|
when (a) the gesture is generic contact (button), (b) the book itself
|
|
|
|
|
|
counsels restraint (command, citing ch. 22 §8: celebrating at the click is
|
|
|
|
|
|
*"celebrate before time"* — the outcome fires downstream), or (c) a
|
|
|
|
|
|
composed child supplies the character (field-langs: the embedded
|
|
|
|
|
|
ToggleGroup's pack puts the tap). The reason is written IN the morfo.
|
|
|
|
|
|
3. **`'delegated'`** — composite; expression lives in the children's packs.
|
|
|
|
|
|
The composite declares ONLY the events its children don't own (date-picker:
|
|
|
|
|
|
its own `commit-reset`; selection/commit sound through the embedded
|
|
|
|
|
|
date-field/calendar). The anti-duplication rationale is radio-cards'
|
|
|
|
|
|
morfo header: *"declaring them here would duplicate the contract"*.
|
|
|
|
|
|
4. **Declared debt** — `events: []` with an honest "yet" comment (the generic
|
|
|
|
|
|
Picker) is better than silence but MUST carry a deadline or become a
|
|
|
|
|
|
decision: an undated "yet" is a hole in disguise.
|
|
|
|
|
|
|
|
|
|
|
|
Coherence is guarded: `morfo-vocabulary-check` fails when a pack file exists
|
|
|
|
|
|
and `expression` declares anything other than `'pack'`, and warns when a pack
|
|
|
|
|
|
exists with no `expression` at all (verdict S11d).
|
|
|
|
|
|
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
### The sound pack — `SEMA_MAP.sounds`
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
docs(sema)!: retirar D.7 y S-07 — el orden hace imposible lo que prohibian
F6 del PLAN-sound-names, y el motivo importa mas que el borrado: no se
derogan por cambio de opinion, se DISUELVEN. La doctrina del autor que
las origino sigue siendo cierta; lo que cambia es quien la sostiene.
D.7 prohibia canonizar un sample sobre un evento cuya familia tuviera
base.sound, porque sound() devolvia una firma COMPLETA y la cascada la
aplicaba en replace DESPUES del intent: un fulfill perdia su +300 Hz
ascendente. S-07 era el mismo defecto una capa mas abajo — el gain
desnudo de los 14 afinados de escalera — y seguia ABIERTO por decision
del autor.
Con el nombre aplicado ANTES de los deltas de intent no queda ninguna
capa posterior que pueda pisarlos. Aplastar el perfil evaluativo ya no
esta prohibido: es INEXPRESABLE. Y S-07 pierde su premisa entera, porque
SOUND_TUNINGS ya no existe.
LO QUE SE CONSERVA, con su sitio nuevo escrito: el silencio como firma
valida (SILENT), el criterio de cuando crear un pack, y los samples como
recurso de producto (el catalogo los admite con nombre; la app autora los
suyos por overrides.cascade, que sigue abierto a proposito).
LO UNICO DE D.7 QUE HAY QUE SEGUIR SABIENDO, y por eso queda escrito en
tres sitios: playSample lee EXACTAMENTE dos campos, sampleUrl y gain. No
hay playbackRate ni detune. Sobre un .wav el intent solo mueve el
volumen — medido, risk es indistinguible de neutral porque solo aporta
roughness y la ruta de sample lo ignora. Un sample con carga evaluativa
necesita UN FICHERO POR INTENT, que es lo que hace signal con ping frente
a error y la verdadera razon de que fuese la excepcion. Es fisica del
audio, no politica.
Tocado: book-deviations §D.7 + §S-07 · sema.md §the sound catalogue
(reescrita entera, con el orden y el limite del WAV) · CLAUDE.md §sema
doctrine · los dos README del art · CONTINUE-sema-audit §3.0/§3.1/§3.6,
que es el handoff vivo y estaba describiendo una cola que ya no existe.
⚠️ Prettier reformatea entero book-deviations.md y sema.md porque NO
estaban formateados en HEAD; reaplicado a mano para que el diff sea solo
lo mio. Mismo motivo por el que CLAUDE.md y arts/README.md van con 1-2
lineas en vez de 30.
VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline · docs:check
0/618 · prettier limpio en los ficheros que toque.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
**A component names a sound. It never writes a parameter.** The whole authoring
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
surface of the sound channel is one word, and only when the component differs
|
|
|
|
|
|
from its family's default:
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
```ts
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
{ selector: onTrigger({ eventName: 'contact-activate' }), sound: 'snap' }
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
```
|
|
|
|
|
|
|
docs(sema)!: retirar D.7 y S-07 — el orden hace imposible lo que prohibian
F6 del PLAN-sound-names, y el motivo importa mas que el borrado: no se
derogan por cambio de opinion, se DISUELVEN. La doctrina del autor que
las origino sigue siendo cierta; lo que cambia es quien la sostiene.
D.7 prohibia canonizar un sample sobre un evento cuya familia tuviera
base.sound, porque sound() devolvia una firma COMPLETA y la cascada la
aplicaba en replace DESPUES del intent: un fulfill perdia su +300 Hz
ascendente. S-07 era el mismo defecto una capa mas abajo — el gain
desnudo de los 14 afinados de escalera — y seguia ABIERTO por decision
del autor.
Con el nombre aplicado ANTES de los deltas de intent no queda ninguna
capa posterior que pueda pisarlos. Aplastar el perfil evaluativo ya no
esta prohibido: es INEXPRESABLE. Y S-07 pierde su premisa entera, porque
SOUND_TUNINGS ya no existe.
LO QUE SE CONSERVA, con su sitio nuevo escrito: el silencio como firma
valida (SILENT), el criterio de cuando crear un pack, y los samples como
recurso de producto (el catalogo los admite con nombre; la app autora los
suyos por overrides.cascade, que sigue abierto a proposito).
LO UNICO DE D.7 QUE HAY QUE SEGUIR SABIENDO, y por eso queda escrito en
tres sitios: playSample lee EXACTAMENTE dos campos, sampleUrl y gain. No
hay playbackRate ni detune. Sobre un .wav el intent solo mueve el
volumen — medido, risk es indistinguible de neutral porque solo aporta
roughness y la ruta de sample lo ignora. Un sample con carga evaluativa
necesita UN FICHERO POR INTENT, que es lo que hace signal con ping frente
a error y la verdadera razon de que fuese la excepcion. Es fisica del
audio, no politica.
Tocado: book-deviations §D.7 + §S-07 · sema.md §the sound catalogue
(reescrita entera, con el orden y el limite del WAV) · CLAUDE.md §sema
doctrine · los dos README del art · CONTINUE-sema-audit §3.0/§3.1/§3.6,
que es el handoff vivo y estaba describiendo una cola que ya no existe.
⚠️ Prettier reformatea entero book-deviations.md y sema.md porque NO
estaban formateados en HEAD; reaplicado a mano para que el diff sea solo
lo mio. Mismo motivo por el que CLAUDE.md y arts/README.md van con 1-2
lineas en vez de 30.
VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline · docs:check
0/618 · prettier limpio en los ficheros que toque.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`Sema['cascade'].sound` accepts a `SoundName` or `SILENT`, **and nothing else** —
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
the law is a type, not a convention. The same holds for the morfo's per-event
|
|
|
|
|
|
`overrides.sound`, for `overrides.cascade` (the app's door) and for the per-emit
|
|
|
|
|
|
option. Nobody authors a signature inline, not even the product: bringing a new
|
|
|
|
|
|
sound means REGISTERING it (declare the name, define it once) and then naming it.
|
fix(sema): los toggles recuperan voz, y el silencio deja de sintetizarse — muere el prefijo form.
Tres cosas que el mismo hilo destapo, de la mas visible a la mas de fondo.
1) LOS TOGGLES SUENAN OTRA VEZ (directiva de autor 2026-08-05)
switch, toggle y toggle-group llevaban SILENCIADOS desde el 2026-05-26: su pack
aplicaba un tuning que restaba exactamente el gain base de la familia commit
(0.3 - 0.3 = 0). Medido en navegador: pico 0.0001, el suelo de la rampa. Un
silencio por defecto no se percibe como sobriedad sino como componente roto.
Pasan a `commit.medium` (gain 0.1): audible, y un tercio de una pulsacion de
boton (contact base 0.25) para que un flip no pese mas que una activacion. Los
deltas de intent siguen montando encima (threat +0.1, fulfill +0.05). El
haptico ligero no cambia. Medido despues: switch pico 0.1.
Conservan el silencio, con su justificacion intacta, solo los dos donde el
silencio ES la firma: tooltip (revela al pasar el raton, sonaria en cada cruce)
y media-player (su propia salida ES audio — D-AP2.7, decision del hilo de audio).
2) EMITIR SILENCIO YA NO CUESTA
`SoundChannel.handle` cortaba DESPUES de resolver la firma, asi que un tuning
silenciador levantaba dos osciladores, un filtro y una envolvente programada
para no sonar, en cada interaccion. Ahora corta antes de sintetizar cuando la
ganancia resuelta es <= 0. El corte mira la ganancia RESUELTA, no el tuning, asi
que un intent que la devuelve por encima de 0 (threat, fulfill) suena igual.
Fijado con test propio, verificado en ROJO quitando el corto.
3) EL AFINADO SE NOMBRA POR LA FAMILIA QUE MODIFICA
El catalogo mezclaba tres ejes en el primer segmento —familia (emerge.*,
contact.silent), componente (tooltip.*, tabs.*) y la categoria huerfana form.*—
sin regla declarada y sin guard que mirara. `form.commit.soft/subtle` entro el
2026-05-19 (09e261878, el commit que CREA sounds.ts) nombrando con verdad a
siete controles de formulario; el 2026-05-26, 2d562f378 lo extendio a menus y
arboles en la misma pasada que escribia la doctrina: 7 -> 29 consumidores en un
commit, 50 hoy, de los que exactamente UNO era el Form. El D.6 de ese commit
llego a poner el nombre correcto —commit.select— en la linea que usaba la clave
incorrecta.
form.commit.soft -> commit.soft
form.commit.subtle -> commit.subtle
form.toggle.silent -> commit.silent
tooltip.silent -> emerge.silent
tabs.select.soft -> commit.select.soft
131 ocurrencias en 68 ficheros, dirigido por `git ls-files` — nunca por recorrido
de directorio: hay 3 worktrees vivos y build/ con 449 apariciones mas que un sed
recursivo habria corrompido en silencio.
La cola queda LIBRE a proposito: media-player aplica el silenciador al
commit-set de un slider, no a un toggle — la cola describe la FIRMA, no el
evento, asi que cerrarla contra el vocabulario de verbos fabricaria otra
mentira. Por eso emerge.* no se toca pese a que `exit` no sea verbo canonico.
Quedan tres silenciadores, uno por familia con base audible, con el mismo
nombre: contact.silent (-0.25), commit.silent (-0.3), emerge.silent (-0.2).
Eso convierte la coherencia en INVARIANTE:
- `sounds-grammar.test.ts` (guard nuevo): cabeza ∈ SEMA_FAMILIES; forma
{family}.{tail}; y todo {family}.silent resta EXACTAMENTE el gain base de su
familia, leido de sema-map.ts —nunca copiado—. Verificado en ROJO: el guard
calculo solo el -0.4 esperado de signal.
- Ley escrita en sema.md § Tuning naming shapes, junto a la seccion hermana que
ya legislaba los nombres de EVENTO.
- vocabularies.md —"the ONE place the closed sets are spelled out"— pasa a
enumerar los 14 afinados por familia; el generador los extrae del const y
docs:check vigila su frescura.
- D.5 gana las dos notas: el renombrado y la reversion del silencio.
VERIFICACION: check 75 (linea base exacta) · sema 198/198 · docs:check 0/615 ·
navegador antes/despues (switch 0.0001 -> 0.1; button 0.25 sin tocar) · los 25
avisos de prettier entre lo tocado son deriva YA en HEAD, ninguno mio.
Cronica NO reescrita (4 ficheros): AUDIT-blocks-2026-08-01, PLAN-audio-player,
handoffs-claude-md y audit/components/date-field registran lo que ERA cierto.
DESVIACION DECLARADA: sema/components/chronos.ts entra con 6 sustituciones
mecanicas —chronos es de escritura excluida, pero dejarlo fuera rompia el
type-check del repo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
#### The two kinds of entry
|
fix(sema): los toggles recuperan voz, y el silencio deja de sintetizarse — muere el prefijo form.
Tres cosas que el mismo hilo destapo, de la mas visible a la mas de fondo.
1) LOS TOGGLES SUENAN OTRA VEZ (directiva de autor 2026-08-05)
switch, toggle y toggle-group llevaban SILENCIADOS desde el 2026-05-26: su pack
aplicaba un tuning que restaba exactamente el gain base de la familia commit
(0.3 - 0.3 = 0). Medido en navegador: pico 0.0001, el suelo de la rampa. Un
silencio por defecto no se percibe como sobriedad sino como componente roto.
Pasan a `commit.medium` (gain 0.1): audible, y un tercio de una pulsacion de
boton (contact base 0.25) para que un flip no pese mas que una activacion. Los
deltas de intent siguen montando encima (threat +0.1, fulfill +0.05). El
haptico ligero no cambia. Medido despues: switch pico 0.1.
Conservan el silencio, con su justificacion intacta, solo los dos donde el
silencio ES la firma: tooltip (revela al pasar el raton, sonaria en cada cruce)
y media-player (su propia salida ES audio — D-AP2.7, decision del hilo de audio).
2) EMITIR SILENCIO YA NO CUESTA
`SoundChannel.handle` cortaba DESPUES de resolver la firma, asi que un tuning
silenciador levantaba dos osciladores, un filtro y una envolvente programada
para no sonar, en cada interaccion. Ahora corta antes de sintetizar cuando la
ganancia resuelta es <= 0. El corte mira la ganancia RESUELTA, no el tuning, asi
que un intent que la devuelve por encima de 0 (threat, fulfill) suena igual.
Fijado con test propio, verificado en ROJO quitando el corto.
3) EL AFINADO SE NOMBRA POR LA FAMILIA QUE MODIFICA
El catalogo mezclaba tres ejes en el primer segmento —familia (emerge.*,
contact.silent), componente (tooltip.*, tabs.*) y la categoria huerfana form.*—
sin regla declarada y sin guard que mirara. `form.commit.soft/subtle` entro el
2026-05-19 (09e261878, el commit que CREA sounds.ts) nombrando con verdad a
siete controles de formulario; el 2026-05-26, 2d562f378 lo extendio a menus y
arboles en la misma pasada que escribia la doctrina: 7 -> 29 consumidores en un
commit, 50 hoy, de los que exactamente UNO era el Form. El D.6 de ese commit
llego a poner el nombre correcto —commit.select— en la linea que usaba la clave
incorrecta.
form.commit.soft -> commit.soft
form.commit.subtle -> commit.subtle
form.toggle.silent -> commit.silent
tooltip.silent -> emerge.silent
tabs.select.soft -> commit.select.soft
131 ocurrencias en 68 ficheros, dirigido por `git ls-files` — nunca por recorrido
de directorio: hay 3 worktrees vivos y build/ con 449 apariciones mas que un sed
recursivo habria corrompido en silencio.
La cola queda LIBRE a proposito: media-player aplica el silenciador al
commit-set de un slider, no a un toggle — la cola describe la FIRMA, no el
evento, asi que cerrarla contra el vocabulario de verbos fabricaria otra
mentira. Por eso emerge.* no se toca pese a que `exit` no sea verbo canonico.
Quedan tres silenciadores, uno por familia con base audible, con el mismo
nombre: contact.silent (-0.25), commit.silent (-0.3), emerge.silent (-0.2).
Eso convierte la coherencia en INVARIANTE:
- `sounds-grammar.test.ts` (guard nuevo): cabeza ∈ SEMA_FAMILIES; forma
{family}.{tail}; y todo {family}.silent resta EXACTAMENTE el gain base de su
familia, leido de sema-map.ts —nunca copiado—. Verificado en ROJO: el guard
calculo solo el -0.4 esperado de signal.
- Ley escrita en sema.md § Tuning naming shapes, junto a la seccion hermana que
ya legislaba los nombres de EVENTO.
- vocabularies.md —"the ONE place the closed sets are spelled out"— pasa a
enumerar los 14 afinados por familia; el generador los extrae del const y
docs:check vigila su frescura.
- D.5 gana las dos notas: el renombrado y la reversion del silencio.
VERIFICACION: check 75 (linea base exacta) · sema 198/198 · docs:check 0/615 ·
navegador antes/despues (switch 0.0001 -> 0.1; button 0.25 sin tocar) · los 25
avisos de prettier entre lo tocado son deriva YA en HEAD, ninguno mio.
Cronica NO reescrita (4 ficheros): AUDIT-blocks-2026-08-01, PLAN-audio-player,
handoffs-claude-md y audit/components/date-field registran lo que ERA cierto.
DESVIACION DECLARADA: sema/components/chronos.ts entra con 6 sustituciones
mecanicas —chronos es de escritura excluida, pero dejarlo fuera rompia el
type-check del repo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
The pack has BASES (`tick`) and VARIANTS (`tick.threat`). Resolution is two
|
|
|
|
|
|
lookups: `name.intent`, then bare `name`, then silence. So a pack that ships only
|
|
|
|
|
|
bases works whole — the intent is ignored where no variant exists — and a pack
|
|
|
|
|
|
that cares adds variants only where it matters.
|
docs(sema)!: retirar D.7 y S-07 — el orden hace imposible lo que prohibian
F6 del PLAN-sound-names, y el motivo importa mas que el borrado: no se
derogan por cambio de opinion, se DISUELVEN. La doctrina del autor que
las origino sigue siendo cierta; lo que cambia es quien la sostiene.
D.7 prohibia canonizar un sample sobre un evento cuya familia tuviera
base.sound, porque sound() devolvia una firma COMPLETA y la cascada la
aplicaba en replace DESPUES del intent: un fulfill perdia su +300 Hz
ascendente. S-07 era el mismo defecto una capa mas abajo — el gain
desnudo de los 14 afinados de escalera — y seguia ABIERTO por decision
del autor.
Con el nombre aplicado ANTES de los deltas de intent no queda ninguna
capa posterior que pueda pisarlos. Aplastar el perfil evaluativo ya no
esta prohibido: es INEXPRESABLE. Y S-07 pierde su premisa entera, porque
SOUND_TUNINGS ya no existe.
LO QUE SE CONSERVA, con su sitio nuevo escrito: el silencio como firma
valida (SILENT), el criterio de cuando crear un pack, y los samples como
recurso de producto (el catalogo los admite con nombre; la app autora los
suyos por overrides.cascade, que sigue abierto a proposito).
LO UNICO DE D.7 QUE HAY QUE SEGUIR SABIENDO, y por eso queda escrito en
tres sitios: playSample lee EXACTAMENTE dos campos, sampleUrl y gain. No
hay playbackRate ni detune. Sobre un .wav el intent solo mueve el
volumen — medido, risk es indistinguible de neutral porque solo aporta
roughness y la ruta de sample lo ignora. Un sample con carga evaluativa
necesita UN FICHERO POR INTENT, que es lo que hace signal con ping frente
a error y la verdadera razon de que fuese la excepcion. Es fisica del
audio, no politica.
Tocado: book-deviations §D.7 + §S-07 · sema.md §the sound catalogue
(reescrita entera, con el orden y el limite del WAV) · CLAUDE.md §sema
doctrine · los dos README del art · CONTINUE-sema-audit §3.0/§3.1/§3.6,
que es el handoff vivo y estaba describiendo una cola que ya no existe.
⚠️ Prettier reformatea entero book-deviations.md y sema.md porque NO
estaban formateados en HEAD; reaplicado a mano para que el diff sea solo
lo mio. Mismo motivo por el que CLAUDE.md y arts/README.md van con 1-2
lineas en vez de 30.
VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline · docs:check
0/618 · prettier limpio en los ficheros que toque.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
The default pack is **pure synthesis**: it works offline, pays no fetch and
|
|
|
|
|
|
cannot 404. A sample entry (`wav` / `mp3` / `ogg` / `aac`) carries its URL plus a
|
|
|
|
|
|
synthetic FALLBACK, so a missing file degrades to a designed sound rather than to
|
|
|
|
|
|
silence. Whether a name is a recipe or a file is not the component's business.
|
docs(sema)!: retirar D.7 y S-07 — el orden hace imposible lo que prohibian
F6 del PLAN-sound-names, y el motivo importa mas que el borrado: no se
derogan por cambio de opinion, se DISUELVEN. La doctrina del autor que
las origino sigue siendo cierta; lo que cambia es quien la sostiene.
D.7 prohibia canonizar un sample sobre un evento cuya familia tuviera
base.sound, porque sound() devolvia una firma COMPLETA y la cascada la
aplicaba en replace DESPUES del intent: un fulfill perdia su +300 Hz
ascendente. S-07 era el mismo defecto una capa mas abajo — el gain
desnudo de los 14 afinados de escalera — y seguia ABIERTO por decision
del autor.
Con el nombre aplicado ANTES de los deltas de intent no queda ninguna
capa posterior que pueda pisarlos. Aplastar el perfil evaluativo ya no
esta prohibido: es INEXPRESABLE. Y S-07 pierde su premisa entera, porque
SOUND_TUNINGS ya no existe.
LO QUE SE CONSERVA, con su sitio nuevo escrito: el silencio como firma
valida (SILENT), el criterio de cuando crear un pack, y los samples como
recurso de producto (el catalogo los admite con nombre; la app autora los
suyos por overrides.cascade, que sigue abierto a proposito).
LO UNICO DE D.7 QUE HAY QUE SEGUIR SABIENDO, y por eso queda escrito en
tres sitios: playSample lee EXACTAMENTE dos campos, sampleUrl y gain. No
hay playbackRate ni detune. Sobre un .wav el intent solo mueve el
volumen — medido, risk es indistinguible de neutral porque solo aporta
roughness y la ruta de sample lo ignora. Un sample con carga evaluativa
necesita UN FICHERO POR INTENT, que es lo que hace signal con ping frente
a error y la verdadera razon de que fuese la excepcion. Es fisica del
audio, no politica.
Tocado: book-deviations §D.7 + §S-07 · sema.md §the sound catalogue
(reescrita entera, con el orden y el limite del WAV) · CLAUDE.md §sema
doctrine · los dos README del art · CONTINUE-sema-audit §3.0/§3.1/§3.6,
que es el handoff vivo y estaba describiendo una cola que ya no existe.
⚠️ Prettier reformatea entero book-deviations.md y sema.md porque NO
estaban formateados en HEAD; reaplicado a mano para que el diff sea solo
lo mio. Mismo motivo por el que CLAUDE.md y arts/README.md van con 1-2
lineas en vez de 30.
VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline · docs:check
0/618 · prettier limpio en los ficheros que toque.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
feat(sema,sound): un pack se entrega como quieras — y un `data:` no se pide, se descodifica
La entrega deja de ser parte del contrato. Un pack de ficheros puede llegar
como quince URLs o como UN JSON de base64 (`packFromBase64`): mismo tipo, mismo
intercambio en caliente, misma reserva sintética por entrada, y un nombre que
no existe sigue sin compilar. Medido sobre `static/sounds/ui-inline.json`: una
petición en vez de quince, y 69.082 B con brotli frente a 79.332 B de los
ficheros sueltos — el +33 % del base64 lo deshace la compresión, y el JSON gana
además porque nadie comprime `audio/mpeg` y todos comprimen `application/json`.
## `step` no se oía
Era a la vez el MÁS CORTO (18 ms) y el MÁS FLOJO (gain 0.025), y esas dos cosas
se multiplican: el oído integra energía durante ~100-200 ms, así que un tono
corto necesita MÁS amplitud, no menos. Medido, rendía a −29,8 dBFS con la
novena parte de la energía de `touch`. Ahora 0.06 a los mismos 18 ms.
Lo que no había era el guard: la distinguibilidad es una RELACIÓN, y dos
sonidos pueden ser perfectamente distintos entre sí y ser los dos inaudibles.
`sound-names.test.ts` gana un suelo absoluto sobre `gain² × duración`.
## El precalentamiento no precalentaba
- `preload` pedía el contexto con `getOrCreateContext()`, que hace
`await resume()` — y antes del primer gesto esa promesa se queda PENDIENTE en
Chrome, no se rechaza. No descargaba nada hasta que el usuario ya había
pulsado, que es justo la latencia que el preload existe para quitar.
`decodeAudioData` funciona en un contexto suspendido.
- Aplicar un pack en caliente no calentaba la caché: cada nombre pagaba su
viaje la primera vez que sonaba. Ahora `rebuildMap()` llama a `warmSamples()`.
- Con `preferences.sound === 'off'` no se descarga NADA — un pack que no se
puede oír son bytes gastados en silencio. Pero la petición se RECUERDA en vez
de tirarse: el nivel se lee en el dispatch, así que la primera reproducción
audible vacía la cola y encender el sonido no devuelve una caché fría.
## Un `data:` se descodifica en el sitio
`connect-src 'self'` BLOQUEA `fetch('data:…')` — la directiva casa por ESQUEMA
y `'self'` no cubre `data:` — mientras deja pasar una ruta del mismo origen. Un
pack inline enrutado por `fetch` caía a síntesis EN SILENCIO justo en el
entorno que llevó a alguien a hacerlo inline. Y es ~6x más lento. `bytesFor()`
lo resuelve con `atob`.
## De la revisión adversarial
- Las claves del JSON se validan: una que no sea `SoundName` LANZA, igual que
una ruta mala en `assertMapPaths` y por la misma razón — tragarse la errata
da el síntoma «parte de mi pack no se aplicó» sin nada a lo que apuntar.
- `isSoundName` preguntaba `name in SEMA_MAP.sounds`, y `in` recorre el
prototipo: `isSoundName('toString')` devolvía `true`. Inofensivo mientras
todos los llamantes tecleaban el nombre; nada inofensivo al validar red.
- `warmSamples` sólo tenía una de las dos ramas que sí tiene el constructor, así
que una app con canal de sonido propio se calentaba al arrancar y nunca más;
y esa rama leía la preferencia UNA vez, en construcción. Las dos se caían por
lo mismo: ahora comparten `warmUrls()` en vez de duplicarse.
- El demo del catálogo cancela su fetch: elegir `inline` y saltar a `synth`
antes de que llegara reinstalaba el pack sobre un `clearMap()` ya hecho.
- `fallbackFor(name)` borra los dos casts que copiaba todo el que autorase un
pack de ficheros.
## Documentación
`architecture/sema.md` gana la sección de las dos formas de entrega y el
párrafo de `preloadSamples` reescrito — describía un precalentamiento que ya no
es el que ocurre. El README del arte conoce la ruta `data:`. La página de packs
gana su sección equivalente y deja de señalar unos `.wav` sueltos como «el
ejemplo».
Y un fantasma: `soft` no existe — es un nombre del catálogo viejo que quedaba
como ejemplo en ocho sitios, incluido el docstring de `applySounds`, cuyo
ejemplo copiado literalmente LANZABA.
`static/sounds/ui-inline.json` se genera desde `packs/ui-mp3.ts`; el comando
está documentado ahí y reproduce el fichero byte a byte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
##### Two ways to DELIVER a file-based pack
|
|
|
|
|
|
|
|
|
|
|
|
The delivery is not part of the contract. A pack is
|
|
|
|
|
|
`Partial<Record<SoundName, NamedSound>>` either way, hot-swappable either way,
|
|
|
|
|
|
and a name that is not a `SoundName` is a compile error either way.
|
|
|
|
|
|
|
|
|
|
|
|
- **One file per name.** The pack points at URLs (`sample('/sounds/tick.mp3', …)`).
|
|
|
|
|
|
The engine's cache is keyed by URL, so each file is fetched and decoded once;
|
|
|
|
|
|
the browser caches each independently, and `preload: false` on an entry keeps
|
|
|
|
|
|
it out of the warm-up so rare sounds load on demand.
|
|
|
|
|
|
- **One file for the whole pack.** A JSON of base64 payloads keyed by sound
|
|
|
|
|
|
name, turned into a pack by `packFromBase64()` — the entries become `data:`
|
|
|
|
|
|
URIs. Measured on `static/sounds/ui-inline.json`: **one** request instead of
|
|
|
|
|
|
fifteen, and 69.082 B under brotli against 79.332 B for the loose files,
|
|
|
|
|
|
because base64's +33 % is undone by compression while `audio/mpeg` is not
|
|
|
|
|
|
compressed by anyone. The cost is granularity: the pack caches as one object,
|
|
|
|
|
|
so one changed sound re-downloads all of them.
|
|
|
|
|
|
|
|
|
|
|
|
A `data:` URI is decoded IN PLACE — never fetched. A `connect-src 'self'` CSP
|
|
|
|
|
|
BLOCKS `fetch('data:…')` (the directive matches by scheme, and `'self'` does not
|
|
|
|
|
|
cover `data:`) while letting a same-origin path through, so routing an inline
|
|
|
|
|
|
pack through `fetch` made it degrade silently to synthesis in exactly the
|
|
|
|
|
|
environment that made someone inline it. It is also ~6x slower.
|
|
|
|
|
|
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
#### Designed to be told apart
|
docs(sema)!: retirar D.7 y S-07 — el orden hace imposible lo que prohibian
F6 del PLAN-sound-names, y el motivo importa mas que el borrado: no se
derogan por cambio de opinion, se DISUELVEN. La doctrina del autor que
las origino sigue siendo cierta; lo que cambia es quien la sostiene.
D.7 prohibia canonizar un sample sobre un evento cuya familia tuviera
base.sound, porque sound() devolvia una firma COMPLETA y la cascada la
aplicaba en replace DESPUES del intent: un fulfill perdia su +300 Hz
ascendente. S-07 era el mismo defecto una capa mas abajo — el gain
desnudo de los 14 afinados de escalera — y seguia ABIERTO por decision
del autor.
Con el nombre aplicado ANTES de los deltas de intent no queda ninguna
capa posterior que pueda pisarlos. Aplastar el perfil evaluativo ya no
esta prohibido: es INEXPRESABLE. Y S-07 pierde su premisa entera, porque
SOUND_TUNINGS ya no existe.
LO QUE SE CONSERVA, con su sitio nuevo escrito: el silencio como firma
valida (SILENT), el criterio de cuando crear un pack, y los samples como
recurso de producto (el catalogo los admite con nombre; la app autora los
suyos por overrides.cascade, que sigue abierto a proposito).
LO UNICO DE D.7 QUE HAY QUE SEGUIR SABIENDO, y por eso queda escrito en
tres sitios: playSample lee EXACTAMENTE dos campos, sampleUrl y gain. No
hay playbackRate ni detune. Sobre un .wav el intent solo mueve el
volumen — medido, risk es indistinguible de neutral porque solo aporta
roughness y la ruta de sample lo ignora. Un sample con carga evaluativa
necesita UN FICHERO POR INTENT, que es lo que hace signal con ping frente
a error y la verdadera razon de que fuese la excepcion. Es fisica del
audio, no politica.
Tocado: book-deviations §D.7 + §S-07 · sema.md §the sound catalogue
(reescrita entera, con el orden y el limite del WAV) · CLAUDE.md §sema
doctrine · los dos README del art · CONTINUE-sema-audit §3.0/§3.1/§3.6,
que es el handoff vivo y estaba describiendo una cola que ya no existe.
⚠️ Prettier reformatea entero book-deviations.md y sema.md porque NO
estaban formateados en HEAD; reaplicado a mano para que el diff sea solo
lo mio. Mismo motivo por el que CLAUDE.md y arts/README.md van con 1-2
lineas en vez de 30.
VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline · docs:check
0/618 · prettier limpio en los ficheros que toque.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`sound-names.test.ts` fails when two entries are not separated on at least TWO
|
|
|
|
|
|
perceptual axes — a fifth of pitch, a third of brightness, half again as long,
|
|
|
|
|
|
a different contour, double the level, or 0.2 of roughness.
|
|
|
|
|
|
|
|
|
|
|
|
That guard exists because its absence was measured, by ear, by the author: a
|
|
|
|
|
|
previous catalogue had five names that were the same 700 Hz note at five
|
|
|
|
|
|
volumes, and every test passed. A snapshot could not have caught it — each value
|
|
|
|
|
|
was exactly what the table said. **The missing property was a RELATION between
|
|
|
|
|
|
entries**, and that is what the guard asserts.
|
|
|
|
|
|
|
|
|
|
|
|
#### Verbs, not components
|
|
|
|
|
|
|
|
|
|
|
|
Names describe an occurrence, never a widget: `open`, `tick`, `alert`. A library
|
|
|
|
|
|
organised by component (`button_hard`, `panel_expand`, `window_open`) needs
|
|
|
|
|
|
TRANSLATING into this vocabulary, and several of its files will compete for one
|
|
|
|
|
|
name — that is normal, and the choosing is where a pack author's ear works. See
|
|
|
|
|
|
`packs/ui-mp3.ts` for a worked example, including what it could not use.
|
|
|
|
|
|
|
|
|
|
|
|
#### Samples: what a file can and cannot carry
|
docs(sema)!: retirar D.7 y S-07 — el orden hace imposible lo que prohibian
F6 del PLAN-sound-names, y el motivo importa mas que el borrado: no se
derogan por cambio de opinion, se DISUELVEN. La doctrina del autor que
las origino sigue siendo cierta; lo que cambia es quien la sostiene.
D.7 prohibia canonizar un sample sobre un evento cuya familia tuviera
base.sound, porque sound() devolvia una firma COMPLETA y la cascada la
aplicaba en replace DESPUES del intent: un fulfill perdia su +300 Hz
ascendente. S-07 era el mismo defecto una capa mas abajo — el gain
desnudo de los 14 afinados de escalera — y seguia ABIERTO por decision
del autor.
Con el nombre aplicado ANTES de los deltas de intent no queda ninguna
capa posterior que pueda pisarlos. Aplastar el perfil evaluativo ya no
esta prohibido: es INEXPRESABLE. Y S-07 pierde su premisa entera, porque
SOUND_TUNINGS ya no existe.
LO QUE SE CONSERVA, con su sitio nuevo escrito: el silencio como firma
valida (SILENT), el criterio de cuando crear un pack, y los samples como
recurso de producto (el catalogo los admite con nombre; la app autora los
suyos por overrides.cascade, que sigue abierto a proposito).
LO UNICO DE D.7 QUE HAY QUE SEGUIR SABIENDO, y por eso queda escrito en
tres sitios: playSample lee EXACTAMENTE dos campos, sampleUrl y gain. No
hay playbackRate ni detune. Sobre un .wav el intent solo mueve el
volumen — medido, risk es indistinguible de neutral porque solo aporta
roughness y la ruta de sample lo ignora. Un sample con carga evaluativa
necesita UN FICHERO POR INTENT, que es lo que hace signal con ping frente
a error y la verdadera razon de que fuese la excepcion. Es fisica del
audio, no politica.
Tocado: book-deviations §D.7 + §S-07 · sema.md §the sound catalogue
(reescrita entera, con el orden y el limite del WAV) · CLAUDE.md §sema
doctrine · los dos README del art · CONTINUE-sema-audit §3.0/§3.1/§3.6,
que es el handoff vivo y estaba describiendo una cola que ya no existe.
⚠️ Prettier reformatea entero book-deviations.md y sema.md porque NO
estaban formateados en HEAD; reaplicado a mano para que el diff sea solo
lo mio. Mismo motivo por el que CLAUDE.md y arts/README.md van con 1-2
lineas en vez de 30.
VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline · docs:check
0/618 · prettier limpio en los ficheros que toque.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
|
|
|
|
|
`playSample` reads **exactly two** fields of the resolved signature: `sampleUrl`
|
docs: el corpus entero deja de describir un sistema que ya no existe
Tras rehacer el sonido dos veces en un dia, la doctrina escrita seguia
explicando la cascada de cinco capas, los tunings y la modulacion por
intent — exactamente la clase de mentira que esta sesion entera se dedico
a perseguir en el codigo. 23 ficheros al dia.
FUENTES DE DOCTRINA
- `architecture/sema.md` — la seccion de resolucion ya no numera seis
capas para el sonido: enuncia las dos busquedas y dice que el sonido NO
participa de la cascada, que es el diseño. La convencion de deltas se
acota al haptico y a `hold`, que son los unicos que aun tienen numeros.
La seccion del catalogo se reescribe como «el sound pack»: bases y
variantes, el pack por defecto sin binarios, el guard de
distinguibilidad con la razon de por que existe (se detecto por OIDO, no
por test), y por que una biblioteca nombrada por componente hay que
TRADUCIRLA.
- `CANON.md` §7 — la fila del sonido dice ahora «un nombre, y solo cuando
difiere de su familia», y se añade que el intent SELECCIONA, con el
motivo perceptual: reconocemos sonidos, no desplazamientos de parametro.
- `CLAUDE.md` — la doctrina operativa pasa de tres reglas a seis, y todas
enunciadas por su mecanismo: las dos busquedas, que NADIE escribe un
parametro, el tier del verbo que vacia los packs, el guard de
distinguibilidad, el limite fisico de las grabaciones y los gestos por
repeticion.
- `book-deviations` D.7/S-07 — dejan de explicarse por «el nombre va
debajo del intent» (modelo intermedio, tambien muerto) y se explican por
la ausencia de aritmetica. Y D.8 corrige la tabla de canales: `handle`
suena, y los tres resolvers de gesto que la entrada citaba como
justificacion ya no existen.
PROCESO
- `PLAN-sound-names.md` se marca SUPERADO EL MISMO DIA, con la leccion
escrita arriba del todo: un sistema de modulacion produce variantes que
difieren sobre el papel y son identicas al oido, y eso solo se detecta
escuchando. Se conserva como cronica de por que NO se hizo asi.
- `CONTINUE-sema-audit.md` gana §3.0-bis con el modelo vigente, los tres
commits y dos avisos que la siguiente sesion necesita: que nada se ha
oido sobre un componente real, y que el catalogo es una PROPUESTA.
COMPONENTES — 16 READMEs citaban nombres de tuning que ya no existen
(`commit.subtle`, `emerge.exit.soft`, `handle.pickup.air`…). Migrados a los
nombres vivos. ⚠️ Distingui los que eran pares FAMILIA.VERBO
(`commit.set`, `emerge.open`) y esos no se tocan: siguen siendo correctos.
⚠️ `chronos/SPEC.md` lo migre y lo REVERTI al darme cuenta: es de escritura
excluida, asi que sigue citando nombres muertos — decision tuya.
VERIFICADO: docs:check 0/618 · check sin errores nuevos · las unicas
referencias a `SOUND_TUNINGS` que quedan son las de S-07, deliberadas:
citan lo que ya no existe para explicar por que dejo de existir.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
and `gain`. There is no `playbackRate` and no `detune`. So over a recording the
|
|
|
|
|
|
intent can only move the LEVEL.
|
|
|
|
|
|
|
|
|
|
|
|
Consequence, and it is physics rather than policy: **a sample that must carry
|
|
|
|
|
|
evaluative weight needs one file per intent** — `tick.mp3` AND
|
|
|
|
|
|
`tick.threat.mp3`, not one file bent two ways. With synthesis the problem does
|
|
|
|
|
|
not arise, because each variant is designed whole.
|
fix(sema): los toggles recuperan voz, y el silencio deja de sintetizarse — muere el prefijo form.
Tres cosas que el mismo hilo destapo, de la mas visible a la mas de fondo.
1) LOS TOGGLES SUENAN OTRA VEZ (directiva de autor 2026-08-05)
switch, toggle y toggle-group llevaban SILENCIADOS desde el 2026-05-26: su pack
aplicaba un tuning que restaba exactamente el gain base de la familia commit
(0.3 - 0.3 = 0). Medido en navegador: pico 0.0001, el suelo de la rampa. Un
silencio por defecto no se percibe como sobriedad sino como componente roto.
Pasan a `commit.medium` (gain 0.1): audible, y un tercio de una pulsacion de
boton (contact base 0.25) para que un flip no pese mas que una activacion. Los
deltas de intent siguen montando encima (threat +0.1, fulfill +0.05). El
haptico ligero no cambia. Medido despues: switch pico 0.1.
Conservan el silencio, con su justificacion intacta, solo los dos donde el
silencio ES la firma: tooltip (revela al pasar el raton, sonaria en cada cruce)
y media-player (su propia salida ES audio — D-AP2.7, decision del hilo de audio).
2) EMITIR SILENCIO YA NO CUESTA
`SoundChannel.handle` cortaba DESPUES de resolver la firma, asi que un tuning
silenciador levantaba dos osciladores, un filtro y una envolvente programada
para no sonar, en cada interaccion. Ahora corta antes de sintetizar cuando la
ganancia resuelta es <= 0. El corte mira la ganancia RESUELTA, no el tuning, asi
que un intent que la devuelve por encima de 0 (threat, fulfill) suena igual.
Fijado con test propio, verificado en ROJO quitando el corto.
3) EL AFINADO SE NOMBRA POR LA FAMILIA QUE MODIFICA
El catalogo mezclaba tres ejes en el primer segmento —familia (emerge.*,
contact.silent), componente (tooltip.*, tabs.*) y la categoria huerfana form.*—
sin regla declarada y sin guard que mirara. `form.commit.soft/subtle` entro el
2026-05-19 (09e261878, el commit que CREA sounds.ts) nombrando con verdad a
siete controles de formulario; el 2026-05-26, 2d562f378 lo extendio a menus y
arboles en la misma pasada que escribia la doctrina: 7 -> 29 consumidores en un
commit, 50 hoy, de los que exactamente UNO era el Form. El D.6 de ese commit
llego a poner el nombre correcto —commit.select— en la linea que usaba la clave
incorrecta.
form.commit.soft -> commit.soft
form.commit.subtle -> commit.subtle
form.toggle.silent -> commit.silent
tooltip.silent -> emerge.silent
tabs.select.soft -> commit.select.soft
131 ocurrencias en 68 ficheros, dirigido por `git ls-files` — nunca por recorrido
de directorio: hay 3 worktrees vivos y build/ con 449 apariciones mas que un sed
recursivo habria corrompido en silencio.
La cola queda LIBRE a proposito: media-player aplica el silenciador al
commit-set de un slider, no a un toggle — la cola describe la FIRMA, no el
evento, asi que cerrarla contra el vocabulario de verbos fabricaria otra
mentira. Por eso emerge.* no se toca pese a que `exit` no sea verbo canonico.
Quedan tres silenciadores, uno por familia con base audible, con el mismo
nombre: contact.silent (-0.25), commit.silent (-0.3), emerge.silent (-0.2).
Eso convierte la coherencia en INVARIANTE:
- `sounds-grammar.test.ts` (guard nuevo): cabeza ∈ SEMA_FAMILIES; forma
{family}.{tail}; y todo {family}.silent resta EXACTAMENTE el gain base de su
familia, leido de sema-map.ts —nunca copiado—. Verificado en ROJO: el guard
calculo solo el -0.4 esperado de signal.
- Ley escrita en sema.md § Tuning naming shapes, junto a la seccion hermana que
ya legislaba los nombres de EVENTO.
- vocabularies.md —"the ONE place the closed sets are spelled out"— pasa a
enumerar los 14 afinados por familia; el generador los extrae del const y
docs:check vigila su frescura.
- D.5 gana las dos notas: el renombrado y la reversion del silencio.
VERIFICACION: check 75 (linea base exacta) · sema 198/198 · docs:check 0/615 ·
navegador antes/despues (switch 0.0001 -> 0.1; button 0.25 sin tocar) · los 25
avisos de prettier entre lo tocado son deriva YA en HEAD, ninguno mio.
Cronica NO reescrita (4 ficheros): AUDIT-blocks-2026-08-01, PLAN-audio-player,
handoffs-claude-md y audit/components/date-field registran lo que ERA cierto.
DESVIACION DECLARADA: sema/components/chronos.ts entra con 6 sustituciones
mecanicas —chronos es de escritura excluida, pero dejarlo fuera rompia el
type-check del repo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
docs(sema)!: retirar D.7 y S-07 — el orden hace imposible lo que prohibian
F6 del PLAN-sound-names, y el motivo importa mas que el borrado: no se
derogan por cambio de opinion, se DISUELVEN. La doctrina del autor que
las origino sigue siendo cierta; lo que cambia es quien la sostiene.
D.7 prohibia canonizar un sample sobre un evento cuya familia tuviera
base.sound, porque sound() devolvia una firma COMPLETA y la cascada la
aplicaba en replace DESPUES del intent: un fulfill perdia su +300 Hz
ascendente. S-07 era el mismo defecto una capa mas abajo — el gain
desnudo de los 14 afinados de escalera — y seguia ABIERTO por decision
del autor.
Con el nombre aplicado ANTES de los deltas de intent no queda ninguna
capa posterior que pueda pisarlos. Aplastar el perfil evaluativo ya no
esta prohibido: es INEXPRESABLE. Y S-07 pierde su premisa entera, porque
SOUND_TUNINGS ya no existe.
LO QUE SE CONSERVA, con su sitio nuevo escrito: el silencio como firma
valida (SILENT), el criterio de cuando crear un pack, y los samples como
recurso de producto (el catalogo los admite con nombre; la app autora los
suyos por overrides.cascade, que sigue abierto a proposito).
LO UNICO DE D.7 QUE HAY QUE SEGUIR SABIENDO, y por eso queda escrito en
tres sitios: playSample lee EXACTAMENTE dos campos, sampleUrl y gain. No
hay playbackRate ni detune. Sobre un .wav el intent solo mueve el
volumen — medido, risk es indistinguible de neutral porque solo aporta
roughness y la ruta de sample lo ignora. Un sample con carga evaluativa
necesita UN FICHERO POR INTENT, que es lo que hace signal con ping frente
a error y la verdadera razon de que fuese la excepcion. Es fisica del
audio, no politica.
Tocado: book-deviations §D.7 + §S-07 · sema.md §the sound catalogue
(reescrita entera, con el orden y el limite del WAV) · CLAUDE.md §sema
doctrine · los dos README del art · CONTINUE-sema-audit §3.0/§3.1/§3.6,
que es el handoff vivo y estaba describiendo una cola que ya no existe.
⚠️ Prettier reformatea entero book-deviations.md y sema.md porque NO
estaban formateados en HEAD; reaplicado a mano para que el diff sea solo
lo mio. Mismo motivo por el que CLAUDE.md y arts/README.md van con 1-2
lineas en vez de 30.
VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline · docs:check
0/618 · prettier limpio en los ficheros que toque.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
#### Silence is a value, not a name
|
fix(sema): el silencio deja de ser una resta y pasa a ser un valor — SILENT
Directiva del autor: «el silencio no admite verbos ni intents, es universal,
por lo tanto es un valor canonico que cuando se le envia al canal semantico
este simplemente lo ignora y no envia nada al soundengine».
LO QUE ERA. `commit.silent`, `emerge.silent` y `contact.silent` no eran
silencio: eran una RESTA del gain base de su familia (-0.3, -0.2, -0.25). Por
eso hacian falta tres —cada una tenia que saber que base cancelaba— y por eso
el silencio tenia familia, que es el absurdo que el autor senalo. Y un cero es
un NUMERO, y las capas posteriores mueven numeros.
LA MEDICION QUE LO CIERRA. Los deltas de intent suman RUGOSIDAD (`risk` +0.2,
`threat` +0.4), lo que cruza el umbral del AM del motor; y el modulador se
conecta al AudioParam de la envolvente —y conectar a un AudioParam SUMA, no
multiplica—, asi que con la envolvente en cero el tremolo pasaba a ser la senal
entera. Renderizado offline con el grafo real del motor:
toggle "silenciado" neutral -77.0 dBFS (mudo de verdad)
toggle "silenciado" risk -13.9 dBFS <- con gain declarado 0
toggle "silenciado" threat -6.7 dBFS
boton normal, referencia -9.3 dBFS
El "silencio" era mas fuerte que un boton, y lo que sonaba no era el earcon:
era un zumbido sin ataque ni caida, cortado en seco. La medicion que yo mismo
di por buena esta manana (0.0001) solo cubria el caso neutral.
LO QUE ES AHORA. `SILENT` — un valor canonico exportado por `$uix/sema`. Se
declara en el slice del canal y el RESOLVER lo honra retirando ese canal de la
firma. Un solo mecanismo para todos los canales, y nada aguas abajo ve jamas un
string donde espera una firma. Es la forma que el propio motor ya prescribia y
se estaba saltando: «muting DROPS the channel rather than scaling to zero,
because a `0` still buzzes» (engine.ts).
- universal por construccion: ninguna familia, ningun verbo, ningun intent
puede resucitarlo, porque no queda ningun numero que mover;
- liftable solo por REEMPLAZO: declarar sonido es una decision, no un delta;
- `SoundOverride` lo EXCLUYE por tipo — un afinado es un delta, nunca una
ausencia.
Migrado: tooltip (1) y media-player (6). Los tres tunings mueren del catalogo.
GUARDS. `resolver.test.ts` fija las cuatro mitades del contrato (retira el
canal · universal sobre 4 familias x 4 intents · vale igual para haptic ·
liftable por reemplazo), verificado en ROJO. `sounds-grammar.test.ts` cambia su
invariante muerta por las dos que ahora importan: ninguna clave `*.silent`, y
ningun afinado que deje su familia en `gain <= 0` — silencio disfrazado.
Doctrina al dia: sema.md gana la seccion «Silence is a value, not a tuning» con
la medicion; D.5 marca DEROGADA su solucion de mayo y registra el porque;
vocabularies.md deja de enumerar silenciadores y explica donde vive el silencio.
VERIFICADO: sema 211/211 · check 76 = la base 75 + 1 error del fichero huerfano
`__adv-verify-haptic-dead.test.ts` que dejo un agente de la auditoria (sin
trackear, no se borra sin instruccion) · docs:check 0/616 · navegador: el
transporte del player EMITE (`contact-activate`, `commit-toggle-play`) y
levanta CERO osciladores · prettier limpio (el unico aviso mio, resolver.ts,
formateado: +17 lineas, sin ruido).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
|
|
|
|
|
`SILENT` is THE canonical silence — one value for the whole system, exported
|
|
|
|
|
|
from `$uix/sema`. Set a channel slice to it and **the channel that owns the
|
|
|
|
|
|
slice ignores it and dispatches nothing downstream**: no signature is
|
|
|
|
|
|
resolved, no engine is called, no context is opened.
|
|
|
|
|
|
|
|
|
|
|
|
It admits no family, no verb and no intent, because there is nothing to
|
|
|
|
|
|
modulate. That is why it is not a key: a per-family silencer would need to
|
|
|
|
|
|
know which base it is cancelling, which is how the catalogue ended up with
|
|
|
|
|
|
three of them.
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
// a pack rule that does not speak in sound
|
|
|
|
|
|
{ selector: onProvider({ eventName: 'emerge-open' }), sound: SILENT }
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Absorbing by construction.** Intent deltas do not apply on top of `SILENT`
|
|
|
|
|
|
(layer 2 cannot un-silence). A later override CAN lift it by REPLACING the
|
|
|
|
|
|
slice with a full signature — declaring sound is a decision, not a delta.
|
|
|
|
|
|
|
|
|
|
|
|
**Why it is a value and not a zero.** Until 2026-08-06 silence was arithmetic:
|
|
|
|
|
|
`{family}.silent` subtracted the family's base gain so neutral landed at 0.
|
|
|
|
|
|
A zero gain is a NUMBER, and later layers move numbers. Measured on a
|
|
|
|
|
|
"silenced" toggle: an intent delta that raises `roughness` past the AM
|
|
|
|
|
|
threshold (`risk` +0.2, `threat` +0.4) turned the signature into a raw tremolo
|
|
|
|
|
|
at **−13.9 dBFS** (`risk`) and **−6.7 dBFS** (`threat`) — louder than a real
|
|
|
|
|
|
button press at −9.3. The engine had already written the rule it was breaking:
|
|
|
|
|
|
*«muting DROPS the channel rather than scaling to zero, because a `0` still
|
|
|
|
|
|
buzzes»* (`engine.ts`).
|
|
|
|
|
|
|
|
|
|
|
|
The grammar and the ban on silence-as-arithmetic are enforced by
|
|
|
|
|
|
`src/uix/sema/sounds-grammar.test.ts`, which reads the families from `event.ts`
|
|
|
|
|
|
and the base gains from `sema-map.ts` rather than restating them; the runtime
|
|
|
|
|
|
half (`SILENT` reaches no engine) is pinned in `chans/sound.test.ts`. The guard
|
|
|
|
|
|
exists because `form.*` named seven form controls truthfully on 2026-05-19, was
|
|
|
|
|
|
extended to menus and trees a week later, and reached 50 packs — one of which
|
|
|
|
|
|
was the Form — before anyone noticed, since no check ever looked at these keys.
|
fix(sema): los toggles recuperan voz, y el silencio deja de sintetizarse — muere el prefijo form.
Tres cosas que el mismo hilo destapo, de la mas visible a la mas de fondo.
1) LOS TOGGLES SUENAN OTRA VEZ (directiva de autor 2026-08-05)
switch, toggle y toggle-group llevaban SILENCIADOS desde el 2026-05-26: su pack
aplicaba un tuning que restaba exactamente el gain base de la familia commit
(0.3 - 0.3 = 0). Medido en navegador: pico 0.0001, el suelo de la rampa. Un
silencio por defecto no se percibe como sobriedad sino como componente roto.
Pasan a `commit.medium` (gain 0.1): audible, y un tercio de una pulsacion de
boton (contact base 0.25) para que un flip no pese mas que una activacion. Los
deltas de intent siguen montando encima (threat +0.1, fulfill +0.05). El
haptico ligero no cambia. Medido despues: switch pico 0.1.
Conservan el silencio, con su justificacion intacta, solo los dos donde el
silencio ES la firma: tooltip (revela al pasar el raton, sonaria en cada cruce)
y media-player (su propia salida ES audio — D-AP2.7, decision del hilo de audio).
2) EMITIR SILENCIO YA NO CUESTA
`SoundChannel.handle` cortaba DESPUES de resolver la firma, asi que un tuning
silenciador levantaba dos osciladores, un filtro y una envolvente programada
para no sonar, en cada interaccion. Ahora corta antes de sintetizar cuando la
ganancia resuelta es <= 0. El corte mira la ganancia RESUELTA, no el tuning, asi
que un intent que la devuelve por encima de 0 (threat, fulfill) suena igual.
Fijado con test propio, verificado en ROJO quitando el corto.
3) EL AFINADO SE NOMBRA POR LA FAMILIA QUE MODIFICA
El catalogo mezclaba tres ejes en el primer segmento —familia (emerge.*,
contact.silent), componente (tooltip.*, tabs.*) y la categoria huerfana form.*—
sin regla declarada y sin guard que mirara. `form.commit.soft/subtle` entro el
2026-05-19 (09e261878, el commit que CREA sounds.ts) nombrando con verdad a
siete controles de formulario; el 2026-05-26, 2d562f378 lo extendio a menus y
arboles en la misma pasada que escribia la doctrina: 7 -> 29 consumidores en un
commit, 50 hoy, de los que exactamente UNO era el Form. El D.6 de ese commit
llego a poner el nombre correcto —commit.select— en la linea que usaba la clave
incorrecta.
form.commit.soft -> commit.soft
form.commit.subtle -> commit.subtle
form.toggle.silent -> commit.silent
tooltip.silent -> emerge.silent
tabs.select.soft -> commit.select.soft
131 ocurrencias en 68 ficheros, dirigido por `git ls-files` — nunca por recorrido
de directorio: hay 3 worktrees vivos y build/ con 449 apariciones mas que un sed
recursivo habria corrompido en silencio.
La cola queda LIBRE a proposito: media-player aplica el silenciador al
commit-set de un slider, no a un toggle — la cola describe la FIRMA, no el
evento, asi que cerrarla contra el vocabulario de verbos fabricaria otra
mentira. Por eso emerge.* no se toca pese a que `exit` no sea verbo canonico.
Quedan tres silenciadores, uno por familia con base audible, con el mismo
nombre: contact.silent (-0.25), commit.silent (-0.3), emerge.silent (-0.2).
Eso convierte la coherencia en INVARIANTE:
- `sounds-grammar.test.ts` (guard nuevo): cabeza ∈ SEMA_FAMILIES; forma
{family}.{tail}; y todo {family}.silent resta EXACTAMENTE el gain base de su
familia, leido de sema-map.ts —nunca copiado—. Verificado en ROJO: el guard
calculo solo el -0.4 esperado de signal.
- Ley escrita en sema.md § Tuning naming shapes, junto a la seccion hermana que
ya legislaba los nombres de EVENTO.
- vocabularies.md —"the ONE place the closed sets are spelled out"— pasa a
enumerar los 14 afinados por familia; el generador los extrae del const y
docs:check vigila su frescura.
- D.5 gana las dos notas: el renombrado y la reversion del silencio.
VERIFICACION: check 75 (linea base exacta) · sema 198/198 · docs:check 0/615 ·
navegador antes/despues (switch 0.0001 -> 0.1; button 0.25 sin tocar) · los 25
avisos de prettier entre lo tocado son deriva YA en HEAD, ninguno mio.
Cronica NO reescrita (4 ficheros): AUDIT-blocks-2026-08-01, PLAN-audio-player,
handoffs-claude-md y audit/components/date-field registran lo que ERA cierto.
DESVIACION DECLARADA: sema/components/chronos.ts entra con 6 sustituciones
mecanicas —chronos es de escritura excluida, pero dejarlo fuera rompia el
type-check del repo.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
### Channels and signatures
|
|
|
|
|
|
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
| Channel | Consumed slice | Behavior when not applicable |
|
|
|
|
|
|
| -------- | ------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
|
|
|
|
| `visual` | `effective.hold` for the hold | Falls back to the family table (SEMA_DURATIONS) or `defaultHold` |
|
|
|
|
|
|
| `sound` | `effective.sound` (skips if `'sound'` not in activeChannels) | no-op |
|
|
|
|
|
|
| `haptic` | `effective.haptic` (Vibration API, honors `prefers-reduced-motion`) | no-op if there is no `navigator.vibrate` |
|
|
|
|
|
|
| (custom) | declaration merging of `SemaChannelSignatures` | read by the registered channel |
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
### The visual channel's attr namespace
|
|
|
|
|
|
|
|
|
|
|
|
`VisualChannel.prepare()` projects **only** attributes under the
|
|
|
|
|
|
`data-event-*` prefix:
|
|
|
|
|
|
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
| Attr | When |
|
|
|
|
|
|
| ---------------------- | --------------------- |
|
|
|
|
|
|
| `data-event` | always |
|
|
|
|
|
|
| `data-event-id` | always |
|
|
|
|
|
|
| `data-event-phase` | always (`'active'`) |
|
|
|
|
|
|
| `data-event-family` | if `signal.family` |
|
|
|
|
|
|
| `data-event-intent` | if `signal.intent` |
|
|
|
|
|
|
| `data-event-direction` | if `signal.direction` |
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
**Rule**: the channel never touches state attrs (`data-state`,
|
|
|
|
|
|
`data-intent`, `data-disabled`, ...). State is managed by the runtime/morfo.
|
|
|
|
|
|
Reason: state is persistent and a signal is transient; reusing the same name
|
|
|
|
|
|
would force the channel to erase state on cleanup (or into fragile
|
|
|
|
|
|
save/restore if state mutates during the hold).
|
|
|
|
|
|
|
|
|
|
|
|
For CSS:
|
|
|
|
|
|
|
|
|
|
|
|
- `[data-event-intent='risk']` → reacts to the transient occurrence's intent
|
|
|
|
|
|
- `[data-intent='risk']` → reacts to the component's persistent state
|
|
|
|
|
|
|
|
|
|
|
|
Both can coexist on the same element with distinct semantics.
|
|
|
|
|
|
|
|
|
|
|
|
### Hold — the visual channel's resolution chain
|
|
|
|
|
|
|
|
|
|
|
|
The `VisualChannel` resolves its `hold` (how long the `data-event-*` live in
|
|
|
|
|
|
the DOM) in this order:
|
|
|
|
|
|
|
|
|
|
|
|
1. `signal.hold` — imperative per-call override.
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
2. `effective.hold` — composed by the resolver from
|
|
|
|
|
|
`resolveHoldsByIntent(family, intent)` (`holds.ts`,
|
|
|
|
|
|
`SEMA_HOLDS_BY_INTENT` — the ONE canonical hold source; the per-family
|
|
|
|
|
|
`SEMA_MAP.families[*].hold` field was REMOVED 2026-07-06 because it
|
|
|
|
|
|
duplicated this table and had drifted from the book's regions).
|
|
|
|
|
|
3. The same canonical table, consulted directly by the channel — defense
|
|
|
|
|
|
when a custom map's resolver path didn't compose a hold.
|
|
|
|
|
|
4. The channel's global `defaultHold` (`brief`, 240ms by default).
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
See `holds.ts` (`SEMA_HOLDS_BY_INTENT`) for the concrete family+intent values.
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
**The hold timer runs on the managed scheduler, not on raw `setTimeout`.**
|
|
|
|
|
|
The engine receives `timers` (in `ActiveUix` it is `uix.timers`) and forwards
|
|
|
|
|
|
it to the three channels: the `VisualChannel`'s hold, the `HapticChannel`'s
|
|
|
|
|
|
`delay` and the `SoundChannel`'s earcon duration are scheduled via
|
|
|
|
|
|
`uix.timers.schedule(...)` (the `semaDelay` helper in
|
|
|
|
|
|
`src/uix/sema/timers.ts`). That makes perceptual timing cancelable on
|
|
|
|
|
|
`dispose`, observable, and deterministic under a fake clock in tests. It only
|
|
|
|
|
|
falls back to `setTimeout` when a channel is built without a scheduler
|
|
|
|
|
|
(direct unit tests); production always injects the scheduler.
|
|
|
|
|
|
|
|
|
|
|
|
> **Overlay openings — `sequence: 'post'`, not `'pre'`.** An appearance event
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
> whose provider sets `open` in the HANDLER (Popover, Dialog and Drawer's
|
|
|
|
|
|
> `emerge-open`) MUST declare `sequence: 'post'`. With `'pre'` the
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
> runtime awaits the emit — and therefore the ~240ms hold — BEFORE the
|
|
|
|
|
|
> handler, gating the content mount behind the hold: the overlay opens late
|
|
|
|
|
|
> and its first render lands inside the hold's `setTimeout` turn (the
|
|
|
|
|
|
> "setTimeout handler took N ms" violation). Same doctrine as the
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
> checkbox-lag fix. Closing (`emerge-close`) stays `'pre'`: there the element exists
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
> and the signal MUST precede the unmount.
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
// Per-signal override
|
|
|
|
|
|
semantic.emit({ ..., hold: 1200 })
|
|
|
|
|
|
|
|
|
|
|
|
// Override the visual channel's global default
|
|
|
|
|
|
const semantic = new EngineSemantic({ dom, visual: { defaultHold: 400 } })
|
|
|
|
|
|
|
|
|
|
|
|
// Disable visual (DOM-less environments)
|
|
|
|
|
|
const semantic = new EngineSemantic({ visual: false })
|
|
|
|
|
|
|
|
|
|
|
|
// Enable the built-in sound channel (opt-in: audible side effect)
|
|
|
|
|
|
const semantic = new EngineSemantic({ dom, sound: true })
|
|
|
|
|
|
|
|
|
|
|
|
// With SoundChannel options
|
|
|
|
|
|
const semantic = new EngineSemantic({
|
|
|
|
|
|
dom,
|
|
|
|
|
|
sound: { masterGain: 0.6 }
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Enable the built-in haptic channel (opt-in: device feedback)
|
|
|
|
|
|
const semantic = new EngineSemantic({ dom, haptic: true })
|
|
|
|
|
|
|
|
|
|
|
|
// With HapticChannel options
|
|
|
|
|
|
const semantic = new EngineSemantic({
|
|
|
|
|
|
dom,
|
|
|
|
|
|
haptic: { masterIntensity: 0.7 }
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Register custom channels (a11y, voice, future)
|
|
|
|
|
|
class A11yChannel implements Channel {
|
|
|
|
|
|
readonly id = 'a11y'
|
|
|
|
|
|
async handle(signal, effective) { /* live-region updates, etc. */ }
|
|
|
|
|
|
}
|
|
|
|
|
|
semantic.register(new A11yChannel())
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Override layers — recipes
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
import { dialogSema } from '$uix/sema/components/dialog';
|
|
|
|
|
|
|
|
|
|
|
|
const semantic = new EngineSemantic({
|
|
|
|
|
|
dom,
|
|
|
|
|
|
sound: true,
|
|
|
|
|
|
haptic: true,
|
|
|
|
|
|
|
|
|
|
|
|
// Layer 5a — component packs (defaults shipped with each component)
|
|
|
|
|
|
components: [dialogSema /* , toastSema, drawerSema, … */],
|
|
|
|
|
|
|
|
|
|
|
|
overrides: {
|
|
|
|
|
|
// Layer 4 — targeted SEMA_MAP edits, valid app-wide
|
|
|
|
|
|
runtime: {
|
|
|
|
|
|
'families.commit.base.sound.pitch': 850,
|
|
|
|
|
|
'intents.threat.deltas.haptic.intensity': 0.4
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// Layer 5b — app CSS-like rules, matched against signal.target
|
|
|
|
|
|
// AFTER the component packs
|
|
|
|
|
|
cascade: [
|
|
|
|
|
|
{
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
// Typed builder here too — `ancestor` carries the instance id
|
|
|
|
|
|
// (it lives outside the morfo's contract: plain string by design).
|
|
|
|
|
|
selector: semaSelector(dialogMorfo, 'content', {
|
|
|
|
|
|
eventIntent: 'threat',
|
|
|
|
|
|
ancestor: '#delete-confirm-dialog'
|
|
|
|
|
|
}),
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
sound: { sampleUrl: '/sounds/scary.wav', gain: 0.25 },
|
|
|
|
|
|
haptic: { kind: 'error', pattern: [50, 80, 50, 80, 50] }
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
// Targets NO morfo-emitted attr (a global reduce gate over the
|
|
|
|
|
|
// engine's own `data-event-*` stamps) — legitimately hand-written;
|
|
|
|
|
|
// the builder mandate covers morfo-targeting selectors only.
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
selector: ':root[data-sound="reduce"] [data-event-phase="active"]',
|
|
|
|
|
|
priority: 100,
|
|
|
|
|
|
sound: { gain: 0.05 },
|
|
|
|
|
|
channels: ['sound']
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
// Layer 3 — per-event override declared in the component's own morfo.
|
|
|
|
|
|
// Propagates via SomaRuntime → SemanticSignal → resolver. The app can
|
|
|
|
|
|
// still override from the cascade (layers 5a/5b).
|
|
|
|
|
|
|
|
|
|
|
|
// src/uix/morfo/components/dialog.ts
|
|
|
|
|
|
{
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
name: 'signal-alert-close-fail',
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
semantic: {
|
|
|
|
|
|
family: 'signal',
|
|
|
|
|
|
verb: 'alert',
|
|
|
|
|
|
target: v.partRef('content'),
|
|
|
|
|
|
sequence: 'pre',
|
|
|
|
|
|
intent: 'threat',
|
|
|
|
|
|
// Per-event silencing: no sound, to avoid competing with the live region
|
|
|
|
|
|
channels: ['haptic'],
|
|
|
|
|
|
// Per-event override: the Dialog's own sample
|
|
|
|
|
|
overrides: {
|
|
|
|
|
|
haptic: { kind: 'error', pattern: [60, 80, 60, 80, 60] }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Specificity between rules
|
|
|
|
|
|
|
|
|
|
|
|
Like CSS:
|
|
|
|
|
|
|
|
|
|
|
|
- **Computed selector specificity** — IDs × 100, attributes × 10, classes ×
|
|
|
|
|
|
10, pseudo-classes × 10, elements × 1.
|
|
|
|
|
|
- **Rules apply in ascending specificity order** — the last applied wins each
|
|
|
|
|
|
pointwise conflict.
|
|
|
|
|
|
- **Tie** → declaration order. Component packs appear BEFORE
|
|
|
|
|
|
`overrides.cascade`, so app rules win ties.
|
|
|
|
|
|
- **`priority?: number`** — overrides the computed value for cases that must
|
|
|
|
|
|
win without counting attributes (typically accessibility, `priority: 100+`).
|
|
|
|
|
|
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
To vary by event, intent, family, name, etc. — everything goes through the
|
|
|
|
|
|
typed builder's matchers, which stamp the `[data-event-*]` tokens. (The
|
|
|
|
|
|
hand-written examples this section used to show targeted `[data-toast-root]`
|
|
|
|
|
|
— a part that never existed in the toast morfo: exactly the silent drift
|
|
|
|
|
|
`semaSelector` turns into a compile error.)
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
// Vary by the event's intent
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
{ selector: semaSelector(toastMorfo, 'item', { eventIntent: 'threat' }), haptic: { kind: 'error' } }
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
// Vary by family
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
{ selector: semaSelector(toastMorfo, 'item', { eventFamily: 'signal' }), sound: { gain: 0.4 } }
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
// Vary by exact event name (typed against the morfo's declared events)
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
{ selector: semaSelector(toastMorfo, 'item', { eventName: 'emerge-dismiss' }), sound: { sampleUrl: '/dismiss.wav' } }
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
// Vary by event prefix
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
{ selector: semaSelector(dialogMorfo, 'content', { eventNamePrefix: 'emerge-close' }), sound: { contour: 'descending' } }
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
```
|
|
|
|
|
|
|
refactor(sound): extraer el motor Web Audio de sema al art `$sound`
`sema/chans/sound.ts` tenía 407 líneas de las que ~255 (≈63%) eran maquinaria
Web Audio —ciclo de vida del AudioContext, síntesis, samples, desbloqueo por
gesto— mezclada con doctrina perceptiva. Deuda arrastrada, con tres síntomas
medidos: el import era estático, así que toda app con sema metía el
sintetizador en el bundle aunque el sonido estuviera apagado (que es el
default); faltaba ciudadanía que `$scene` ya resuelve; y la costura de
inyección (`audioContextFactory`) llevaba ahí sin usar desde el principio.
Mismo movimiento que `$motion` hizo desde eidos: el art se lleva el RUNTIME, la
capa conserva sus DATOS y su doctrina.
- `$sound` / `EngineSound`: UN AudioContext por documento (los navegadores los
limitan y el gesto de desbloqueo es por contexto), síntesis de earcon,
samples con caché y fallback a síntesis, `autoSuspend` OPT-IN —suspender con
la pestaña oculta es correcto para earcons y erróneo para contenido, así que
es decisión de quien compone— y aviso cuando un segundo contexto va vivo.
Puertos `SoundDom` / `SoundTimers` inyectados; no importa ningún otro art ni
nada de `$uix/sema`, que es la prueba objetiva del corte.
- `SoundChannel`: 407 → 136 líneas. Solo doctrina: el gate de `prepare`, la
política de reducción y el reparto «el canal resuelve el NIVEL, el motor
aplica la ganancia». Sema no gana ni un import: recibe el motor por puerto.
- `uix.sound` en standalone y attach con `ownsSound` (idioma ya shipped:
`ownsMotion` / `ownsScene`), fila `sound` en la tabla ejecutable
`contracts.ts`, y `defineEngineSound()` para el camino de app.
- Tests nuevos: `engine-sound.test.ts` (11), `sound-port.test.ts` (guard de
deriva de tipos + la regla de propiedad) y `sound-e2e.test.ts`, que recorre
`emit -> cascada -> canal -> art -> grafo real`: el camino que las 16 suites
previas no cubrían porque paraban en canales falsos.
Sin `diagnostics.ts` ni `errors.ts`, y es decisión: espejo de `$scene`, aquí
todo fallo es degradación documentada, no error de programador.
Verificación: 17 suites / 198 tests · `check` en la baseline exacta (73
errores, 0 propios) · `sound.test.ts` verde SIN tocar un solo assert, que era
el criterio de que el movimiento fue value-preserving.
Planes: `PLAN-sound-engine.md` (completo, con el registro de la revisión
adversarial E-1..E-7), `PLAN-audio-player.md` (aparcado tras el análisis del
reproductor, con sus correcciones en cabecera) y `CONTINUE-sound-engine.md`
(handoff).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
### SoundChannel — doctrine here, machine in `$sound`
|
|
|
|
|
|
|
|
|
|
|
|
> **The Web Audio machinery does NOT live in sema** (since 2026-07-30). The
|
|
|
|
|
|
> context lifecycle, the synthesis graph, the unlock-on-gesture and the sample
|
|
|
|
|
|
> path were extracted to the art [`$sound`](../../src/arts/sound/README.md)
|
|
|
|
|
|
> (`EngineSound`) — they were ~63% of a 407-line "channel" and are machinery,
|
|
|
|
|
|
> not perceptual doctrine. Same move `$motion` made out of eidos, for the same
|
|
|
|
|
|
> reason and with the same result: the art owns the RUNTIME, the layer keeps its
|
|
|
|
|
|
> DATA and doctrine.
|
|
|
|
|
|
|
|
|
|
|
|
What the channel keeps — all of it doctrine:
|
|
|
|
|
|
|
|
|
|
|
|
- the `prepare` gate (does this signal admit sound at all?),
|
|
|
|
|
|
- the per-channel reduction policy (BK-REDUCTIONS): `off` silences (meaning
|
|
|
|
|
|
migrates via `SEMA_MIGRATION.sound` → presence / live region), `reduce`
|
|
|
|
|
|
attenuates,
|
feat(sound): $sound orquestador (buses+voces+media) y player v2 F1-F3 sobre el servicio
Rediseno clean-room del sonido (gate D-SR.1-12 firmado; la doctrina "la voz
es del art" de PLAN-sound-engine s16.1 queda revocada):
- Mezcla: master -> buses ui/content (gain/mute/duck refcount, gana la mas
fuerte; politica pre-contexto). prefs de UI jamas tocan la obra.
- Voces registradas: la calibracion es DATO del consumidor (sema registra
'sema'; el default conserva la calibracion historica - cero cambio audible,
A/B del usuario: "suena igual").
- Ciudadania de media: sound.media(el) PROVEE el transporte (la forma exacta
del puerto MediaProvider) + foco mixed/exclusive/duck PERSISTENTE (estado
derivado; el ducker mas reciente retiene la palabra) + duckUiWhileContent +
MediaSession de la fuente activa (play/pause/seekto + posicion, liberacion
y promocion) + visibilidad content-aware + attach() opt-in (irreversible,
CORS declarado). Re-registro idempotente por elemento.
- diagnostics.ts con catalogo tipado (contrato de arts) y guards post-dispose
(ningun camino abre un contexto huerfano). Auditoria AU-1..9 resuelta;
bundle medido: 16,2 KB min / 5,6 KB gz.
Player v2 (gate D-AP2.1-13 firmado) F1-F3:
- F1 gaps de framework: aria-valuetext en Slider (valueText por thumb) +
parte SecondaryRange con token --slider-secondary-bg (buffer/clip/capitulos)
+ formatDuration en $libs/days + fix del selector del pack (H-1: la regla
de play/pause construia sobre provider y el stamp aterriza en play-button).
- F2 morfo: 6 partes audio-only (artwork/artist/identity/transport/
rate-button/live-indicator), commit-set-rate, commit-set-time RETIRADO
(D-AP2.13: el scrubber delega en el commit-set del Slider compuesto),
sustain-loading cableado (H-9), teclado j/l, </> y 0-9 (con guard de
modificadores para no pisar atajos del navegador).
- F3 la migracion: el transporte default es uix.sound.media(el, {metadata})
(pineado con el motor real); nativeMediaProvider RETIRADO (media-provider.ts
queda como contrato puro del puerto, sin shim); G-5: los commits de
play/mute/rate cabalgan el evento de RESULTADO (play/pause saltando el
pause de ended, volumechange con transicion de muted, ratechange);
formatTime -> formatDuration; sub-providers + wrappers + exports de las 6
partes; prop metadata publica (captura al registrar, documentado).
Verificacion: 45 suites / 458 tests verdes en el alcance (sound, sema,
active-uix, active-app, morfo, slider, media-player, days) - check 74 =
baseline de la rama, 0 propios - docs:check 0 - invariante de UN AudioContext
intacta (e2e sin tocar). Planes de proceso y handoff al dia
(PLAN-sound-redesign, PLAN-audio-player-v2, CONTINUE-sound-engine).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
- **its voice** — `SEMA_SOUND_VOICE` in `sounds.ts`, the synthesis calibration
|
|
|
|
|
|
sema's vocabulary was tuned against, registered on the engine at channel
|
|
|
|
|
|
construction (redesign 2026-07-31, D-SR.3 in `PLAN-sound-redesign.md`; it was
|
|
|
|
|
|
baked into the art as constants before). Earcons play on the engine's **`ui`
|
|
|
|
|
|
bus** with that voice — so UI-sound policy (BK-REDUCTIONS, resolved here and
|
|
|
|
|
|
handed over as `gainScale`) can never touch the content's volume; the `ui`
|
|
|
|
|
|
bus itself is the art's graph-side lever, with no direct prefs wiring today,
|
refactor(sound): extraer el motor Web Audio de sema al art `$sound`
`sema/chans/sound.ts` tenía 407 líneas de las que ~255 (≈63%) eran maquinaria
Web Audio —ciclo de vida del AudioContext, síntesis, samples, desbloqueo por
gesto— mezclada con doctrina perceptiva. Deuda arrastrada, con tres síntomas
medidos: el import era estático, así que toda app con sema metía el
sintetizador en el bundle aunque el sonido estuviera apagado (que es el
default); faltaba ciudadanía que `$scene` ya resuelve; y la costura de
inyección (`audioContextFactory`) llevaba ahí sin usar desde el principio.
Mismo movimiento que `$motion` hizo desde eidos: el art se lleva el RUNTIME, la
capa conserva sus DATOS y su doctrina.
- `$sound` / `EngineSound`: UN AudioContext por documento (los navegadores los
limitan y el gesto de desbloqueo es por contexto), síntesis de earcon,
samples con caché y fallback a síntesis, `autoSuspend` OPT-IN —suspender con
la pestaña oculta es correcto para earcons y erróneo para contenido, así que
es decisión de quien compone— y aviso cuando un segundo contexto va vivo.
Puertos `SoundDom` / `SoundTimers` inyectados; no importa ningún otro art ni
nada de `$uix/sema`, que es la prueba objetiva del corte.
- `SoundChannel`: 407 → 136 líneas. Solo doctrina: el gate de `prepare`, la
política de reducción y el reparto «el canal resuelve el NIVEL, el motor
aplica la ganancia». Sema no gana ni un import: recibe el motor por puerto.
- `uix.sound` en standalone y attach con `ownsSound` (idioma ya shipped:
`ownsMotion` / `ownsScene`), fila `sound` en la tabla ejecutable
`contracts.ts`, y `defineEngineSound()` para el camino de app.
- Tests nuevos: `engine-sound.test.ts` (11), `sound-port.test.ts` (guard de
deriva de tipos + la regla de propiedad) y `sound-e2e.test.ts`, que recorre
`emit -> cascada -> canal -> art -> grafo real`: el camino que las 16 suites
previas no cubrían porque paraban en canales falsos.
Sin `diagnostics.ts` ni `errors.ts`, y es decisión: espejo de `$scene`, aquí
todo fallo es degradación documentada, no error de programador.
Verificación: 17 suites / 198 tests · `check` en la baseline exacta (73
errores, 0 propios) · `sound.test.ts` verde SIN tocar un solo assert, que era
el criterio de que el movimiento fue value-preserving.
Planes: `PLAN-sound-engine.md` (completo, con el registro de la revisión
adversarial E-1..E-7), `PLAN-audio-player.md` (aparcado tras el análisis del
reproductor, con sus correcciones en cabecera) y `CONTINUE-sound-engine.md`
(handoff).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
- and the division of labour: **the channel resolves the LEVEL, the engine
|
|
|
|
|
|
applies the gain**.
|
|
|
|
|
|
|
docs(sema)!: retirar D.7 y S-07 — el orden hace imposible lo que prohibian
F6 del PLAN-sound-names, y el motivo importa mas que el borrado: no se
derogan por cambio de opinion, se DISUELVEN. La doctrina del autor que
las origino sigue siendo cierta; lo que cambia es quien la sostiene.
D.7 prohibia canonizar un sample sobre un evento cuya familia tuviera
base.sound, porque sound() devolvia una firma COMPLETA y la cascada la
aplicaba en replace DESPUES del intent: un fulfill perdia su +300 Hz
ascendente. S-07 era el mismo defecto una capa mas abajo — el gain
desnudo de los 14 afinados de escalera — y seguia ABIERTO por decision
del autor.
Con el nombre aplicado ANTES de los deltas de intent no queda ninguna
capa posterior que pueda pisarlos. Aplastar el perfil evaluativo ya no
esta prohibido: es INEXPRESABLE. Y S-07 pierde su premisa entera, porque
SOUND_TUNINGS ya no existe.
LO QUE SE CONSERVA, con su sitio nuevo escrito: el silencio como firma
valida (SILENT), el criterio de cuando crear un pack, y los samples como
recurso de producto (el catalogo los admite con nombre; la app autora los
suyos por overrides.cascade, que sigue abierto a proposito).
LO UNICO DE D.7 QUE HAY QUE SEGUIR SABIENDO, y por eso queda escrito en
tres sitios: playSample lee EXACTAMENTE dos campos, sampleUrl y gain. No
hay playbackRate ni detune. Sobre un .wav el intent solo mueve el
volumen — medido, risk es indistinguible de neutral porque solo aporta
roughness y la ruta de sample lo ignora. Un sample con carga evaluativa
necesita UN FICHERO POR INTENT, que es lo que hace signal con ping frente
a error y la verdadera razon de que fuese la excepcion. Es fisica del
audio, no politica.
Tocado: book-deviations §D.7 + §S-07 · sema.md §the sound catalogue
(reescrita entera, con el orden y el limite del WAV) · CLAUDE.md §sema
doctrine · los dos README del art · CONTINUE-sema-audit §3.0/§3.1/§3.6,
que es el handoff vivo y estaba describiendo una cola que ya no existe.
⚠️ Prettier reformatea entero book-deviations.md y sema.md porque NO
estaban formateados en HEAD; reaplicado a mano para que el diff sea solo
lo mio. Mismo motivo por el que CLAUDE.md y arts/README.md van con 1-2
lineas en vez de 30.
VERIFICADO: sema+morfo+sound 437/437 · check 75 = baseline · docs:check
0/618 · prettier limpio en los ficheros que toque.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
Everything else — `SOUNDS` (the named catalogue), the gesture resolvers, the
|
refactor(sound): extraer el motor Web Audio de sema al art `$sound`
`sema/chans/sound.ts` tenía 407 líneas de las que ~255 (≈63%) eran maquinaria
Web Audio —ciclo de vida del AudioContext, síntesis, samples, desbloqueo por
gesto— mezclada con doctrina perceptiva. Deuda arrastrada, con tres síntomas
medidos: el import era estático, así que toda app con sema metía el
sintetizador en el bundle aunque el sonido estuviera apagado (que es el
default); faltaba ciudadanía que `$scene` ya resuelve; y la costura de
inyección (`audioContextFactory`) llevaba ahí sin usar desde el principio.
Mismo movimiento que `$motion` hizo desde eidos: el art se lleva el RUNTIME, la
capa conserva sus DATOS y su doctrina.
- `$sound` / `EngineSound`: UN AudioContext por documento (los navegadores los
limitan y el gesto de desbloqueo es por contexto), síntesis de earcon,
samples con caché y fallback a síntesis, `autoSuspend` OPT-IN —suspender con
la pestaña oculta es correcto para earcons y erróneo para contenido, así que
es decisión de quien compone— y aviso cuando un segundo contexto va vivo.
Puertos `SoundDom` / `SoundTimers` inyectados; no importa ningún otro art ni
nada de `$uix/sema`, que es la prueba objetiva del corte.
- `SoundChannel`: 407 → 136 líneas. Solo doctrina: el gate de `prepare`, la
política de reducción y el reparto «el canal resuelve el NIVEL, el motor
aplica la ganancia». Sema no gana ni un import: recibe el motor por puerto.
- `uix.sound` en standalone y attach con `ownsSound` (idioma ya shipped:
`ownsMotion` / `ownsScene`), fila `sound` en la tabla ejecutable
`contracts.ts`, y `defineEngineSound()` para el camino de app.
- Tests nuevos: `engine-sound.test.ts` (11), `sound-port.test.ts` (guard de
deriva de tipos + la regla de propiedad) y `sound-e2e.test.ts`, que recorre
`emit -> cascada -> canal -> art -> grafo real`: el camino que las 16 suites
previas no cubrían porque paraban en canales falsos.
Sin `diagnostics.ts` ni `errors.ts`, y es decisión: espejo de `$scene`, aquí
todo fallo es degradación documentada, no error de programador.
Verificación: 17 suites / 198 tests · `check` en la baseline exacta (73
errores, 0 propios) · `sound.test.ts` verde SIN tocar un solo assert, que era
el criterio de que el movimiento fue value-preserving.
Planes: `PLAN-sound-engine.md` (completo, con el registro de la revisión
adversarial E-1..E-7), `PLAN-audio-player.md` (aparcado tras el análisis del
reproductor, con sus correcciones en cabecera) y `CONTINUE-sound-engine.md`
(handoff).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
cascade — is unchanged and still sema's.
|
|
|
|
|
|
|
|
|
|
|
|
**How it reaches the engine.** `EngineSemantic` takes a `soundEngine` option and
|
fix(sound): la invariante de un solo AudioContext, cerrada en attach y medida
`PLAN-sound-engine` daba por cableada la propiedad del motor «en los dos modos
de arranque». En attach no lo estaba: `defineUixServices` registraba `motion` y
`scene` junto a `dom` pero NO `sound`, y `defineEngineSemantic` no reenviaba
`soundEngine`. Una app en attach con sonido activo tenía el motor privado del
canal MÁS `uix.sound` — dos motores, y dos contextos en cuanto el reproductor
primase el suyo. `attachActiveUix` DOCUMENTABA el footgun en un comentario en
vez de cerrarlo, mientras `contracts.ts` ya prometía `singleContextPerDocument`.
- `defineUixServices` declara `sound` junto a `motion` / `scene`, y
`defineEngineSemantic` lo toma como `serviceDependencies: ['dom', 'sound']` y
lo reenvía. Degrada igual que `dom`: sin el servicio declarado llega
`undefined` y el canal vuelve a crear el suyo (construcción directa y tests).
- La nota de `attachActiveUix` pasa de describir el footgun a describir el
cierre, y deja escrito el único caso que sigue vivo: un esquema de servicios
a mano que declare `events` sin `sound`.
- Fila `events` de `contracts.ts` con `serviceDependencies`, y el assert DERIVA
de la tabla en vez de hardcodearla — que es lo que su propia doctrina pide.
- El estudio de sema (`/temas/sema`) enchufa `uix.sound`. Era la única página
capaz de ejercitar la inyección y no lo hacía.
MEDIDO en Chrome, no deducido. Con el motor privado, cada edición del draft
reconstruye el `EngineSemantic`, el `dispose()` del canal cierra el contexto y
el siguiente disparo abre otro: 9 ediciones dejaron **10 contextos creados y 9
cerrados**, perdiendo además la caché de samples decodificados en cada una. Con
el motor compartido: **1 contexto, 0 cierres**, y 24 osciladores construidos en
6 ciclos — el earcon sigue vivo.
Dos guards, y los dos VISTOS FALLAR sin el cableado. Es la lección de la
retirada de F2, donde una medición vacua se presentó como prueba:
- `active-uix.svelte.test.ts`: el `events` de la app prima el motor de la app
(quitando el reenvío: `expected null not to be null`).
- `sound-e2e.test.ts`: un motor inyectado sobrevive a 3 reconstrucciones con UN
contexto y sin `close()`; sólo lo cierra quien lo creó.
Verificación: `client` 130/130 · 842/842 · `server` 262/264 · 3718/3722 — los 3
rojos son ajenos (`aura`, `menubar`, `radio-group`) y el cuarto fue un timeout
de `soma-attr-audit` por contención, verde aislado en 3,1 s · `check` en la
baseline exacta (73 errores, 0 propios).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
forwards it. Both boot modes fill it without the integrator doing anything:
|
|
|
|
|
|
standalone `ActiveUix` creates the engine and passes it in (exposing it as
|
|
|
|
|
|
`uix.sound`); in attach, `defineEngineSemantic()` declares `sound` as a service
|
docs(process): el motor cierra sus fases y abre 5 hallazgos; el player, al gate
`PLAN-sound-engine` pasa a CERRADO (F0…F5) y `PLAN-audio-player` a DESBLOQUEADO.
Pero cerrar las fases no es dejar el diseño incuestionado, así que el plan gana
una auditoría propia que lo contradice donde toca.
- **§15 — la invariante, cerrada y medida.** Incluye lo que la medición
DESMINTIÓ: el handoff anterior predecía un aviso por consola en `/temas/sema`
que no podía aparecer, porque el aviso cuenta contextos VIVOS y allí sólo
había uno. Y **E-8**, el agujero de attach que E-1 dio por cableado sin estarlo.
- **§16 — 5 hallazgos ABIERTOS sobre el art**, tres con decisión pendiente:
`analyze.ts` sigue abriendo su contexto (medido 1 → 2 al importar un `.wav`);
el aviso de segundo contexto es ciego a los contextos crudos; **S-1 NO está
cerrado** y §7 afirmaba lo contrario —queda tachado en su sitio—; el canal tira
en silencio `masterGain` y compañía cuando le inyectan el motor; y `gainScale`,
que es de UNA reproducción, se escribe en el master compartido.
- **§16.1 — la pregunta de fondo**: el corte separa módulos, **no conocimiento**.
La quinta a 1.5×, el ADSR recortado a 15 %/40 %, el contour de ±400 cents y el
mapeo de `roughness` son diseño sonoro calibrado contra el vocabulario de sema,
viviendo dentro de lo que el plan llama «maquinaria». El precedente de
`$motion` —datos en la capa, mecanismos en el art— no se replica tan de cerca
como §3 afirma. Y la superficie no sirve a dos de los tres consumidores que la
justificaban: `Waveform` y el analizador necesitan los `AudioBuffer`, y
`preload(urls)` los esconde en una caché privada.
- **`sema.md` corregido**: «sema no importa el art» era cierto para la INSTANCIA
y falso para el grafo de módulos.
- **`PLAN-audio-player` con las 5 correcciones de su cabecera incorporadas al
cuerpo**, que era la condición para presentar nada: segmentos en la matriz §2 y
en el contrato §7.5; **G-2 sube a bloqueante** (buffer, ventana de clip,
capítulos); las dos invariantes de §7.6 (`prefs.sound` NUNCA toca el volumen
del contenido; el silencio de UI debe alcanzar al `Slider` compuesto).
**D-AP.11 escrita contra el art** —su premisa, «no hay motor», era falsa— y
**D-AP.12** (segmentos `clip`) añadida; las dos existían como referencia sin
fila en §4. **D-AP.7 reescrita** como ducking.
- El handoff añade dos reglas que costaron caro: **un guard que no has visto
fallar no vale**, y acoplarse al dev server vivo del usuario en vez de
levantar otro.
D-AP.1…D-AP.12 siguen SIN FIRMAR: el gate es lo primero de F0 y no se escribe una
línea de código del player antes.
`docs:check` deja 1 error ajeno (`blocks/banner/README.md:15`, «8 roles» por 9).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
dependency and forwards whatever `defineUixServices()` registered. The engine
|
|
|
|
|
|
arrives as a structural port, the `MotionDom` / `SceneDom` pattern — sema never
|
|
|
|
|
|
reaches for it. (**Precision**: the *instance* is injected, but the module graph
|
|
|
|
|
|
is not free of the art — `chans/sound.ts` imports `createEngineSound` as a value
|
|
|
|
|
|
for the private-engine fallback, so an app that builds an `EngineSemantic` still
|
|
|
|
|
|
bundles the synthesizer with sound off. See `PLAN-sound-engine.md` §16.)
|
|
|
|
|
|
Without an injected engine the channel creates a private one and owns
|
refactor(sound): extraer el motor Web Audio de sema al art `$sound`
`sema/chans/sound.ts` tenía 407 líneas de las que ~255 (≈63%) eran maquinaria
Web Audio —ciclo de vida del AudioContext, síntesis, samples, desbloqueo por
gesto— mezclada con doctrina perceptiva. Deuda arrastrada, con tres síntomas
medidos: el import era estático, así que toda app con sema metía el
sintetizador en el bundle aunque el sonido estuviera apagado (que es el
default); faltaba ciudadanía que `$scene` ya resuelve; y la costura de
inyección (`audioContextFactory`) llevaba ahí sin usar desde el principio.
Mismo movimiento que `$motion` hizo desde eidos: el art se lleva el RUNTIME, la
capa conserva sus DATOS y su doctrina.
- `$sound` / `EngineSound`: UN AudioContext por documento (los navegadores los
limitan y el gesto de desbloqueo es por contexto), síntesis de earcon,
samples con caché y fallback a síntesis, `autoSuspend` OPT-IN —suspender con
la pestaña oculta es correcto para earcons y erróneo para contenido, así que
es decisión de quien compone— y aviso cuando un segundo contexto va vivo.
Puertos `SoundDom` / `SoundTimers` inyectados; no importa ningún otro art ni
nada de `$uix/sema`, que es la prueba objetiva del corte.
- `SoundChannel`: 407 → 136 líneas. Solo doctrina: el gate de `prepare`, la
política de reducción y el reparto «el canal resuelve el NIVEL, el motor
aplica la ganancia». Sema no gana ni un import: recibe el motor por puerto.
- `uix.sound` en standalone y attach con `ownsSound` (idioma ya shipped:
`ownsMotion` / `ownsScene`), fila `sound` en la tabla ejecutable
`contracts.ts`, y `defineEngineSound()` para el camino de app.
- Tests nuevos: `engine-sound.test.ts` (11), `sound-port.test.ts` (guard de
deriva de tipos + la regla de propiedad) y `sound-e2e.test.ts`, que recorre
`emit -> cascada -> canal -> art -> grafo real`: el camino que las 16 suites
previas no cubrían porque paraban en canales falsos.
Sin `diagnostics.ts` ni `errors.ts`, y es decisión: espejo de `$scene`, aquí
todo fallo es degradación documentada, no error de programador.
Verificación: 17 suites / 198 tests · `check` en la baseline exacta (73
errores, 0 propios) · `sound.test.ts` verde SIN tocar un solo assert, que era
el criterio de que el movimiento fue value-preserving.
Planes: `PLAN-sound-engine.md` (completo, con el registro de la revisión
adversarial E-1..E-7), `PLAN-audio-player.md` (aparcado tras el análisis del
reproductor, con sus correcciones en cabecera) y `CONTINUE-sound-engine.md`
(handoff).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
its lifecycle — *whoever creates, disposes*; a shared engine is never closed by
|
fix(sound): la invariante de un solo AudioContext, cerrada en attach y medida
`PLAN-sound-engine` daba por cableada la propiedad del motor «en los dos modos
de arranque». En attach no lo estaba: `defineUixServices` registraba `motion` y
`scene` junto a `dom` pero NO `sound`, y `defineEngineSemantic` no reenviaba
`soundEngine`. Una app en attach con sonido activo tenía el motor privado del
canal MÁS `uix.sound` — dos motores, y dos contextos en cuanto el reproductor
primase el suyo. `attachActiveUix` DOCUMENTABA el footgun en un comentario en
vez de cerrarlo, mientras `contracts.ts` ya prometía `singleContextPerDocument`.
- `defineUixServices` declara `sound` junto a `motion` / `scene`, y
`defineEngineSemantic` lo toma como `serviceDependencies: ['dom', 'sound']` y
lo reenvía. Degrada igual que `dom`: sin el servicio declarado llega
`undefined` y el canal vuelve a crear el suyo (construcción directa y tests).
- La nota de `attachActiveUix` pasa de describir el footgun a describir el
cierre, y deja escrito el único caso que sigue vivo: un esquema de servicios
a mano que declare `events` sin `sound`.
- Fila `events` de `contracts.ts` con `serviceDependencies`, y el assert DERIVA
de la tabla en vez de hardcodearla — que es lo que su propia doctrina pide.
- El estudio de sema (`/temas/sema`) enchufa `uix.sound`. Era la única página
capaz de ejercitar la inyección y no lo hacía.
MEDIDO en Chrome, no deducido. Con el motor privado, cada edición del draft
reconstruye el `EngineSemantic`, el `dispose()` del canal cierra el contexto y
el siguiente disparo abre otro: 9 ediciones dejaron **10 contextos creados y 9
cerrados**, perdiendo además la caché de samples decodificados en cada una. Con
el motor compartido: **1 contexto, 0 cierres**, y 24 osciladores construidos en
6 ciclos — el earcon sigue vivo.
Dos guards, y los dos VISTOS FALLAR sin el cableado. Es la lección de la
retirada de F2, donde una medición vacua se presentó como prueba:
- `active-uix.svelte.test.ts`: el `events` de la app prima el motor de la app
(quitando el reenvío: `expected null not to be null`).
- `sound-e2e.test.ts`: un motor inyectado sobrevive a 3 reconstrucciones con UN
contexto y sin `close()`; sólo lo cierra quien lo creó.
Verificación: `client` 130/130 · 842/842 · `server` 262/264 · 3718/3722 — los 3
rojos son ajenos (`aura`, `menubar`, `radio-group`) y el cuarto fue un timeout
de `soma-attr-audit` por contención, verde aislado en 3,1 s · `check` en la
baseline exacta (73 errores, 0 propios).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
a consumer. That last rule is what lets a page rebuild its `EngineSemantic`
|
|
|
|
|
|
freely: the sema studio does it on every draft edit, and the context survives.
|
refactor(sound): extraer el motor Web Audio de sema al art `$sound`
`sema/chans/sound.ts` tenía 407 líneas de las que ~255 (≈63%) eran maquinaria
Web Audio —ciclo de vida del AudioContext, síntesis, samples, desbloqueo por
gesto— mezclada con doctrina perceptiva. Deuda arrastrada, con tres síntomas
medidos: el import era estático, así que toda app con sema metía el
sintetizador en el bundle aunque el sonido estuviera apagado (que es el
default); faltaba ciudadanía que `$scene` ya resuelve; y la costura de
inyección (`audioContextFactory`) llevaba ahí sin usar desde el principio.
Mismo movimiento que `$motion` hizo desde eidos: el art se lleva el RUNTIME, la
capa conserva sus DATOS y su doctrina.
- `$sound` / `EngineSound`: UN AudioContext por documento (los navegadores los
limitan y el gesto de desbloqueo es por contexto), síntesis de earcon,
samples con caché y fallback a síntesis, `autoSuspend` OPT-IN —suspender con
la pestaña oculta es correcto para earcons y erróneo para contenido, así que
es decisión de quien compone— y aviso cuando un segundo contexto va vivo.
Puertos `SoundDom` / `SoundTimers` inyectados; no importa ningún otro art ni
nada de `$uix/sema`, que es la prueba objetiva del corte.
- `SoundChannel`: 407 → 136 líneas. Solo doctrina: el gate de `prepare`, la
política de reducción y el reparto «el canal resuelve el NIVEL, el motor
aplica la ganancia». Sema no gana ni un import: recibe el motor por puerto.
- `uix.sound` en standalone y attach con `ownsSound` (idioma ya shipped:
`ownsMotion` / `ownsScene`), fila `sound` en la tabla ejecutable
`contracts.ts`, y `defineEngineSound()` para el camino de app.
- Tests nuevos: `engine-sound.test.ts` (11), `sound-port.test.ts` (guard de
deriva de tipos + la regla de propiedad) y `sound-e2e.test.ts`, que recorre
`emit -> cascada -> canal -> art -> grafo real`: el camino que las 16 suites
previas no cubrían porque paraban en canales falsos.
Sin `diagnostics.ts` ni `errors.ts`, y es decisión: espejo de `$scene`, aquí
todo fallo es degradación documentada, no error de programador.
Verificación: 17 suites / 198 tests · `check` en la baseline exacta (73
errores, 0 propios) · `sound.test.ts` verde SIN tocar un solo assert, que era
el criterio de que el movimiento fue value-preserving.
Planes: `PLAN-sound-engine.md` (completo, con el registro de la revisión
adversarial E-1..E-7), `PLAN-audio-player.md` (aparcado tras el análisis del
reproductor, con sus correcciones en cabecera) y `CONTINUE-sound-engine.md`
(handoff).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
|
|
|
|
|
|
**Why one engine matters.** Browsers cap concurrent `AudioContext`s and the
|
|
|
|
|
|
autoplay unlock gesture is per-context, so a second context leaves one of the
|
|
|
|
|
|
two mute. An app that also plays content (a media player, a waveform) must take
|
|
|
|
|
|
`uix.sound` — or pass `soundEngine` to its own `EngineSemantic` — instead of
|
|
|
|
|
|
opening its own. The art warns when a second context goes live.
|
|
|
|
|
|
|
|
|
|
|
|
Behaviour, unchanged by the extraction:
|
|
|
|
|
|
|
|
|
|
|
|
- **Prepare-time priming**, no constructor side effect: the context is created +
|
|
|
|
|
|
resumed in `prepare()` when the signal admits `sound`, synchronously inside
|
|
|
|
|
|
the user gesture.
|
|
|
|
|
|
- The unlock listener (`pointerdown` / `mousedown` / `click` / `touchstart` /
|
|
|
|
|
|
`keydown`) is registered only AFTER the context exists, through the injected
|
|
|
|
|
|
DOM surface. An engine that never plays installs no global listeners.
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
- Synthesis: two oscillators (sine + a fifth) → biquad lowpass (centroid) →
|
fix(sound): la rugosidad pasa a ser un tremolo EN SERIE — deja de sumarse a la envolvente
Conectar un nodo a un AudioParam SUMA a su automatizacion; no la escala. El
modulador de AM colgaba de `envelope.gain`, asi que su profundidad se mantenia
CONSTANTE mientras la envolvente se movia: el tremolo ni crecia con el ataque
ni moria con la caida, y alli donde la automatizacion bajaba de la profundidad
el parametro CRUZABA CERO — modulacion en anillo, no tremolo.
MEDIDO con render offline del grafo real, viejo contra nuevo:
caso cuerpo RMS cola PICO corte
A commit neutral (control) 0.242 -> 0.242 0.149 -> 0.149 0.0002 (igual)
B signal neutral 0.332 -> 0.275 0.145 -> 0.088 0.0666 -> 0.0002
C commit + risk 0.243 -> 0.200 0.263 -> 0.103 ~0
D commit.subtle + threat 0.143 -> 0.018 0.333 -> 0.009 ~0
- B: el clic del cierre de cada aviso/error desaparece (x333 menos amplitud en
el corte). Era el tick audible al final de TODOS los earcons de `signal`.
- C: la cola dejaba +76% de pico sobre el control; ahora muere por debajo, que
es lo que una cola debe hacer. El sustain no se toca (ahi el tremolo ES el
percepto de rugosidad buscado).
- D: el caso grave. `commit.subtle` (gain 0.03) cargado con `threat`
(roughness 0.5) salia a RMS 0.143 — SIETE VECES su nivel declarado, con
inversiones de polaridad. Ahora sale a 0.018, su nivel de diseño. Escenario
real: un item de menu destructivo con intent="threat".
- A: el control sin AM no se mueve ni un digito. El fix no toca lo que no debe.
LA FORMA. Etapa de ganancia en serie entre el filtro y la envolvente, con
valor base `1 - depth` y el modulador sobre su propio `.gain`: el factor es
`(1 - depth) + depth*sin`, que hace pico en 1 —el tremolo nunca ANADE nivel— y
multiplica la envolvente, asi que silencio por cualquier cosa es silencio.
`depth` clampeada a 0.5 para que `1 - 2*depth >= 0`: invertir polaridad es otro
efecto. Y deja de escalarse por `gainScale`: siendo un ratio ya es relativa por
construccion, que es justo lo que el comentario viejo perseguia a mano
(«scaling both keeps the timbre and only moves the volume»).
CONTRAPARTIDA DECLARADA: los earcons con rugosidad bajan 1.6-2.7 dB de nivel
medio (B: -1.6 dB de cuerpo, -2.7 dB de pico), porque el AM ya no suma nivel.
Es correccion, no perdida — pero es un cambio perceptual real en la familia
`signal` y en todo `risk`/`threat`. Si el autor quiere recalibrar los gains
base, es una decision de catalogo aparte.
GUARD. `engine-sound.test.ts` sustituye el test que fijaba la propiedad vieja
(la profundidad escalada por gainScale) por el que fija la invariante que de
verdad importa: NADA puede conectarse al AudioParam de la envolvente, y la
etapa en serie vale `1 - depth`. Verificado en ROJO (al reconectar el modulador
a `envelope.gain` falla con su mensaje). El fallo colateral que aparecio al
hacerlo —el test de la voz desconocida avisando dos veces— era cascada: al
fallar el assert no corre `dispose()`, el AudioContext queda vivo y el
siguiente test recibe el aviso de «segundo contexto».
Doctrina: `sema.md` (sintesis) y `arts/sound/README.md` (voces) describen ahora
la etapa en serie y por que nunca se parchea un modulador sobre `envelope.gain`.
VERIFICADO: sonido + sema 244/244 · check 76 = base 75 + 1 del fichero huerfano
`__adv-verify-haptic-dead.test.ts` (sin trackear, sin borrar sin instruccion) ·
docs:check 0/616 · el dev server sirve el fix (comprobado por fetch del modulo)
· prettier: los dos ficheros eran limpios en HEAD y quedan limpios.
Cierra el hallazgo S-06 de AUDIT-sema-2026-08-05.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`roughness > 0.2` inserts a tremolo stage → ADSR-lite envelope; `contour`
|
refactor(sound): extraer el motor Web Audio de sema al art `$sound`
`sema/chans/sound.ts` tenía 407 líneas de las que ~255 (≈63%) eran maquinaria
Web Audio —ciclo de vida del AudioContext, síntesis, samples, desbloqueo por
gesto— mezclada con doctrina perceptiva. Deuda arrastrada, con tres síntomas
medidos: el import era estático, así que toda app con sema metía el
sintetizador en el bundle aunque el sonido estuviera apagado (que es el
default); faltaba ciudadanía que `$scene` ya resuelve; y la costura de
inyección (`audioContextFactory`) llevaba ahí sin usar desde el principio.
Mismo movimiento que `$motion` hizo desde eidos: el art se lleva el RUNTIME, la
capa conserva sus DATOS y su doctrina.
- `$sound` / `EngineSound`: UN AudioContext por documento (los navegadores los
limitan y el gesto de desbloqueo es por contexto), síntesis de earcon,
samples con caché y fallback a síntesis, `autoSuspend` OPT-IN —suspender con
la pestaña oculta es correcto para earcons y erróneo para contenido, así que
es decisión de quien compone— y aviso cuando un segundo contexto va vivo.
Puertos `SoundDom` / `SoundTimers` inyectados; no importa ningún otro art ni
nada de `$uix/sema`, que es la prueba objetiva del corte.
- `SoundChannel`: 407 → 136 líneas. Solo doctrina: el gate de `prepare`, la
política de reducción y el reparto «el canal resuelve el NIVEL, el motor
aplica la ganancia». Sema no gana ni un import: recibe el motor por puerto.
- `uix.sound` en standalone y attach con `ownsSound` (idioma ya shipped:
`ownsMotion` / `ownsScene`), fila `sound` en la tabla ejecutable
`contracts.ts`, y `defineEngineSound()` para el camino de app.
- Tests nuevos: `engine-sound.test.ts` (11), `sound-port.test.ts` (guard de
deriva de tipos + la regla de propiedad) y `sound-e2e.test.ts`, que recorre
`emit -> cascada -> canal -> art -> grafo real`: el camino que las 16 suites
previas no cubrían porque paraban en canales falsos.
Sin `diagnostics.ts` ni `errors.ts`, y es decisión: espejo de `$scene`, aquí
todo fallo es degradación documentada, no error de programador.
Verificación: 17 suites / 198 tests · `check` en la baseline exacta (73
errores, 0 propios) · `sound.test.ts` verde SIN tocar un solo assert, que era
el criterio de que el movimiento fue value-preserving.
Planes: `PLAN-sound-engine.md` (completo, con el registro de la revisión
adversarial E-1..E-7), `PLAN-audio-player.md` (aparcado tras el análisis del
reproductor, con sus correcciones en cabecera) y `CONTINUE-sound-engine.md`
(handoff).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
(`flat` / `ascending` / `descending` / `arc` / `bell`) rides `osc.detune`.
|
fix(sound): la rugosidad pasa a ser un tremolo EN SERIE — deja de sumarse a la envolvente
Conectar un nodo a un AudioParam SUMA a su automatizacion; no la escala. El
modulador de AM colgaba de `envelope.gain`, asi que su profundidad se mantenia
CONSTANTE mientras la envolvente se movia: el tremolo ni crecia con el ataque
ni moria con la caida, y alli donde la automatizacion bajaba de la profundidad
el parametro CRUZABA CERO — modulacion en anillo, no tremolo.
MEDIDO con render offline del grafo real, viejo contra nuevo:
caso cuerpo RMS cola PICO corte
A commit neutral (control) 0.242 -> 0.242 0.149 -> 0.149 0.0002 (igual)
B signal neutral 0.332 -> 0.275 0.145 -> 0.088 0.0666 -> 0.0002
C commit + risk 0.243 -> 0.200 0.263 -> 0.103 ~0
D commit.subtle + threat 0.143 -> 0.018 0.333 -> 0.009 ~0
- B: el clic del cierre de cada aviso/error desaparece (x333 menos amplitud en
el corte). Era el tick audible al final de TODOS los earcons de `signal`.
- C: la cola dejaba +76% de pico sobre el control; ahora muere por debajo, que
es lo que una cola debe hacer. El sustain no se toca (ahi el tremolo ES el
percepto de rugosidad buscado).
- D: el caso grave. `commit.subtle` (gain 0.03) cargado con `threat`
(roughness 0.5) salia a RMS 0.143 — SIETE VECES su nivel declarado, con
inversiones de polaridad. Ahora sale a 0.018, su nivel de diseño. Escenario
real: un item de menu destructivo con intent="threat".
- A: el control sin AM no se mueve ni un digito. El fix no toca lo que no debe.
LA FORMA. Etapa de ganancia en serie entre el filtro y la envolvente, con
valor base `1 - depth` y el modulador sobre su propio `.gain`: el factor es
`(1 - depth) + depth*sin`, que hace pico en 1 —el tremolo nunca ANADE nivel— y
multiplica la envolvente, asi que silencio por cualquier cosa es silencio.
`depth` clampeada a 0.5 para que `1 - 2*depth >= 0`: invertir polaridad es otro
efecto. Y deja de escalarse por `gainScale`: siendo un ratio ya es relativa por
construccion, que es justo lo que el comentario viejo perseguia a mano
(«scaling both keeps the timbre and only moves the volume»).
CONTRAPARTIDA DECLARADA: los earcons con rugosidad bajan 1.6-2.7 dB de nivel
medio (B: -1.6 dB de cuerpo, -2.7 dB de pico), porque el AM ya no suma nivel.
Es correccion, no perdida — pero es un cambio perceptual real en la familia
`signal` y en todo `risk`/`threat`. Si el autor quiere recalibrar los gains
base, es una decision de catalogo aparte.
GUARD. `engine-sound.test.ts` sustituye el test que fijaba la propiedad vieja
(la profundidad escalada por gainScale) por el que fija la invariante que de
verdad importa: NADA puede conectarse al AudioParam de la envolvente, y la
etapa en serie vale `1 - depth`. Verificado en ROJO (al reconectar el modulador
a `envelope.gain` falla con su mensaje). El fallo colateral que aparecio al
hacerlo —el test de la voz desconocida avisando dos veces— era cascada: al
fallar el assert no corre `dispose()`, el AudioContext queda vivo y el
siguiente test recibe el aviso de «segundo contexto».
Doctrina: `sema.md` (sintesis) y `arts/sound/README.md` (voces) describen ahora
la etapa en serie y por que nunca se parchea un modulador sobre `envelope.gain`.
VERIFICADO: sonido + sema 244/244 · check 76 = base 75 + 1 del fichero huerfano
`__adv-verify-haptic-dead.test.ts` (sin trackear, sin borrar sin instruccion) ·
docs:check 0/616 · el dev server sirve el fix (comprobado por fetch del modulo)
· prettier: los dos ficheros eran limpios en HEAD y quedan limpios.
Cierra el hallazgo S-06 de AUDIT-sema-2026-08-05.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
The tremolo is a gain node IN SERIES at `1 - depth`, modulated on its own
|
|
|
|
|
|
`.gain`, so the factor peaks at 1 and the trill scales WITH the envelope.
|
|
|
|
|
|
It used to be patched onto `envelope.gain`, where a connection ADDS to the
|
|
|
|
|
|
automation instead of scaling it: the depth stayed constant while the
|
|
|
|
|
|
envelope moved, closing every `signal` note on a non-zero sample (an audible
|
|
|
|
|
|
tick) and inflating a `commit.subtle` charged with `threat` to seven times
|
|
|
|
|
|
its declared level. Pinned by `engine-sound.test.ts`.
|
refactor(sound): extraer el motor Web Audio de sema al art `$sound`
`sema/chans/sound.ts` tenía 407 líneas de las que ~255 (≈63%) eran maquinaria
Web Audio —ciclo de vida del AudioContext, síntesis, samples, desbloqueo por
gesto— mezclada con doctrina perceptiva. Deuda arrastrada, con tres síntomas
medidos: el import era estático, así que toda app con sema metía el
sintetizador en el bundle aunque el sonido estuviera apagado (que es el
default); faltaba ciudadanía que `$scene` ya resuelve; y la costura de
inyección (`audioContextFactory`) llevaba ahí sin usar desde el principio.
Mismo movimiento que `$motion` hizo desde eidos: el art se lleva el RUNTIME, la
capa conserva sus DATOS y su doctrina.
- `$sound` / `EngineSound`: UN AudioContext por documento (los navegadores los
limitan y el gesto de desbloqueo es por contexto), síntesis de earcon,
samples con caché y fallback a síntesis, `autoSuspend` OPT-IN —suspender con
la pestaña oculta es correcto para earcons y erróneo para contenido, así que
es decisión de quien compone— y aviso cuando un segundo contexto va vivo.
Puertos `SoundDom` / `SoundTimers` inyectados; no importa ningún otro art ni
nada de `$uix/sema`, que es la prueba objetiva del corte.
- `SoundChannel`: 407 → 136 líneas. Solo doctrina: el gate de `prepare`, la
política de reducción y el reparto «el canal resuelve el NIVEL, el motor
aplica la ganancia». Sema no gana ni un import: recibe el motor por puerto.
- `uix.sound` en standalone y attach con `ownsSound` (idioma ya shipped:
`ownsMotion` / `ownsScene`), fila `sound` en la tabla ejecutable
`contracts.ts`, y `defineEngineSound()` para el camino de app.
- Tests nuevos: `engine-sound.test.ts` (11), `sound-port.test.ts` (guard de
deriva de tipos + la regla de propiedad) y `sound-e2e.test.ts`, que recorre
`emit -> cascada -> canal -> art -> grafo real`: el camino que las 16 suites
previas no cubrían porque paraban en canales falsos.
Sin `diagnostics.ts` ni `errors.ts`, y es decisión: espejo de `$scene`, aquí
todo fallo es degradación documentada, no error de programador.
Verificación: 17 suites / 198 tests · `check` en la baseline exacta (73
errores, 0 propios) · `sound.test.ts` verde SIN tocar un solo assert, que era
el criterio de que el movimiento fue value-preserving.
Planes: `PLAN-sound-engine.md` (completo, con el registro de la revisión
adversarial E-1..E-7), `PLAN-audio-player.md` (aparcado tras el análisis del
reproductor, con sus correcciones en cabecera) y `CONTINUE-sound-engine.md`
(handoff).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
- A signature carrying `sampleUrl` plays the sample (with an `AudioBuffer`
|
|
|
|
|
|
cache) and **falls back to synthesis** on fetch / decode failure.
|
|
|
|
|
|
- Any failure is absorbed — sema is ornamental.
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
The prepare-time priming pattern applies in general to any channel whose
|
|
|
|
|
|
backend has a "first time must happen inside a gesture" restriction: audio,
|
|
|
|
|
|
vibration, fullscreen, clipboard write. Documented as **convention 12** in
|
docs(book): F7.6 (1/2) — decision logs moved to docs/decisions/ (verbatim Spanish)
LIBRO_VARIACIONES_Y_EXTENSIONES -> decisions/book-deviations.md and
GUIA_IMPLEMENTACION_SEMAUIX -> decisions/guia-semantica-historica.md,
both moved AS-IS in Spanish: the deviations registry is a logbook of the
author's literal decisions ('transcrita literal') and carries proposed
doctrinal text destined for the Spanish book — translating it would
destroy that function (s G calls itself bitacora); the guia was already
status: historical (Fase 6) and the plan exempts it explicitly. English
frontmatter added to both; internal cross-links repointed (CANON,
theming/reference, book-deviations D.11). docs-check's I2 phantom-field
exemption follows the moved file (it matched by the LIBRO_VARIACIONES
filename; now also matches decisions/book-deviations.md). Corpus swept:
CANON x3, README (E2/E3 strata + tables — also fixed the pre-Fase-6
leftover row still calling the guia 'authoritative for any new wrapper'
and the unswept eidos/TSC.md stratum mention), building-a-component D.4,
completion-checklist G-1.1 + header, theming/reference, architecture
x5 (active-architecture, eidos, morfo, overview, sema x2).
docs:check 0 errors, 11-warn baseline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
[`guia-semantica-historica.md`](../decisions/guia-semantica-historica.md)
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
(historical seed).
|
|
|
|
|
|
|
|
|
|
|
|
### Error policy
|
|
|
|
|
|
|
|
|
|
|
|
- Errors in NON-visual channels are logged but never propagate. Sema is
|
|
|
|
|
|
ornamental: an audio-context or vibration-API failure must not abort the
|
|
|
|
|
|
provider's operation.
|
|
|
|
|
|
- If the visual channel throws, the `emit` Promise rejects. The caller
|
|
|
|
|
|
decides.
|
|
|
|
|
|
- In fire-and-forget (`void semantic.emit(...)`), a visual rejection
|
|
|
|
|
|
propagates as an unhandled promise — a conscious policy.
|
|
|
|
|
|
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
## Perceptual arbitration, reductions and accessibility (C-series, 2026-07-04)
|
|
|
|
|
|
|
fix(cleanroom): F2+F3+F4-C+SEM-4s1 — lote mecánico, censos con guard, corpus documental y el close polimórfico de los pickers VIVO
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>
3 months ago
|
|
|
|
Landed from the Sema↔book audit (`sema-findings.md`, a process registry since
|
|
|
|
|
|
removed from the tree); anchors in [`book-map.md`](../book-map.md). All
|
|
|
|
|
|
opt-outable, all covered by unit tests.
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
### Frequency memory — `engine.frequencyMemory` (default on)
|
|
|
|
|
|
|
|
|
|
|
|
`BK-FREQ-MEMORY` (ch. 32 §11): _"la gramática debe tener memoria de frecuencia"_.
|
|
|
|
|
|
Repeated occurrences of the **same** event identity (`signal.name`, else
|
|
|
|
|
|
`family:intent`) attenuate their non-visual channels — `sound.gain` and
|
|
|
|
|
|
`haptic.intensity` — past a small threshold, down to a floor, so the 50th
|
|
|
|
|
|
autosave doesn't sound like the first. `threat` is exempt; the visual hold is
|
|
|
|
|
|
never touched. A window of silence resets the key to full. Distinct from the
|
|
|
|
|
|
pointer-rate throttle (that samples ONE continuous gesture; this damps _repeated_
|
|
|
|
|
|
discrete signals). Disable with `frequencyMemory: false`.
|
|
|
|
|
|
|
|
|
|
|
|
### Dominance arbiter — `engine.dominance` (default on)
|
|
|
|
|
|
|
|
|
|
|
|
`BK-DOMINANCE` (ch. 30 §7): when signals overlap, the engine ranks each active
|
|
|
|
|
|
occurrence (evaluable `commit`/`signal` > structural; higher activation from
|
|
|
|
|
|
intent; recency breaks ties for the newcomer) and **mutes the non-visual
|
|
|
|
|
|
channels** of an incoming signal a still-active occurrence out-ranks — "lo
|
|
|
|
|
|
evaluable calla a lo estructural". `threat` is never muted; the visual hold and
|
|
|
|
|
|
the `announce` channel survive (a dominated event still reads structurally and
|
|
|
|
|
|
remains accessible). Occurrences stay active for a short overlap window. Disable
|
|
|
|
|
|
with `dominance: false`.
|
|
|
|
|
|
|
|
|
|
|
|
### Announce channel — `engine.announce` (opt-in)
|
|
|
|
|
|
|
|
|
|
|
|
`BK-SIGNAL-A11Y` / `BK-A11Y-CRITICAL`: the accessible live region is now a
|
|
|
|
|
|
first-class **channel** (`AnnounceChannel`, id `announce`), opt-in like sound /
|
|
|
|
|
|
haptic. It reads the human-facing text from `signal.message` (never inferred from
|
|
|
|
|
|
the technical event name), derives priority from intent (`threat`/`loss` →
|
|
|
|
|
|
`assertive`, else `polite`), and materializes it either through an injected
|
|
|
|
|
|
announcer (`{ announce }`, e.g. `ActiveUix.announce`, one shared region) or a
|
|
|
|
|
|
self-owned pair of live regions built from the injected `dom`. Fire-and-forget,
|
|
|
|
|
|
never rejects. Supersedes `book-deviations.md` D.8's deferral.
|
|
|
|
|
|
|
|
|
|
|
|
**Live-region doctrine — who owns what (AUX-1 / SEM-1, 2026-07-11).** The
|
|
|
|
|
|
framework has ONE sink, two emitters, and an app-level component:
|
|
|
|
|
|
|
|
|
|
|
|
- `uix.announce` (ActiveUix) owns the SHARED pair of live regions — the
|
|
|
|
|
|
low-level sink (its zwsp-toggle re-announce is an implementation detail of
|
|
|
|
|
|
that sink, not a third policy).
|
|
|
|
|
|
- The two framework **emitters** both prefer delegating to it: the soma
|
|
|
|
|
|
runtime's a11y commitments (`a11ySemantic.requiresLiveRegion` →
|
docs(sema): la doctrina deja de mentir — deriva propia, copias podridas y dos leyes muertas
Pasada de saneamiento documental tras los tres commits de sonido, con el
informe de AUDIT-sema-2026-08-05 como mapa. Tres clases de defecto.
1) DERIVA QUE YO MISMO DEJE (lo mas urgente)
El 05 renombre las claves silenciadoras a `commit.silent` / `emerge.silent` y
el 06 las elimine del catalogo — dejando media docena de docs citando claves
que ya no existen, y afirmando ademas comportamientos que ya no ocurren:
- switch / toggle / toggle-group README: decian «silent-by-default
(`commit.silent`)». Hoy es `commit.medium` (gain 0.1) y suenan. Corregidos
con el nivel real y su razon (un tercio de una pulsacion de boton).
- tooltip README + docblock del pack: decian que el tuning «resta el gain de
la familia, asi que neutral emite a 0» y que «threat / fulfill siguen
aflorando». Ambas cosas son falsas desde el 06: es `SILENT`, el resolver
retira el canal y NADA aflora, porque no queda ganancia que subir.
- toggle-group apuntaba a `LIBRO_VARIACIONES_Y_EXTENSIONES.md`, que es un stub
movido; ahora apunta a book-deviations.
- La nota del renombrado en D.5 decia «hoy es `commit.silent`»: una clave que
vivio UN DIA. Marcada como tal, con la lista de las que siguen vivas.
2) COPIAS PODRIDAS — la ley del corpus es enlazar, no copiar, y estas dos
entradas la incumplian
- D.9 transcribia `SEMA_HOLDS_BY_INTENT` entera y se habia quedado atras: D.12
corrigio DOS valores el 2026-07-06 (`commit.fulfill` noticed→settled,
`signal.loss` noticed→brief, ambos contra el texto del libro) y la copia
siguio afirmando los viejos un mes. Sustituida por el puntero a holds.ts +
el enumerado generado, con la leccion escrita en el sitio.
- sema.md transcribia `SEMA_VERBS` y le faltaban DOS verbos vivos:
`commit.unselect` y `handle.zoom`. Retirada; queda el puntero a verbs.ts y a
vocabularies.md, que si se genera y tiene guard de frescura.
3) LEYES QUE LA PRACTICA YA HABIA DEROGADO, Y NADIE REGISTRO
- El contrato `emit` publicaba `Promise<void>`; devuelve `Promise<string>`
desde D.9. Corregido, y explicado que ese string es el id de la ocurrencia —
el unico asidero para cerrar una senal persistente con `clear`.
- channels.md fijaba «3 canales runtime» y D.8 cerraba la puerta a Announce
(«hoy no»). El `AnnounceChannel` existe desde el 2026-07-04: built-in,
opt-in y exportado. channels.md pasa a 4 con la distincion que importa
(visual/sound/haptic EXPRESAN; announce SUSTITUYE) y D.8 queda marcada
PARCIALMENTE SUPERSEDED.
- sema.md prescribia `{ announce: uix.announce }` — y eso NO COMPILA: las dos
firmas no casan (bolsa de opciones vs posicional). Ahora ensena el adaptador
de una linea que si compila, y declara que ninguna raiz cablea el canal hoy,
asi que activarlo cae en el fallback que anade un SEGUNDO par de live
regions. El arreglo de codigo queda sin tomar: es decision de diseno.
- La cabecera de engine-sound.ts y la fila de arts/README seguian afirmando
como MECANISMO que «`prefs.sound` mapea al bus ui», que la auditoria AU-4 ya
habia corregido en el README del propio arte: lo garantizado por
construccion es el NEGATIVO (ninguna politica de UI escribe el bus content).
AMBIGUEDADES QUE NO RESUELVO PORQUE SON TUYAS, pero que dejan de estar
escondidas: D.7 prohibe canonizar samples fuera de `signal` y
`proof-of-human` los usa en dos eventos `commit`, aplastando la modulacion por
intent que esa misma entrada existe para proteger —y el comentario del pack
afirma literalmente lo contrario de lo que hace—; y D.8 declara que los packs
deben respetar el `activeChannels` de la familia mientras sema.md prescribe lo
contrario y el pack de dialog deja dos reglas inertes. Ambas quedan marcadas
con su estado real y los dos caminos excluyentes, pendientes de tu firma.
VERIFICADO: docs:check 0/616 · sonido + sema 244/244 · cero referencias vivas a
las tres claves muertas (las que quedan en book-deviations son historia
declarada como tal, y las de cronica no se reescriben) · prettier: los 6 docs
con avisos ya estaban sucios en HEAD, no los toco.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`sources.announce`) and this channel; its self-owned clear-then-set regions
|
|
|
|
|
|
are ONLY the no-uix fallback.
|
|
|
|
|
|
|
fix(sema,docs): S-19 — el puerto de anuncios encaja con su sumidero sin adaptador
`AnnounceFn` pedia la prioridad en una bolsa de opciones y `ActiveUix.announce`
la toma POSICIONAL, asi que el cableado que la doctrina prescribe —una sola
region viva compartida, este canal como uno de sus dos emisores— no se podia
escribir: `{ announce: uix.announce }` no compilaba. Y forzarlo era peor que no
tenerlo: el sumidero recibia un OBJETO donde lee una prioridad,
`liveRegionIds[obj]` es `undefined`, y TODO aterrizaba en la region polite — un
`threat` dejaba de interrumpir, que es justo lo que un aviso critico no puede
hacer.
La firma pasa a posicional, como el sumidero y como la fuente equivalente de
soma. Tres puertos, una sola forma. Cambio de conducta: CERO — el canal es
opt-in y ninguna raiz lo enciende hoy.
Visto en rojo antes de tocar: un test con la forma EXACTA de `uix.announce`
(`(message, priority?, timeout?)`) recibia `{priority:'assertive'}` en el hueco
de la prioridad. Tres aserciones existentes migran de bolsa a posicional — su
contrato cambia, y era el contrato defectuoso.
⚠️ Mi analisis inicial estaba equivocado y el autor lo mando revisar. Habia
concluido que el canal estaba muerto porque el runtime de soma no mete `message`
en la señal. No lo mete, cierto, pero es DISEÑO: son dos emisores para dos
publicos —soma cubre sus componentes, el canal cubre a quien usa
`EngineSemantic` sin soma y escribe su propia señal— y precisamente por eso
nada se anuncia dos veces. La propuesta de fusionarlos habria roto ese diseño;
retirada antes de escribir una linea.
`sema.md` §announce reescrito: fuera el aviso del adaptador (ya no hace falta),
dentro la razon de los dos publicos, y el aviso que SI queda — ninguna raiz
enchufa el canal, y encenderlo sin inyectar el anunciador añadiria un segundo
par de regiones vivas junto al compartido. Eso es decision aparte, sin firmar.
Verificado: announce 6 ✓ · sema+morfo+contracts 541 ✓ / 6 ajenos · check 69 =
base aislada, diff VACIO · docs 0/624 · prettier limpio.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
The two emitters serve **different publics, and that is why nothing is
|
|
|
|
|
|
announced twice**: the runtime path covers components built on soma, and this
|
|
|
|
|
|
channel covers an app driving `EngineSemantic` WITHOUT soma, which writes its
|
|
|
|
|
|
own signal and puts the text in `signal.message` itself. The soma runtime
|
|
|
|
|
|
deliberately does NOT forward `message` into the perceptual signal — its
|
|
|
|
|
|
a11y commitment is already discharged through `sources.announce`.
|
|
|
|
|
|
|
|
|
|
|
|
✅ **The delegation is now a literal** (S-19, fixed 2026-08-13). `AnnounceFn`
|
|
|
|
|
|
takes the priority POSITIONALLY, like the sink and like soma's source, so
|
|
|
|
|
|
`{ announce: uix.announce }` compiles as written — no adapter. It used to take
|
|
|
|
|
|
an options bag, and forcing the wiring through a cast handed the sink an
|
|
|
|
|
|
OBJECT where it reads a priority: `liveRegionIds[obj]` is `undefined`, so every
|
|
|
|
|
|
announcement, `threat` included, landed in the polite region and stopped
|
|
|
|
|
|
interrupting.
|
|
|
|
|
|
|
feat(active-uix,sema)!: S-19(ii) — announce encendido por defecto: un sumidero, materializado por la raiz
¿Debia encenderse? El analisis dijo que era LA RAIZ O NADIE: la opcion
`announce` se pasa al construir el engine dentro de `createActiveUix(options)`,
y en ese momento `uix.announce` no existe todavia — huevo y gallina. El unico
cableado que un app podia escribir (`announce: { dom }`) caia en las regiones
propias del canal: un SEGUNDO par de regiones vivas, exactamente lo que la
doctrina «ONE sink» (AUX-1) prohibe. La unica puerta alcanzable violaba la
doctrina; la raiz es el unico sitio que sostiene las dos puntas.
El impl registra el canal POST-construccion con cierre tardio —
`events.register(new AnnounceChannel({ announce: (m, p) => this.announce(m, p) }))`
— la misma forma para standalone y attach. Default ON, y la asimetria con
sound/haptic (apagados) es doctrina, no inconsistencia: esos son ORNAMENTO
(opt-in); announce es SUSTITUCION (sema.md §channels — «the one that
substitutes»), la categoria que el framework ya enciende solo (las regiones de
uix.announce se crean solas, el camino de soma esta siempre activo). La norma
del campo hace lo mismo: Angular CDK LiveAnnouncer es singleton por defecto,
React Aria usa una region ambiental de modulo. Un framework de referencia no
hace opt-in la accesibilidad.
Opt-outs estandar: `events: { announce: false }` — el engine gana el flag
legible `announceOptedOut` (las opciones de construccion no eran observables) —
y un `announce` explicito del app gana: la raiz jamas pisa un canal existente.
Cero doble anuncio, por diseño ya verificado: el runtime de soma no mete
`message` en la señal perceptual (su a11y viaja por sources.announce), asi que
el canal no-opea para todos los componentes de soma.
Visto en ROJO via stash del impl (canal sin registrar) y en verde con el:
una señal con `message` por `uix.events` aterriza en la region COMPARTIDA
(`uix-announce-assertive`, prioridad derivada del intent threat) y el
documento tiene UN solo [role='alert'] — el par fantasma nunca nace. El
opt-out respetado. `sema.md` §announce reescrito: el ⚠️ de «ninguna raiz lo
cablea» pasa a documentar el default y sus salidas.
Verificado: sema+morfo+eidos+contracts 947 ✓ / 6 ajenos · soma navegador
1278✓/1 (el timeout ajeno — TODOS los tests de navegador arrancan la raiz
tocada) · check 69 = base aislada, diff VACIO · docs 0/624 · prettier:
engine.ts limpio en HEAD queda limpio.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
✅ **Both roots wire it by DEFAULT** (S-19(ii), signed 2026-08-13). The
|
|
|
|
|
|
composition root is the only place that holds both ends — the shared sink
|
|
|
|
|
|
and the engine — and at engine-construction time `uix.announce` does not
|
|
|
|
|
|
exist yet, so any wiring an app could write fell back to the channel's
|
|
|
|
|
|
self-owned regions: a SECOND live pair, the very thing this section forbids.
|
|
|
|
|
|
`ActiveUix` therefore registers the channel post-construction with a
|
|
|
|
|
|
late-bound closure, in standalone and attach alike. Default ON because
|
|
|
|
|
|
announce is SUBSTITUTION, not ornament (§channels) — the a11y announcer
|
|
|
|
|
|
ships ambient, the field norm (Angular CDK `LiveAnnouncer`, React Aria).
|
|
|
|
|
|
Opt out with `events: {{ announce: false }}`; an explicitly passed
|
|
|
|
|
|
`announce` wins (the root never overwrites an existing channel). Soma
|
|
|
|
|
|
components still announce exactly once: their runtime keeps `message` out
|
|
|
|
|
|
of the perceptual signal, so the channel no-ops for them.
|
|
|
|
|
|
- The soma `<Announce>` component is different in kind: an app-authored,
|
|
|
|
|
|
declarative region for app-level messages — not a vehicle for framework
|
|
|
|
|
|
event announcements.
|
|
|
|
|
|
|
|
|
|
|
|
Priority is ONE policy everywhere (SEM-1 — the runtime used to add a
|
|
|
|
|
|
`family === 'signal'` conjunct, making a threat-tinted commit announce
|
|
|
|
|
|
polite on one path and assertive on the other): the evaluative INTENT alone
|
|
|
|
|
|
— `threat` / `loss` → `assertive`, else `polite` — implemented identically
|
|
|
|
|
|
in `priorityForIntent` (`chans/announce.ts`) and the runtime's a11y step
|
|
|
|
|
|
(`runtime.svelte.ts`), pinned by tests on both sides
|
|
|
|
|
|
(`announce.test.ts` · `runtime.svelte.test.ts` SEM-1).
|
|
|
|
|
|
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
### Per-channel reductions — `engine.preferences`
|
|
|
|
|
|
|
|
|
|
|
|
`BK-REDUCTIONS` (ch. 32 §12 / ch. 33 §7): a symmetric reduction story per
|
|
|
|
|
|
channel. `SemaPreferences { sound?, haptic?: 'full' | 'reduce' | 'off' }` is read
|
|
|
|
|
|
at dispatch (back it with reactive state to make it live). Sound gains a
|
|
|
|
|
|
reduce/off path (attenuate master gain / no-op) symmetric to haptic; haptic
|
feat(sema,sound): un pack se entrega como quieras — y un `data:` no se pide, se descodifica
La entrega deja de ser parte del contrato. Un pack de ficheros puede llegar
como quince URLs o como UN JSON de base64 (`packFromBase64`): mismo tipo, mismo
intercambio en caliente, misma reserva sintética por entrada, y un nombre que
no existe sigue sin compilar. Medido sobre `static/sounds/ui-inline.json`: una
petición en vez de quince, y 69.082 B con brotli frente a 79.332 B de los
ficheros sueltos — el +33 % del base64 lo deshace la compresión, y el JSON gana
además porque nadie comprime `audio/mpeg` y todos comprimen `application/json`.
## `step` no se oía
Era a la vez el MÁS CORTO (18 ms) y el MÁS FLOJO (gain 0.025), y esas dos cosas
se multiplican: el oído integra energía durante ~100-200 ms, así que un tono
corto necesita MÁS amplitud, no menos. Medido, rendía a −29,8 dBFS con la
novena parte de la energía de `touch`. Ahora 0.06 a los mismos 18 ms.
Lo que no había era el guard: la distinguibilidad es una RELACIÓN, y dos
sonidos pueden ser perfectamente distintos entre sí y ser los dos inaudibles.
`sound-names.test.ts` gana un suelo absoluto sobre `gain² × duración`.
## El precalentamiento no precalentaba
- `preload` pedía el contexto con `getOrCreateContext()`, que hace
`await resume()` — y antes del primer gesto esa promesa se queda PENDIENTE en
Chrome, no se rechaza. No descargaba nada hasta que el usuario ya había
pulsado, que es justo la latencia que el preload existe para quitar.
`decodeAudioData` funciona en un contexto suspendido.
- Aplicar un pack en caliente no calentaba la caché: cada nombre pagaba su
viaje la primera vez que sonaba. Ahora `rebuildMap()` llama a `warmSamples()`.
- Con `preferences.sound === 'off'` no se descarga NADA — un pack que no se
puede oír son bytes gastados en silencio. Pero la petición se RECUERDA en vez
de tirarse: el nivel se lee en el dispatch, así que la primera reproducción
audible vacía la cola y encender el sonido no devuelve una caché fría.
## Un `data:` se descodifica en el sitio
`connect-src 'self'` BLOQUEA `fetch('data:…')` — la directiva casa por ESQUEMA
y `'self'` no cubre `data:` — mientras deja pasar una ruta del mismo origen. Un
pack inline enrutado por `fetch` caía a síntesis EN SILENCIO justo en el
entorno que llevó a alguien a hacerlo inline. Y es ~6x más lento. `bytesFor()`
lo resuelve con `atob`.
## De la revisión adversarial
- Las claves del JSON se validan: una que no sea `SoundName` LANZA, igual que
una ruta mala en `assertMapPaths` y por la misma razón — tragarse la errata
da el síntoma «parte de mi pack no se aplicó» sin nada a lo que apuntar.
- `isSoundName` preguntaba `name in SEMA_MAP.sounds`, y `in` recorre el
prototipo: `isSoundName('toString')` devolvía `true`. Inofensivo mientras
todos los llamantes tecleaban el nombre; nada inofensivo al validar red.
- `warmSamples` sólo tenía una de las dos ramas que sí tiene el constructor, así
que una app con canal de sonido propio se calentaba al arrancar y nunca más;
y esa rama leía la preferencia UNA vez, en construcción. Las dos se caían por
lo mismo: ahora comparten `warmUrls()` en vez de duplicarse.
- El demo del catálogo cancela su fetch: elegir `inline` y saltar a `synth`
antes de que llegara reinstalaba el pack sobre un `clearMap()` ya hecho.
- `fallbackFor(name)` borra los dos casts que copiaba todo el que autorase un
pack de ficheros.
## Documentación
`architecture/sema.md` gana la sección de las dos formas de entrega y el
párrafo de `preloadSamples` reescrito — describía un precalentamiento que ya no
es el que ocurre. El README del arte conoce la ruta `data:`. La página de packs
gana su sección equivalente y deja de señalar unos `.wav` sueltos como «el
ejemplo».
Y un fantasma: `soft` no existe — es un nombre del catálogo viejo que quedaba
como ejemplo en ocho sitios, incluido el docstring de `applySounds`, cuyo
ejemplo copiado literalmente LANZABA.
`static/sounds/ui-inline.json` se genera desde `packs/ui-mp3.ts`; el comando
está documentado ahí y reproduce el fichero byte a byte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
_also_ keeps honoring `prefers-reduced-motion`. For sound, `off` governs the
|
|
|
|
|
|
NETWORK as well as the output: no sample is downloaded while it holds (see
|
|
|
|
|
|
`preloadSamples` above). Visual-motion reduction stays in
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
eidos CSS; when a channel is `off`, meaning migrates via the table below.
|
|
|
|
|
|
|
|
|
|
|
|
### Migration table — `sema/migration.ts`
|
|
|
|
|
|
|
|
|
|
|
|
`BK-A11Y-MIGRATION` (ch. 33): _"cuando un canal falla, migra el significado, no
|
|
|
|
|
|
el adorno"_ — as **data**, not just prose. `SEMA_MIGRATION` gives per-modality
|
|
|
|
|
|
fallback surfaces (motion → state/focus/text; color → shape/icon/text; sound →
|
|
|
|
|
|
presence/text/liveRegion; haptic → motion/shape/state); `SEMA_MIGRATION_BY_FAMILY`
|
|
|
|
|
|
refines the cases the book calls out (signal-sound → live region; commit-color →
|
|
|
|
|
|
footprint). `resolveFallback(modality, family?)` is the accessor a11y / eidos
|
|
|
|
|
|
consult.
|
|
|
|
|
|
|
|
|
|
|
|
### Frame-intent guardrail (morfo)
|
|
|
|
|
|
|
|
|
|
|
|
`BK-FRAME-NO-INTENT` (Apéndice A): a structural family (`contact` / `emerge` /
|
|
|
|
|
|
`shift` / `sustain` / `delegate`) that declares a non-neutral intent must justify
|
|
|
|
|
|
it with `MorfoEventSemantic.intentRationale`, or `validateMorfo` rejects it. This
|
|
|
|
|
|
makes the "appearance that is the warning" exception ([book-updates
|
|
|
|
|
|
A-1](../audit/book-updates.md)) explicit and auditable rather than a silent
|
|
|
|
|
|
loophole. `handle` is exempt (the book puts intent on `handle.drop`);
|
|
|
|
|
|
`commit`/`signal` require intent anyway.
|
|
|
|
|
|
|
docs(sema): add "Continuous components" doctrine section (STUMBLES S2)
The emit contract explains discrete events (one gesture → one emit → one
hold) but says nothing about direct-manipulation surfaces (Slider, Drawer,
future knob/swipe) where the pointer moves at sample rate while the value
updates continuously. Add a `## Continuous components (drag, swipe, hold)`
section after the emit contract, grounded entirely in the real Slider/Drawer
code (adversarially fact-checked, zero discrepancies):
- One door: `runtime.trigger()` is the sole path (there is no `emitEvent`).
Its Promise represents the whole occurrence incl. the visual hold — so
`void trigger()` is fire-and-forget (correct for high-frequency emits) and
`await trigger()` blocks until the hold ends (correct when a structural
change must observe the resolved signal, e.g. `close`).
- `coincident` vs `post` for a moving value: the move (handle-drag,
drag-progress) is `coincident` (signal + mutation indivisible); the commit
(commit-set) is `post` (handler settles, then the signal celebrates).
Slider is the worked example.
- Throttle continuous POINTER emits, not keyboard: pointer emits are coalesced
to animation frames + floored to a component-tuned interval via ActiveDom's
requestFrame (Slider DRAG_SIGNAL_MS, Drawer DRAG_PROGRESS_SIGNAL_MS);
keyboard commit-set fires once per keydown (already human-paced). Tuning ms
point to the code, never hard-coded here.
- The per-emit `overrides` payload owns pitch/gain/contour; a continuous
event's cascade rule sets only `channels` and MUST NOT override those
primitives, or it would clobber the live payload every frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
## Continuous components (drag, swipe, hold)
|
|
|
|
|
|
|
|
|
|
|
|
Most events are discrete: one gesture, one emit, one hold. Direct-manipulation
|
|
|
|
|
|
components — Slider, Drawer, and any future knob / swipe surface — are
|
|
|
|
|
|
**continuous**: the pointer moves at sample rate (dozens to hundreds of events
|
|
|
|
|
|
per second) while the value updates the whole time. Emitting one perceptual
|
|
|
|
|
|
signal per pointer sample would flood the channels and desynchronise the hold.
|
|
|
|
|
|
The rules below keep a continuous gesture perceptually legible without breaking
|
|
|
|
|
|
the emit contract.
|
|
|
|
|
|
|
|
|
|
|
|
### One door: `runtime.trigger(eventName, opts?)`
|
|
|
|
|
|
|
|
|
|
|
|
There is no `emitEvent`. Providers reach the engine through a single method,
|
|
|
|
|
|
`runtime.trigger(name)`, which resolves the morfo's compiled action, applies
|
|
|
|
|
|
polymorphic overrides, runs the handler in the declared `sequence`, awaits the
|
|
|
|
|
|
perceptual emit, and honours the event's a11y commitments. It returns a
|
|
|
|
|
|
`Promise` that represents **the whole occurrence, including the visual hold** —
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
the same sequential-strict window described in _Promise semantics_.
|
docs(sema): add "Continuous components" doctrine section (STUMBLES S2)
The emit contract explains discrete events (one gesture → one emit → one
hold) but says nothing about direct-manipulation surfaces (Slider, Drawer,
future knob/swipe) where the pointer moves at sample rate while the value
updates continuously. Add a `## Continuous components (drag, swipe, hold)`
section after the emit contract, grounded entirely in the real Slider/Drawer
code (adversarially fact-checked, zero discrepancies):
- One door: `runtime.trigger()` is the sole path (there is no `emitEvent`).
Its Promise represents the whole occurrence incl. the visual hold — so
`void trigger()` is fire-and-forget (correct for high-frequency emits) and
`await trigger()` blocks until the hold ends (correct when a structural
change must observe the resolved signal, e.g. `close`).
- `coincident` vs `post` for a moving value: the move (handle-drag,
drag-progress) is `coincident` (signal + mutation indivisible); the commit
(commit-set) is `post` (handler settles, then the signal celebrates).
Slider is the worked example.
- Throttle continuous POINTER emits, not keyboard: pointer emits are coalesced
to animation frames + floored to a component-tuned interval via ActiveDom's
requestFrame (Slider DRAG_SIGNAL_MS, Drawer DRAG_PROGRESS_SIGNAL_MS);
keyboard commit-set fires once per keydown (already human-paced). Tuning ms
point to the code, never hard-coded here.
- The per-emit `overrides` payload owns pitch/gain/contour; a continuous
event's cascade rule sets only `channels` and MUST NOT override those
primitives, or it would clobber the live payload every frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
That Promise is the control the caller uses to opt into or out of the hold:
|
|
|
|
|
|
|
|
|
|
|
|
- `void runtime.trigger('handle-drag')` — **fire-and-forget**. The signal
|
|
|
|
|
|
starts; the caller does not wait for the hold. Correct for high-frequency
|
|
|
|
|
|
emits, where blocking the gesture loop on a ~240ms hold would be absurd.
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
- `await runtime.trigger('emerge-close', …)` — **blocking**. The caller waits for
|
|
|
|
|
|
the hold to finish before its next step. Correct when a structural change must
|
|
|
|
|
|
observe the resolved signal (e.g. an `emerge-close` whose element unmounts after
|
|
|
|
|
|
the pulse — see the `sequence: 'post'` note under _Hold_).
|
docs(sema): add "Continuous components" doctrine section (STUMBLES S2)
The emit contract explains discrete events (one gesture → one emit → one
hold) but says nothing about direct-manipulation surfaces (Slider, Drawer,
future knob/swipe) where the pointer moves at sample rate while the value
updates continuously. Add a `## Continuous components (drag, swipe, hold)`
section after the emit contract, grounded entirely in the real Slider/Drawer
code (adversarially fact-checked, zero discrepancies):
- One door: `runtime.trigger()` is the sole path (there is no `emitEvent`).
Its Promise represents the whole occurrence incl. the visual hold — so
`void trigger()` is fire-and-forget (correct for high-frequency emits) and
`await trigger()` blocks until the hold ends (correct when a structural
change must observe the resolved signal, e.g. `close`).
- `coincident` vs `post` for a moving value: the move (handle-drag,
drag-progress) is `coincident` (signal + mutation indivisible); the commit
(commit-set) is `post` (handler settles, then the signal celebrates).
Slider is the worked example.
- Throttle continuous POINTER emits, not keyboard: pointer emits are coalesced
to animation frames + floored to a component-tuned interval via ActiveDom's
requestFrame (Slider DRAG_SIGNAL_MS, Drawer DRAG_PROGRESS_SIGNAL_MS);
keyboard commit-set fires once per keydown (already human-paced). Tuning ms
point to the code, never hard-coded here.
- The per-emit `overrides` payload owns pitch/gain/contour; a continuous
event's cascade rule sets only `channels` and MUST NOT override those
primitives, or it would clobber the live payload every frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
Slider and Drawer go through `trigger` exclusively — `handle-pick`,
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`handle-drag`, `commit-set` on the slider; `handle-pick`,
|
|
|
|
|
|
`handle-drag-progress`, `handle-drop` on the drawer. Every continuous one is
|
|
|
|
|
|
`void`.
|
docs(sema): add "Continuous components" doctrine section (STUMBLES S2)
The emit contract explains discrete events (one gesture → one emit → one
hold) but says nothing about direct-manipulation surfaces (Slider, Drawer,
future knob/swipe) where the pointer moves at sample rate while the value
updates continuously. Add a `## Continuous components (drag, swipe, hold)`
section after the emit contract, grounded entirely in the real Slider/Drawer
code (adversarially fact-checked, zero discrepancies):
- One door: `runtime.trigger()` is the sole path (there is no `emitEvent`).
Its Promise represents the whole occurrence incl. the visual hold — so
`void trigger()` is fire-and-forget (correct for high-frequency emits) and
`await trigger()` blocks until the hold ends (correct when a structural
change must observe the resolved signal, e.g. `close`).
- `coincident` vs `post` for a moving value: the move (handle-drag,
drag-progress) is `coincident` (signal + mutation indivisible); the commit
(commit-set) is `post` (handler settles, then the signal celebrates).
Slider is the worked example.
- Throttle continuous POINTER emits, not keyboard: pointer emits are coalesced
to animation frames + floored to a component-tuned interval via ActiveDom's
requestFrame (Slider DRAG_SIGNAL_MS, Drawer DRAG_PROGRESS_SIGNAL_MS);
keyboard commit-set fires once per keydown (already human-paced). Tuning ms
point to the code, never hard-coded here.
- The per-emit `overrides` payload owns pitch/gain/contour; a continuous
event's cascade rule sets only `channels` and MUST NOT override those
primitives, or it would clobber the live payload every frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
### `coincident` vs `post` for a moving value
|
|
|
|
|
|
|
|
|
|
|
|
A continuous gesture has two temporally distinct moments, and the morfo encodes
|
|
|
|
|
|
each with its `sequence`:
|
|
|
|
|
|
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
- **The move** (`handle-drag`, `handle-drag-progress`) is `sequence: 'coincident'` —
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
the perceptual signal and the value update are indivisible. The user _is_ the
|
docs(sema): add "Continuous components" doctrine section (STUMBLES S2)
The emit contract explains discrete events (one gesture → one emit → one
hold) but says nothing about direct-manipulation surfaces (Slider, Drawer,
future knob/swipe) where the pointer moves at sample rate while the value
updates continuously. Add a `## Continuous components (drag, swipe, hold)`
section after the emit contract, grounded entirely in the real Slider/Drawer
code (adversarially fact-checked, zero discrepancies):
- One door: `runtime.trigger()` is the sole path (there is no `emitEvent`).
Its Promise represents the whole occurrence incl. the visual hold — so
`void trigger()` is fire-and-forget (correct for high-frequency emits) and
`await trigger()` blocks until the hold ends (correct when a structural
change must observe the resolved signal, e.g. `close`).
- `coincident` vs `post` for a moving value: the move (handle-drag,
drag-progress) is `coincident` (signal + mutation indivisible); the commit
(commit-set) is `post` (handler settles, then the signal celebrates).
Slider is the worked example.
- Throttle continuous POINTER emits, not keyboard: pointer emits are coalesced
to animation frames + floored to a component-tuned interval via ActiveDom's
requestFrame (Slider DRAG_SIGNAL_MS, Drawer DRAG_PROGRESS_SIGNAL_MS);
keyboard commit-set fires once per keydown (already human-paced). Tuning ms
point to the code, never hard-coded here.
- The per-emit `overrides` payload owns pitch/gain/contour; a continuous
event's cascade rule sets only `channels` and MUST NOT override those
primitives, or it would clobber the live payload every frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
value changing, so the signal fires alongside the mutation, neither
|
|
|
|
|
|
anticipating nor trailing it. (`coincident` is emit-then-handler, like `pre`;
|
|
|
|
|
|
the two are just declared indivisible.)
|
|
|
|
|
|
- **The commit** (`commit-set`) is `sequence: 'post'` — the handler settles the
|
|
|
|
|
|
resolved value first, then the signal celebrates it. The move is felt
|
|
|
|
|
|
continuously; the commit is felt once, after. (`post` is handler-then-emit;
|
|
|
|
|
|
see the `sequence` comment in `runtime.svelte.ts` and the overlay note under
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
_Hold_.)
|
docs(sema): add "Continuous components" doctrine section (STUMBLES S2)
The emit contract explains discrete events (one gesture → one emit → one
hold) but says nothing about direct-manipulation surfaces (Slider, Drawer,
future knob/swipe) where the pointer moves at sample rate while the value
updates continuously. Add a `## Continuous components (drag, swipe, hold)`
section after the emit contract, grounded entirely in the real Slider/Drawer
code (adversarially fact-checked, zero discrepancies):
- One door: `runtime.trigger()` is the sole path (there is no `emitEvent`).
Its Promise represents the whole occurrence incl. the visual hold — so
`void trigger()` is fire-and-forget (correct for high-frequency emits) and
`await trigger()` blocks until the hold ends (correct when a structural
change must observe the resolved signal, e.g. `close`).
- `coincident` vs `post` for a moving value: the move (handle-drag,
drag-progress) is `coincident` (signal + mutation indivisible); the commit
(commit-set) is `post` (handler settles, then the signal celebrates).
Slider is the worked example.
- Throttle continuous POINTER emits, not keyboard: pointer emits are coalesced
to animation frames + floored to a component-tuned interval via ActiveDom's
requestFrame (Slider DRAG_SIGNAL_MS, Drawer DRAG_PROGRESS_SIGNAL_MS);
keyboard commit-set fires once per keydown (already human-paced). Tuning ms
point to the code, never hard-coded here.
- The per-emit `overrides` payload owns pitch/gain/contour; a continuous
event's cascade rule sets only `channels` and MUST NOT override those
primitives, or it would clobber the live payload every frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
Slider is the worked example: its morfo declares `handle-pick` / `handle-drag`
|
|
|
|
|
|
as `handle` · `coincident` and `commit-set` as `commit` · `post`.
|
|
|
|
|
|
|
|
|
|
|
|
### Throttle continuous pointer emits; leave keyboard alone
|
|
|
|
|
|
|
|
|
|
|
|
`onpointermove` fires far faster than the eye or ear resolves. Continuous emits
|
|
|
|
|
|
are therefore **coalesced to animation frames** and floored to a
|
|
|
|
|
|
component-tuned minimum interval — both via `ActiveDom`'s `requestFrame` (the
|
|
|
|
|
|
sanctioned rAF vehicle; never a raw `requestAnimationFrame` or `setTimeout`):
|
|
|
|
|
|
|
|
|
|
|
|
- Slider's `queueHandleDrag` stores the pending value, schedules one
|
|
|
|
|
|
`requestFrame`, and inside it skips the emit when less than
|
|
|
|
|
|
`SliderProvider.DRAG_SIGNAL_MS` has elapsed since the last signal.
|
|
|
|
|
|
- Drawer's `flushDragProgress` does the same with `DRAG_PROGRESS_SIGNAL_MS`,
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
deliberately set _below_ rAF cadence (sparser than one signal per frame).
|
docs(sema): add "Continuous components" doctrine section (STUMBLES S2)
The emit contract explains discrete events (one gesture → one emit → one
hold) but says nothing about direct-manipulation surfaces (Slider, Drawer,
future knob/swipe) where the pointer moves at sample rate while the value
updates continuously. Add a `## Continuous components (drag, swipe, hold)`
section after the emit contract, grounded entirely in the real Slider/Drawer
code (adversarially fact-checked, zero discrepancies):
- One door: `runtime.trigger()` is the sole path (there is no `emitEvent`).
Its Promise represents the whole occurrence incl. the visual hold — so
`void trigger()` is fire-and-forget (correct for high-frequency emits) and
`await trigger()` blocks until the hold ends (correct when a structural
change must observe the resolved signal, e.g. `close`).
- `coincident` vs `post` for a moving value: the move (handle-drag,
drag-progress) is `coincident` (signal + mutation indivisible); the commit
(commit-set) is `post` (handler settles, then the signal celebrates).
Slider is the worked example.
- Throttle continuous POINTER emits, not keyboard: pointer emits are coalesced
to animation frames + floored to a component-tuned interval via ActiveDom's
requestFrame (Slider DRAG_SIGNAL_MS, Drawer DRAG_PROGRESS_SIGNAL_MS);
keyboard commit-set fires once per keydown (already human-paced). Tuning ms
point to the code, never hard-coded here.
- The per-emit `overrides` payload owns pitch/gain/contour; a continuous
event's cascade rule sets only `channels` and MUST NOT override those
primitives, or it would clobber the live payload every frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
The concrete millisecond floors are perceptual tuning, not architecture — they
|
|
|
|
|
|
live at those constants in the providers, never copied here.
|
|
|
|
|
|
|
|
|
|
|
|
Keyboard is the opposite case and is **not** throttled: Slider's `onkeydown`
|
|
|
|
|
|
calls `commitValue()` → `trigger('commit-set')` on every arrow / Page / Home /
|
|
|
|
|
|
End press. OS key-repeat is already human-paced and every repeat is a discrete
|
|
|
|
|
|
committed value, so one emit per keydown is correct. Throttling is a property of
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
_sub-perceptual pointer sampling_, not of continuous components in general.
|
docs(sema): add "Continuous components" doctrine section (STUMBLES S2)
The emit contract explains discrete events (one gesture → one emit → one
hold) but says nothing about direct-manipulation surfaces (Slider, Drawer,
future knob/swipe) where the pointer moves at sample rate while the value
updates continuously. Add a `## Continuous components (drag, swipe, hold)`
section after the emit contract, grounded entirely in the real Slider/Drawer
code (adversarially fact-checked, zero discrepancies):
- One door: `runtime.trigger()` is the sole path (there is no `emitEvent`).
Its Promise represents the whole occurrence incl. the visual hold — so
`void trigger()` is fire-and-forget (correct for high-frequency emits) and
`await trigger()` blocks until the hold ends (correct when a structural
change must observe the resolved signal, e.g. `close`).
- `coincident` vs `post` for a moving value: the move (handle-drag,
drag-progress) is `coincident` (signal + mutation indivisible); the commit
(commit-set) is `post` (handler settles, then the signal celebrates).
Slider is the worked example.
- Throttle continuous POINTER emits, not keyboard: pointer emits are coalesced
to animation frames + floored to a component-tuned interval via ActiveDom's
requestFrame (Slider DRAG_SIGNAL_MS, Drawer DRAG_PROGRESS_SIGNAL_MS);
keyboard commit-set fires once per keydown (already human-paced). Tuning ms
point to the code, never hard-coded here.
- The per-emit `overrides` payload owns pitch/gain/contour; a continuous
event's cascade rule sets only `channels` and MUST NOT override those
primitives, or it would clobber the live payload every frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
### The per-emit payload owns the primitives; the cascade only adds character
|
|
|
|
|
|
|
refactor(sema): los 3 resolvers de gesto se retiran — esta vez desde el eje, y el registro se hace verdad
El rediseno del 2026-08-06 (gestos por REPETICION, sound:'step' por emision)
los dejo sin llamador, y book-deviations D.7 escribio en pasado un borrado que
nunca ocurrio. Hoy ocurre, firmado y desde una sesion del eje que empezo por
su handoff — la condicion que la retirada revertida de 5571f3bf7 se salto.
Fuera: los 3 resolvers + DragSoundParams + el SoundContour de sema (el
homonimo del art queda solo, 5 valores) + clamp/lerp huerfanos + 5 re-exports
+ los 2 tests que solo se probaban a si mismos. El registro (SEMA_SOUND_VOICE,
sample, resolveSoundDefinition) intacto.
Adjudicados los 8 sitios que los describian como vigentes: los 5 de la ficha
D10, el sexto del re-analisis (sema.md §per-emit payload, reescrito a la
verdad — el payload es un NOMBRE mas la curva haptica) y DOS que la ficha no
listaba, hallados al leer el eje (la fila de estado de CONTINUE-sound-engine y
D-AP2.7 del gate v2), ambos con nota fechada. La tabla de corte del plan
cerrado queda anotada y D.7 gana la nota de que su pasado se hizo verdad hoy.
AUDIT-sema-2026-08-05 no se toca: es cronica por cabecera propia.
sema+sound 333/333 · check 69 (base 70 menos el probe scratch de adom borrado
en fase 0) · docs:check 0/623 · prettier limpio en lo propio con eol auto
(motion/types y splitter-provider ya fallaban en HEAD; no se reformatean).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`handle-drag` carries a per-emit payload through `trigger`'s `overrides` —
|
|
|
|
|
|
since the 2026-08-06 redesign, a sound NAME (`'step'`: the gesture sounds by
|
|
|
|
|
|
REPETITION, so the cadence of the drag is the cadence of the ratchet) plus the
|
|
|
|
|
|
HAPTIC primitives derived from pointer velocity. The gesture resolvers that
|
|
|
|
|
|
used to synthesise pitch/gain/contour from position+velocity died with that
|
|
|
|
|
|
trade-off and were retired on 2026-08-12 (ledger
|
|
|
|
|
|
`docs/process/AUDIT-docs-code-ledger.md` §D10) — nothing authors sound
|
|
|
|
|
|
parameters per-emit any more. For the live payload to survive frame after
|
|
|
|
|
|
frame, the component's sema pack for the continuous event sets **only**
|
docs(sema): add "Continuous components" doctrine section (STUMBLES S2)
The emit contract explains discrete events (one gesture → one emit → one
hold) but says nothing about direct-manipulation surfaces (Slider, Drawer,
future knob/swipe) where the pointer moves at sample rate while the value
updates continuously. Add a `## Continuous components (drag, swipe, hold)`
section after the emit contract, grounded entirely in the real Slider/Drawer
code (adversarially fact-checked, zero discrepancies):
- One door: `runtime.trigger()` is the sole path (there is no `emitEvent`).
Its Promise represents the whole occurrence incl. the visual hold — so
`void trigger()` is fire-and-forget (correct for high-frequency emits) and
`await trigger()` blocks until the hold ends (correct when a structural
change must observe the resolved signal, e.g. `close`).
- `coincident` vs `post` for a moving value: the move (handle-drag,
drag-progress) is `coincident` (signal + mutation indivisible); the commit
(commit-set) is `post` (handler settles, then the signal celebrates).
Slider is the worked example.
- Throttle continuous POINTER emits, not keyboard: pointer emits are coalesced
to animation frames + floored to a component-tuned interval via ActiveDom's
requestFrame (Slider DRAG_SIGNAL_MS, Drawer DRAG_PROGRESS_SIGNAL_MS);
keyboard commit-set fires once per keydown (already human-paced). Tuning ms
point to the code, never hard-coded here.
- The per-emit `overrides` payload owns pitch/gain/contour; a continuous
event's cascade rule sets only `channels` and MUST NOT override those
primitives, or it would clobber the live payload every frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
`channels: ['sound', 'haptic']` and overrides nothing else
|
|
|
|
|
|
(`sema/components/slider.ts`).
|
|
|
|
|
|
|
refactor(sema): los 3 resolvers de gesto se retiran — esta vez desde el eje, y el registro se hace verdad
El rediseno del 2026-08-06 (gestos por REPETICION, sound:'step' por emision)
los dejo sin llamador, y book-deviations D.7 escribio en pasado un borrado que
nunca ocurrio. Hoy ocurre, firmado y desde una sesion del eje que empezo por
su handoff — la condicion que la retirada revertida de 5571f3bf7 se salto.
Fuera: los 3 resolvers + DragSoundParams + el SoundContour de sema (el
homonimo del art queda solo, 5 valores) + clamp/lerp huerfanos + 5 re-exports
+ los 2 tests que solo se probaban a si mismos. El registro (SEMA_SOUND_VOICE,
sample, resolveSoundDefinition) intacto.
Adjudicados los 8 sitios que los describian como vigentes: los 5 de la ficha
D10, el sexto del re-analisis (sema.md §per-emit payload, reescrito a la
verdad — el payload es un NOMBRE mas la curva haptica) y DOS que la ficha no
listaba, hallados al leer el eje (la fila de estado de CONTINUE-sound-engine y
D-AP2.7 del gate v2), ambos con nota fechada. La tabla de corte del plan
cerrado queda anotada y D.7 gana la nota de que su pasado se hizo verdad hoy.
AUDIT-sema-2026-08-05 no se toca: es cronica por cabecera propia.
sema+sound 333/333 · check 69 (base 70 menos el probe scratch de adom borrado
en fase 0) · docs:check 0/623 · prettier limpio en lo propio con eol auto
(motion/types y splitter-provider ya fallaban en HEAD; no se reformatean).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
> A cascade rule for a continuous event MUST NOT set `sound` (it would replace
|
|
|
|
|
|
> the per-emit name on every frame) nor the per-intent haptic `intensity` (it
|
|
|
|
|
|
> would flatten the live velocity curve to a constant buzz). The rule enables
|
|
|
|
|
|
> the channels and adds character — it never fixes the gesture's payload.
|
|
|
|
|
|
> (Same division as _Override layers_ and the canon rule "cascade rules add
|
|
|
|
|
|
> character, never the intent's evaluative profile".)
|
docs(sema): add "Continuous components" doctrine section (STUMBLES S2)
The emit contract explains discrete events (one gesture → one emit → one
hold) but says nothing about direct-manipulation surfaces (Slider, Drawer,
future knob/swipe) where the pointer moves at sample rate while the value
updates continuously. Add a `## Continuous components (drag, swipe, hold)`
section after the emit contract, grounded entirely in the real Slider/Drawer
code (adversarially fact-checked, zero discrepancies):
- One door: `runtime.trigger()` is the sole path (there is no `emitEvent`).
Its Promise represents the whole occurrence incl. the visual hold — so
`void trigger()` is fire-and-forget (correct for high-frequency emits) and
`await trigger()` blocks until the hold ends (correct when a structural
change must observe the resolved signal, e.g. `close`).
- `coincident` vs `post` for a moving value: the move (handle-drag,
drag-progress) is `coincident` (signal + mutation indivisible); the commit
(commit-set) is `post` (handler settles, then the signal celebrates).
Slider is the worked example.
- Throttle continuous POINTER emits, not keyboard: pointer emits are coalesced
to animation frames + floored to a component-tuned interval via ActiveDom's
requestFrame (Slider DRAG_SIGNAL_MS, Drawer DRAG_PROGRESS_SIGNAL_MS);
keyboard commit-set fires once per keydown (already human-paced). Tuning ms
point to the code, never hard-coded here.
- The per-emit `overrides` payload owns pitch/gain/contour; a continuous
event's cascade rule sets only `channels` and MUST NOT override those
primitives, or it would clobber the live payload every frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
## The per-family intent policy — `SEMA_FAMILY_POLICY`
|
|
|
|
|
|
|
|
|
|
|
|
> **Canonical:** [`CANON.md`](../CANON.md) §4 is the single source for this
|
|
|
|
|
|
> policy. The shape below mirrors `SEMA_FAMILY_POLICY` in `types.ts`; if they
|
|
|
|
|
|
> ever disagree, the code + canon win.
|
|
|
|
|
|
|
|
|
|
|
|
The doctrine on when intent is mandatory lives in a const in
|
|
|
|
|
|
`src/uix/sema/types.ts`. Each family declares **two independent axes**:
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
export const SEMA_FAMILY_POLICY = {
|
|
|
|
|
|
contact: { intentRequirement: 'optional', intentGuidance: 'discouraged' },
|
|
|
|
|
|
commit: { intentRequirement: 'required', intentGuidance: 'expected' },
|
|
|
|
|
|
signal: { intentRequirement: 'required', intentGuidance: 'expected' },
|
|
|
|
|
|
handle: { intentRequirement: 'optional', intentGuidance: 'contextual' },
|
|
|
|
|
|
emerge: { intentRequirement: 'optional', intentGuidance: 'contextual' },
|
|
|
|
|
|
shift: { intentRequirement: 'optional', intentGuidance: 'contextual' },
|
|
|
|
|
|
sustain: { intentRequirement: 'optional', intentGuidance: 'contextual' },
|
|
|
|
|
|
delegate: { intentRequirement: 'optional', intentGuidance: 'contextual' }
|
|
|
|
|
|
} as const;
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- **`intentRequirement`** (`'required' | 'optional' | 'forbidden'`) — the
|
|
|
|
|
|
compile-time gate that shapes the discriminated union. `'required'` (only
|
|
|
|
|
|
`commit` and `signal`) → `intent` is MANDATORY in `MorfoEventSemantic`.
|
|
|
|
|
|
`'forbidden'` is reserved; no family uses it today.
|
|
|
|
|
|
- **`intentGuidance`** (`'expected' | 'contextual' | 'discouraged'`) — a
|
|
|
|
|
|
doctrinal hint with no type effect. `commit`/`signal` are `'expected'`;
|
|
|
|
|
|
`contact` is `'discouraged'` (book ch. 22 §11: "strong intent should not
|
|
|
|
|
|
live in the contact"); the rest are `'contextual'`.
|
|
|
|
|
|
|
|
|
|
|
|
**How it is enforced:**
|
|
|
|
|
|
|
|
|
|
|
|
1. **Compile time** — `SemaEvent` and `MorfoEventSemantic` are discriminated
|
|
|
|
|
|
unions derived from the `intentRequirement` axis. Flipping a family from
|
|
|
|
|
|
`'optional'` to `'required'` forces every morfo of that family to declare
|
|
|
|
|
|
an intent or fail the typecheck.
|
|
|
|
|
|
|
|
|
|
|
|
2. **Runtime** — `validateSemaEvent` throws when an event of a family with
|
|
|
|
|
|
`intentRequirement: 'required'` is built without intent (a defense against
|
|
|
|
|
|
malformed morfos or external inputs).
|
|
|
|
|
|
|
|
|
|
|
|
**Why this policy replaced the valenced/transitional split:**
|
|
|
|
|
|
|
|
|
|
|
|
The original canonical doctrine assumed only valenced families (contact,
|
|
|
|
|
|
commit, signal, handle) could declare intent. Transitional ones (emerge,
|
|
|
|
|
|
shift, sustain) were intent-less by definition. UX reality contradicted it: a
|
|
|
|
|
|
Dialog opening to confirm a destructive delete carries threat in its very
|
|
|
|
|
|
appearance. The policy distinguishes by the practical NEED for intent, not by
|
|
|
|
|
|
taxonomic category.
|
|
|
|
|
|
|
|
|
|
|
|
The valenced/transitional distinction still exists as a classification, but
|
|
|
|
|
|
it no longer dictates the intent rules — the policy does.
|
|
|
|
|
|
|
|
|
|
|
|
## The canonical verb vocabulary (`SEMA_VERBS`)
|
|
|
|
|
|
|
|
|
|
|
|
> **Canonical:** [`CANON.md`](../CANON.md) §6 +
|
|
|
|
|
|
> [`verbs.ts`](../../src/uix/sema/verbs.ts) are the source of truth for the
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
> verb vocabulary. This section documents how sema _consumes_ it (validation,
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
> naming shapes).
|
|
|
|
|
|
|
|
|
|
|
|
Cross-component action verbs grouped by family. The canon lives in
|
feat(audit): component re-audit + fixes P0–P5 (P4 complete, P5 in progress)
Re-audit of the whole component catalog at pilot depth (91 fichas + the
checkpoint verdicts in docs/audit/components/) and the executed fix packages.
- P0–P3: doctrine (sema participation, CANON §3 intent, component-guide §5 +
API naming, §32 outline), guards (morfo-vocabulary-check S10/S11d,
component-audit A-3.1/A-1.4/S9, eidos-lint classHooks), morfo contracts
(role=application removed ×4, aria-selected off the Day, drp translationRef,
field data-state prune, pin-input commit-set, media-player renames), 13 new
sema packs + 12 morfos family-default → pack.
- P4 (N1–N10) COMPLETE: selectionMode (select/combobox/toggle-group/calendar);
onValueCommit terminal-callback norm (pin-input/search/password/textarea +
date/time/color-field add); typed validation reason + onInvalid (tags-input,
css-field); index/onIndexChange (carousel); deselectable; openDelay/
groupSkipDelay; allowCustomValue; defaultValue prune.
- P5 (in progress): S1 class-hooks codemod (22 hooks → data-attrs across
cropper/button/image-picker/toggle/image-adjustments); S5 outline remnant in
field.css; depth pass (data-depth=overlay on tooltip/toast/float-panel);
touch-rows (--touch-target token, decoupled ::before hit-slop, area-not-visual,
44 AAA). S6 (Field composition) + S8 (calendar-surface) pending.
Verification: errors-outside-(alpha|words|palabras|chronos) == 59 (baseline);
morfo-vocabulary-check exit 0; eidos-lint class-hooks/invalid 0 on touched
components; per-component vitest suites green.
Handoff + remaining plan: docs/process/continue-audit-fixes-2026-07.md
Excluded (broken by the N1 rename, left broken per user decision, not staged):
words/**, palabras/**, chronos, web/routes/alpha/**.
Reconciliation pending: the touch-rows ::before for checkbox/switch reverses
changelog §37's earlier pseudo-element rejection (WCAG-overlap) that had routed
markers to a labeled-row/Field task — flagged for the user in the handoff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
[`verbs.ts`](../../src/uix/sema/verbs.ts) and reflects the book _Diseñando lo
|
|
|
|
|
|
que ocurre_ ch. 22–29 (families) + ch. 10 (intents).
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
`morfo.events[].semantic.verb` MUST be in this vocabulary;
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`morfo.events[].name` MUST follow the `{family}-{verb}[-{nuance}]` shape
|
|
|
|
|
|
(guaranteed by `validateMorfo`) so sema/sound/haptic can subscribe by verb and
|
|
|
|
|
|
eidos can write transversal selectors (`[data-event^="emerge-dismiss"]`).
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
docs(sema): la doctrina deja de mentir — deriva propia, copias podridas y dos leyes muertas
Pasada de saneamiento documental tras los tres commits de sonido, con el
informe de AUDIT-sema-2026-08-05 como mapa. Tres clases de defecto.
1) DERIVA QUE YO MISMO DEJE (lo mas urgente)
El 05 renombre las claves silenciadoras a `commit.silent` / `emerge.silent` y
el 06 las elimine del catalogo — dejando media docena de docs citando claves
que ya no existen, y afirmando ademas comportamientos que ya no ocurren:
- switch / toggle / toggle-group README: decian «silent-by-default
(`commit.silent`)». Hoy es `commit.medium` (gain 0.1) y suenan. Corregidos
con el nivel real y su razon (un tercio de una pulsacion de boton).
- tooltip README + docblock del pack: decian que el tuning «resta el gain de
la familia, asi que neutral emite a 0» y que «threat / fulfill siguen
aflorando». Ambas cosas son falsas desde el 06: es `SILENT`, el resolver
retira el canal y NADA aflora, porque no queda ganancia que subir.
- toggle-group apuntaba a `LIBRO_VARIACIONES_Y_EXTENSIONES.md`, que es un stub
movido; ahora apunta a book-deviations.
- La nota del renombrado en D.5 decia «hoy es `commit.silent`»: una clave que
vivio UN DIA. Marcada como tal, con la lista de las que siguen vivas.
2) COPIAS PODRIDAS — la ley del corpus es enlazar, no copiar, y estas dos
entradas la incumplian
- D.9 transcribia `SEMA_HOLDS_BY_INTENT` entera y se habia quedado atras: D.12
corrigio DOS valores el 2026-07-06 (`commit.fulfill` noticed→settled,
`signal.loss` noticed→brief, ambos contra el texto del libro) y la copia
siguio afirmando los viejos un mes. Sustituida por el puntero a holds.ts +
el enumerado generado, con la leccion escrita en el sitio.
- sema.md transcribia `SEMA_VERBS` y le faltaban DOS verbos vivos:
`commit.unselect` y `handle.zoom`. Retirada; queda el puntero a verbs.ts y a
vocabularies.md, que si se genera y tiene guard de frescura.
3) LEYES QUE LA PRACTICA YA HABIA DEROGADO, Y NADIE REGISTRO
- El contrato `emit` publicaba `Promise<void>`; devuelve `Promise<string>`
desde D.9. Corregido, y explicado que ese string es el id de la ocurrencia —
el unico asidero para cerrar una senal persistente con `clear`.
- channels.md fijaba «3 canales runtime» y D.8 cerraba la puerta a Announce
(«hoy no»). El `AnnounceChannel` existe desde el 2026-07-04: built-in,
opt-in y exportado. channels.md pasa a 4 con la distincion que importa
(visual/sound/haptic EXPRESAN; announce SUSTITUYE) y D.8 queda marcada
PARCIALMENTE SUPERSEDED.
- sema.md prescribia `{ announce: uix.announce }` — y eso NO COMPILA: las dos
firmas no casan (bolsa de opciones vs posicional). Ahora ensena el adaptador
de una linea que si compila, y declara que ninguna raiz cablea el canal hoy,
asi que activarlo cae en el fallback que anade un SEGUNDO par de live
regions. El arreglo de codigo queda sin tomar: es decision de diseno.
- La cabecera de engine-sound.ts y la fila de arts/README seguian afirmando
como MECANISMO que «`prefs.sound` mapea al bus ui», que la auditoria AU-4 ya
habia corregido en el README del propio arte: lo garantizado por
construccion es el NEGATIVO (ninguna politica de UI escribe el bus content).
AMBIGUEDADES QUE NO RESUELVO PORQUE SON TUYAS, pero que dejan de estar
escondidas: D.7 prohibe canonizar samples fuera de `signal` y
`proof-of-human` los usa en dos eventos `commit`, aplastando la modulacion por
intent que esa misma entrada existe para proteger —y el comentario del pack
afirma literalmente lo contrario de lo que hace—; y D.8 declara que los packs
deben respetar el `activeChannels` de la familia mientras sema.md prescribe lo
contrario y el pack de dialog deja dos reglas inertes. Ambas quedan marcadas
con su estado real y los dos caminos excluyentes, pendientes de tu firma.
VERIFICADO: docs:check 0/616 · sonido + sema 244/244 · cero referencias vivas a
las tres claves muertas (las que quedan en book-deviations son historia
declarada como tal, y las de cronica no se reescriben) · prettier: los 6 docs
con avisos ya estaban sucios en HEAD, no los toco.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
> **The literal table used to live here, and it rotted.** It was missing
|
|
|
|
|
|
> `commit.unselect` and `handle.zoom` — both live in `verbs.ts` and both used
|
|
|
|
|
|
> by real morfos. A copy of a closed set is a copy that goes stale; the
|
|
|
|
|
|
> generated enumeration in
|
|
|
|
|
|
> [`canon/vocabularies.md`](../canon/vocabularies.md#sema-verbs-by-family)
|
|
|
|
|
|
> is regenerated from the const by `npm run docs:vocabularies` and guarded for
|
|
|
|
|
|
> freshness by `npm run docs:check`. Removed 2026-08-06.
|
|
|
|
|
|
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
**Verbs that look like one family but belong to another** per the canon:
|
|
|
|
|
|
`select`/`toggle`/`acknowledge` are `commit` (they fix state); `edit` is
|
|
|
|
|
|
expressed as `shift.enter-mode` (it changes the regime — there is no `edit`
|
|
|
|
|
|
verb in handle).
|
|
|
|
|
|
|
|
|
|
|
|
Defined in [`verbs.ts:SEMA_VERBS`](../../src/uix/sema/verbs.ts).
|
|
|
|
|
|
|
|
|
|
|
|
### Naming shapes
|
|
|
|
|
|
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
A `morfo.events[].name` takes ONE canonical shape — the name declares the
|
|
|
|
|
|
family, and `validateMorfo` rejects any that does not:
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
|
|
|
|
|
|
```ts
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
// {family}-{verb}[-{nuance}] — head is the family, then the canonical verb,
|
|
|
|
|
|
// then the nuance when the component needs one.
|
|
|
|
|
|
'emerge-dismiss'; // family=emerge, verb=dismiss
|
|
|
|
|
|
'emerge-dismiss-outside'; // + nuance (outside)
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
'commit-toggle'; // family=commit, verb=toggle
|
|
|
|
|
|
'commit-save'; // family=commit, verb=save
|
|
|
|
|
|
```
|
|
|
|
|
|
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`validateEventName(name)` parses a name — it still accepts the retired
|
|
|
|
|
|
bare-verb shape — and returns `{ family, verb, variant, matchesCanonical }`.
|
|
|
|
|
|
Used by
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
`scripts/morfo-vocabulary-check.ts` (`npm run morfo:vocabulary`), which
|
|
|
|
|
|
hard-fails when a morfo's declared `semantic.verb` is not in its family's
|
|
|
|
|
|
canon, and soft-warns when the event NAME doesn't fit
|
feat(morfo,sema,eidos): todo evento dice de que familia es, y el cruce por fin se ve
El framework llamaba a la misma cosa de dos maneras: `open` pelado en ocho
componentes y `emerge-open` en tres. No era estetica — un preset de movimiento
engancha el nombre con `^=`, asi que el dialecto pelado no casaba con ninguna
firma y simplemente no animaba, sin romper una sola prueba.
Los 40 nombres sin prefijo pasan a `{familia}-{verbo}[-{matiz}]`: 256 eventos,
256 con prefijo, 0 ambiguos. El plan decia 36 y decia `handle-drag-start`; eran
40, y el canon (c25) dice que esos verbos son `pick` y `drop` — `handle-pick` y
`handle-drop` ya existian en 10 y 4 componentes.
`validateMorfo` cierra la puerta: un `events[].name` que no empiece por su
familia ahora lanza. Visto fallar antes con un nombre pelado inyectado.
Lo que el renombrado destapo, y va aqui tambien:
- La receta del splitter enganchaba `commit-resize`, muerto desde
`bd2e40366`. No casaba desde mayo y nadie chillo. Reescrita por FAMILIA, como
slider y knob, y `eidos-lint` valida ahora el VALOR de `data-event*` contra el
catalogo de morfos — el guard que lo habria cazado en su dia.
- La familia `shift` era muda en el canal visual, contra su propia doctrina
(c27: el cruce debe percibirse; c34 tipifica el «shift invisible»). Su mapa ya
describia la firma que le faltaba y su sonido por defecto es `slide`. Ahora
tiene firma direccional: sexto atributo del sello (`data-event-direction`,
`forward`|`backward`, por emision) y deslizamiento de 320ms RTL-safe por
`:dir()`. Medido: LTR -30px/+30px, RTL los invierte.
- El sello de `shift-navigate` pasa del BOTON al `grid` en los cuatro
calendarios. Medido: el boton recibia `contact-activate` y 8,5 ms despues
—media trama— el `shift-navigate` pisaba la misma ranura y el `press-squeeze`
moria sin pintar un fotograma. Una superficie, una ranura (A-36).
- 101 contradicciones docs<->morfo adjudicadas con evidencia (git log, docs de
decision, el componente vivo). Las docs desfasadas, corregidas; los nueve
DEFECTOS de codigo obsoleto quedan abiertos y sin tocar.
- `SoundDirection` -> `SoundContour`: era un contorno de tono, no un sentido, y
habia tres cosas distintas deletreadas «direction».
check en su linea base con 0 errores nuevos por diferencia de conjuntos ·
docs:check 0/0 · eidos-lint invalid 0 · el censo y las escenas de navegador
medidas con raton real y rAF vivo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
`{family}-{verb}[-{nuance}]` even though the verb is canonical. A temporary
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
allowlist in the script covers deliberate divergences.
|
|
|
|
|
|
|
|
|
|
|
|
```ts
|
|
|
|
|
|
import { validateEventName } from '$uix/sema';
|
|
|
|
|
|
|
|
|
|
|
|
validateEventName('commit-toggle');
|
|
|
|
|
|
// { name: 'commit-toggle', head: 'commit', matchesCanonical: true,
|
|
|
|
|
|
// variant: 'toggle', family: 'commit', verb: 'toggle' }
|
|
|
|
|
|
|
|
|
|
|
|
validateEventName('dismiss-outside');
|
|
|
|
|
|
// { name: 'dismiss-outside', head: 'dismiss', matchesCanonical: true,
|
|
|
|
|
|
// variant: 'outside', family: 'emerge', verb: 'dismiss' }
|
|
|
|
|
|
|
|
|
|
|
|
validateEventName('frob-glob');
|
|
|
|
|
|
// { name: 'frob-glob', head: 'frob', matchesCanonical: false,
|
|
|
|
|
|
// variant: 'glob', family: undefined, verb: undefined }
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Relationship with Morfo and Soma
|
|
|
|
|
|
|
|
|
|
|
|
- `Morfo` declares the component's semantic events in `morfo.events`
|
|
|
|
|
|
- `Provider` decides when they occur and calls `semantic.emit(...)`
|
|
|
|
|
|
- `SomaRuntime` orchestrates the `prewrite -> emit -> handler -> effects`
|
|
|
|
|
|
sequence
|
|
|
|
|
|
- `Sema` contributes the vocabulary, normalization and domain validation, and
|
|
|
|
|
|
publishes the occurrences
|
|
|
|
|
|
|
|
|
|
|
|
## Dependencies
|
|
|
|
|
|
|
|
|
|
|
|
- `EngineSemantic` writes no attributes directly. It orchestrates channel
|
|
|
|
|
|
hooks (`prepare`, `handle`, `cleanup`) without knowing the DOM attrs.
|
|
|
|
|
|
- Each channel manages its own modality:
|
|
|
|
|
|
- `VisualChannel.prepare()` projects `data-event-*` and then holds the
|
|
|
|
|
|
perceptual window.
|
|
|
|
|
|
- `DomSignalProjector` is the DOM writer used by the visual channel; it
|
|
|
|
|
|
writes through the `ActiveDom` received from `ActiveUix`.
|
|
|
|
|
|
- Other channels (sound, haptic) access their respective APIs
|
|
|
|
|
|
(`AudioContext`, `navigator.vibrate`, etc.).
|
|
|
|
|
|
- In normal use, `ActiveUix` injects the `ActiveDom` into `EngineSemantic`.
|
|
|
|
|
|
Using Sema directly outside `ActiveUix` must pass an explicit
|
|
|
|
|
|
`dom/projector` or choose a documented degradation.
|
|
|
|
|
|
|
|
|
|
|
|
## Architecture rule
|
|
|
|
|
|
|
|
|
|
|
|
`Morfo` authorizes the component's semantics.
|
|
|
|
|
|
|
|
|
|
|
|
`Sema` defines the canonical vocabulary and dispatches signals to channels.
|
|
|
|
|
|
|
|
|
|
|
|
`Provider` decides when to emit.
|
|
|
|
|
|
|
|
|
|
|
|
Each `Channel` materializes the signal in its modality.
|
|
|
|
|
|
|
|
|
|
|
|
See [`architecture/overview.md`](./overview.md) §2.bis for the cross-layer
|
|
|
|
|
|
view. The original Spanish API conventions (single-event for instantaneous
|
|
|
|
|
|
operations, intent ↔ visual token resolution, sound prepare-time priming)
|
|
|
|
|
|
survive as a historical seed in
|
docs(book): F7.6 (1/2) — decision logs moved to docs/decisions/ (verbatim Spanish)
LIBRO_VARIACIONES_Y_EXTENSIONES -> decisions/book-deviations.md and
GUIA_IMPLEMENTACION_SEMAUIX -> decisions/guia-semantica-historica.md,
both moved AS-IS in Spanish: the deviations registry is a logbook of the
author's literal decisions ('transcrita literal') and carries proposed
doctrinal text destined for the Spanish book — translating it would
destroy that function (s G calls itself bitacora); the guia was already
status: historical (Fase 6) and the plan exempts it explicitly. English
frontmatter added to both; internal cross-links repointed (CANON,
theming/reference, book-deviations D.11). docs-check's I2 phantom-field
exemption follows the moved file (it matched by the LIBRO_VARIACIONES
filename; now also matches decisions/book-deviations.md). Corpus swept:
CANON x3, README (E2/E3 strata + tables — also fixed the pre-Fase-6
leftover row still calling the guia 'authoritative for any new wrapper'
and the unswept eidos/TSC.md stratum mention), building-a-component D.4,
completion-checklist G-1.1 + header, theming/reference, architecture
x5 (active-architecture, eidos, morfo, overview, sema x2).
docs:check 0 errors, 11-warn baseline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
[`guia-semantica-historica.md`](../decisions/guia-semantica-historica.md);
|
docs(book): F7.2 (4/6) — sema chapter translated to docs/architecture/sema.md
src/uix/sema/README.md (749 L, Spanish) translated to English: the emit
contract (sequential strict), the 1-2-3-4-5a-5b resolution cascade, the
data-event-* tokens, the typed semaSelector builder, per-component packs,
the sound repository, SoundChannel details, SEMA_FAMILY_POLICY (two axes)
and SEMA_VERBS + naming shapes. Thin stub at the old path; corpus links
swept (CANON, comparison, glossary, docs map, building-a-component,
overview, morfo chapter, active_architecture). docs:check 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 months ago
|
|
|
|
the ruling vocabulary is [`CANON.md`](../CANON.md).
|