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
---
title: Registro de desviaciones entre implementación y canon editorial
type: decision-log
audience: human + agent
authority: authoritative registry — where the implementation deviates from the book canon, with per-entry status
status: current
source: migrated verbatim from src/docs/LIBRO_VARIACIONES_Y_EXTENSIONES.md (2026-07-02, docs-book F7.6; kept in Spanish — it is a logbook of literal author decisions and proposed doctrinal text for the Spanish book)
---
# Registro de desviaciones entre implementación y canon editorial
> **Este documento no forma parte del libro.** Es un registro interno de decisiones de implementación. Su objetivo es separar qué pertenece al canon editorial («Diseñando lo que ocurre»), qué pertenece al canon del proyecto UIX, y qué queda como extensión local o candidato pendiente.
>
> **Principio rector**: solo entra al libro lo que mejora la teoría general. Lo demás puede vivir como extensión del proyecto. El libro debe conservar un núcleo estable; la implementación puede tener vocabulario más rico.
>
> **No todo lo que aparece en implementación debe volver al libro.**
---
## Clasificación de status
| Status | Significado |
|---|---|
| **BOOK_CANON** | Ya debería pasar al libro como ampliación canónica. Aceptado por el autor. |
| **PROJECT_CANON** | Canon válido del proyecto, pero no necesariamente del libro. |
| **CANDIDATE** | Caso plausible, pero falta doctrina o uso real para canonizar. |
| **LOCAL_EXTENSION** | Necesario para este proyecto, pero no escalable al libro. |
| **DEPRECATED** | Se mantiene temporalmente, pero debería eliminarse. |
| **ALIAS** | Nombre aceptado como comodidad técnica, mapea a otro verbo doctrinal. |
| **IMPLEMENTATION_CONTRACT** | Existe en morfos/runtime, pero no necesariamente como doctrina editorial. |
Cada entrada lleva su status. Las entradas con `BOOK_CANON` incluyen el texto doctrinal recomendado para el libro, en bloques citados.
---
## A. Verbos añadidos al canon de implementación
Estos verbos están en `src/uix/sema/verbs.ts:SEMA_VERBS` . Su status doctrinal para el libro varía.
### A.1 `handle.scroll`
- **Status**: **BOOK_CANON**
- **Libro Cap 25 §1** lista 7 verbos: pick, carry, drop, drag, resize, rotate, reorder. `scroll` no aparece literalmente.
- **Decisión del autor**: aceptar como ampliación de `handle` . Cap 25 §1 ("manipulación directa de un objeto") cubre la lectura: el usuario desplaza directamente un viewport mediante gesto continuo.
- **Distinción doctrinal**:
- Scroll gestual del usuario → `handle.scroll`
- Scroll programático del sistema (scrollToIndex / scrollToCell / scrollIntoView) → `shift.navigate`
- **Texto doctrinal para el libro**:
> `handle.scroll` cubre los casos en los que el usuario desplaza directamente un viewport, lista, panel o superficie desplazable. No equivale a navegación programática: cuando el sistema mueve al usuario a una posición concreta sin control directo, el evento pertenece mejor a `shift.navigate`.
### A.2 `commit.acknowledge`
- **Status**: **CANDIDATE**
- **Libro Cap 23 §5** lista 12 verbos de commit. `acknowledge` no aparece.
- **Decisión del autor**: NO pasar al libro todavía. Mantener en canon de implementación pendiente de casos fuertes.
- **Solapamiento problemático**: con `commit.confirm` , `commit.cancel` , `commit.submit` , `signal.dismiss` . Si el usuario solo cierra un aviso, quizá no hay commit; quizá solo hay retirada de señal (`signal.notify + neutral → emerge.close`).
- **Cuándo sí cambiar a BOOK_CANON**: si hay obligación explícita de reconocimiento (registrado en el sistema):
- "He leído y entiendo esta advertencia"
- "Entiendo que esta acción no se puede deshacer"
- "Acepto las condiciones"
### A.3 `commit.remove` vs `commit.delete` vs `commit.unselect`
- **Status de `remove` **: **BOOK_CANON**
- **Libro Cap 23 §5** lista `delete` (destrucción consumada). `remove` no aparece.
- **Decisión del autor**: distinción de tres verbos sobre operaciones de retirada/eliminación.
- **Texto doctrinal para el libro**:
> `remove` no significa destruir. Significa retirar un elemento de una colección, relación o conjunto operativo. Si el elemento deja de existir o deja de estar disponible, corresponde `delete`. Si solo deja de estar seleccionado, corresponde `unselect`.
### A.4 `commit.confirm`
- **Status**: **CANDIDATE**
- **Libro Cap 23 §5** lista `submit` , `complete` . `confirm` no aparece.
- **Decisión del autor**: NO canonizar todavía.
- **Problema**: "confirmar" muchas veces no es el resultado final, sino un paso previo. El botón dice "Confirmar" pero el evento real puede ser `delete` , `submit` , `apply` , `authorize` o `acknowledge` .
- **Cuándo sí cambiar a BOOK_CANON**: si hay casos donde el resultado aplicado sea literalmente "confirmación registrada", no acción posterior (confirmar asistencia, confirmar lectura, confirmar email).
### A.5 `commit.set`
- **Status**: **BOOK_CANON**
- **Libro**: Cap 25 ejemplo slider menciona `commit.set + affirm` pero no figura en lista canónica de Cap 23.
- **Decisión del autor**: formalizar en Cap 23 §5.
- **Casos canónicos**: slider, sort, criterio de filtro, valor de un picker, tamaño de página, zoom, preferencia local, criterio de ordenación, valor numérico.
- **Texto doctrinal para el libro**:
> `commit.set` comunica que un valor, criterio o parámetro ha quedado aplicado. Diferente de `save` (persistir globalmente), `submit` (enviar formulario), `complete` (culminar flujo), `select` (elegir un item).
### A.6 `commit.apply`
- **Status**: **BOOK_CANON**
- **Libro Cap 29** (delegate) usa `commit.apply` en ejemplos. Cap 23 §5 no lo lista.
- **Decisión del autor**: formalizar en Cap 23 §5.
- **Texto doctrinal para el libro**:
> `commit.apply` comunica que un conjunto de cambios o una operación se ha aplicado. Diferente de `save` (guardar) — apply puede aplicar sin persistir; save persiste.
### A.7 `commit.move`
- **Status**: **BOOK_CANON** (con distinción de `reorder` )
- **Decisión del autor**: aceptar si se distingue:
- `commit.move` → un elemento cambia de lugar
- `commit.reorder` → una colección cambia de orden
- **Caso típico**: `handle.drop → commit.move + affirm` o `handle.drop → commit.reorder + affirm` según si lo que cambió fue la posición de UN item o el orden de la colección.
### A.8 `commit.upload`
- **Status**: **CANDIDATE**
- **Decisión del autor**: dudoso como commit. Subir un archivo es proceso (`sustain.uploading`) que termina en `commit.complete` (éxito) o `commit.fail` (error). Como verbo de resultado quizá es redundante con `commit.complete` .
- **Mantener** como candidato hasta que haya caso donde "upload" sea el resultado final no reducible a complete/attach/add/apply.
### A.9 `commit.partial`
- **Status**: **CANDIDATE / revisar**
- **Decisión del autor**: probablemente NO es verbo. "Partial" suena a estado o resultado incompleto, no a acción.
- **Alternativas mejores**:
- `commit.complete` + variant `partial`
- `commit.fail + risk`
- `sustain.partial` (estado, no acción)
- **A revisar antes de canonizar**.
### A.10 `commit.block`
- **Status**: **CANDIDATE / revisar**
- **Decisión del autor**: probablemente NO es verbo de commit. "Blocked" suele ser estado, no resultado aplicado por el usuario.
- **Alternativas mejores**:
- `signal.alert + threat`
- `commit.fail + risk`
- `sustain.blocked + risk` (estado)
- **A revisar antes de canonizar**.
### A.11 `commit.unselect`
- **Status**: **BOOK_CANON**
- **Libro Cap 23 §5** lista `select` pero no `unselect` . Pasa el par natural al canon.
- **Decisión del autor (transcrita literal)**:
> Seleccionar y deseleccionar son resultados aplicados sobre el estado de selección de un elemento. Eso es `commit`, porque el resultado queda aplicado.
> - No es `remove`: no estás eliminando el item ni sacándolo de una colección funcional; solo estás cambiando su estado de selección.
> - No es necesariamente `toggle`: `toggle` describe mejor el mecanismo binario o el control, pero no expresa tan bien el resultado semántico concreto.
>
> Regla final:
> - `select` / `unselect` → resultados sobre estado de selección
> - `toggle` → inversión binaria genérica
> - `remove` → retirada, eliminación o salida de colección
- **Aplicado en**: calendar, combobox, grid-list, listbox, select, tag-group.
---
## B. Adopciones interpretativas (no literales en el libro)
### B.1 Cancelación de drag = `commit.cancel`
- **Status**: **BOOK_CANON** (composición canónica)
- **Libro Cap 25 §4** cubre fases pick → carry → drop. No aborda explícitamente Escape durante carry.
- **Decisión del autor**: la cancelación de un drag es composición `handle + commit.cancel` . No hay drop, no hay resultado aplicado, la manipulación se aborta.
- **Para el libro**: añadir al capítulo de handle como composición canónica.
### B.2 Scroll programático = `shift.navigate`
- **Status**: **BOOK_CANON** (con matiz)
- **Libro Cap 27 §5** lista `shift.navigate` con ejemplos a escala "Lista → detalle. Página A → página B".
- **Decisión del autor**: aclarar que `shift.navigate` puede operar a varias escalas:
- entre páginas
- entre vistas
- entre pasos
- dentro de una lista (programáticamente)
- hasta una celda
- hasta un índice
- **Distinción**: usuario desplaza manualmente → `handle.scroll` ; sistema mueve viewport → `shift.navigate` . **No** crear `shift.scrollto` todavía.
### B.3 Cambio de tamaño del modelo de datos
- **Status**: **LOCAL_EXTENSION / CANDIDATE**
- **Decisión del autor**: NO regla general del libro todavía. Caso por caso.
- **Regla doctrinal aplicable** (ya en el libro Cap 4 §1, recordatorio):
> Un cambio interno de datos solo se convierte en evento cuando se vuelve perceptible o cambia lo que el usuario puede hacer, debe atender o necesita interpretar.
- **Si el cambio merece evento**, el verbo correcto depende del caso:
- `signal.notify + neutral` — si avisa de nuevos items
- `emerge.reveal` — si aparecen elementos
- `commit.set + neutral` — si el sistema aplica un nuevo valor operativo visible (tamaño de dataset, criterio)
### B.4 Sort de tabla = `commit.set`
- **Status**: **BOOK_CANON** (como ejemplo en commit.set)
- **Decisión del autor**: ordenar por columna no es reordenar manualmente items; es fijar un criterio.
- **Distinción**:
- sort by criterion → `commit.set`
- manual reorder → `handle.reorder` → `commit.reorder`
- **Para el libro**: añadir como ejemplo de `commit.set` cuando se introduzca ese verbo.
### B.5 Eventos no perceptibles no son eventos
- **Status**: **BOOK_CANON** (regla doctrinal)
- **Libro Cap 4 §1** ya tiene la regla pero conviene reforzar.
- **Texto doctrinal para el libro** (añadir como nota explícita en Cap 4):
> No todo cambio de estado necesita evento. Un estado puede volver automáticamente a su forma base sin producir un evento semántico si el usuario no necesita interpretarlo como cambio relevante.
- **Ejemplo de aplicación**: timer interno que revierte `copied=false` tras N ms en clipboard. Es estado (`data-copied`), no evento sema.
### B.6 Toggle con dos eventos direccionales
- **Status**: **BOOK_CANON** (posibilidad direccional, NO canonizar intents)
- **Libro Cap 22 §10** ejemplo: "Toggle: contact.press → commit.toggle + affirm". UN evento.
- **Decisión del autor**: aceptar la POSIBILIDAD de dos eventos direccionales, pero NO fijar intents por defecto.
- **Texto doctrinal para el libro**:
> Un toggle puede modelarse como un solo evento de inversión o como dos eventos direccionales si la diferencia entre activar y desactivar importa para el usuario. El intent de cada dirección depende del contexto.
- **Ejemplos del autor**:
- Activar notificaciones: check → affirm, uncheck → neutral
- Desactivar tracking: uncheck → affirm
- Desmarcar consentimiento obligatorio: uncheck → risk
- **Nota para la implementación**: el checkbox actual del proyecto fija `check=affirm` / `uncheck=neutral` como defaults razonables; los consumidores pueden override per-instance.
### B.7 Intent en `contact` como anticipación visual únicamente
- **Status**: **BOOK_CANON** (regla de buena práctica)
- **Libro Cap 22 §11** ya tiene la doctrina ("el intent fuerte no debería vivir en el contacto").
- **Decisión del autor**: el evento `contact.*` no debe cargar intent fuerte; el `intent` prop del componente puede afectar visualmente (data-color, forma) pero el evento sema se mantiene neutro.
- **Aplicado en**: Button (`contact.activate` sin intent en el evento; `intent` prop drives data-color).
- **Conecta con D.3**: la family policy actual `'allowed'` no comunica "discouraged" — requiere refinamiento.
---
## C. Cluster decisions
### C.1 `clear` field — RESUELTO
- **Status**: **BOOK_CANON** (mapeo a verbo existente)
- **Decisión del autor**: `commit.reset` . 10 morfos actualizados.
- **Para el libro**: añadir como ejemplo de `commit.reset` cuando se introduzca `commit.set` /`commit.reset` al libro.
### C.2 `unselect` — RESUELTO
- Ver A.11 — promovido a verbo BOOK_CANON.
### C.3.a Renames de forma (mecánicos)
- **Status**: PROJECT_CANON (no requieren cambio en el libro)
- 11 events renombrados a `{family}-{verb}-{variant}` para alinearse con la convención de naming:
- `carousel.shift-slide` → `shift-navigate-slide`
- `feed.shift-focus-item` → `shift-navigate-focus-item`
- `feed.commit-load-more` → `commit-submit-load-more`
- `file-upload.commit-add` → `commit-set-add`
- `file-upload.signal-reject` → `signal-warn-reject`
- `form.signal-invalid` → `signal-warn-invalid`
- `number-field.handle-scrub` → `handle-drag-scrub`
- `range-calendar.commit-start` → `commit-select-start`
- `range-calendar.commit-range` → `commit-select-range`
- `tags-input.commit-add` → `commit-set-add`
- `tags-input.signal-reject` → `signal-warn-reject`
### C.3.b Correcciones doctrinales
- **Status**: BOOK_CANON (precedent Button)
- `command.commit-invoke` (declared `submit + fulfill` ) → `commit-submit-invoke + submit + affirm` . Cambio de intent (`fulfill` → `affirm` ) por Cap 22 §8 (celebrate-before-time es antipatrón). Mismo precedent que Button.
---
## D. Decisiones arquitecturales
### D.1 Cada actor declara sus eventos
- **Status**: **BOOK_CANON**
- **Texto doctrinal para el libro** (capítulo de composición o apéndice técnico):
> Un componente no debe declarar eventos que no produce. En una composición, cada actor declara su parte del evento.
- **Ejemplo**: un Button no declara `commit.delete + loss` si solo registra el click; declara `contact.activate` . El flujo, diálogo o acción que realmente elimina declara `commit.delete + loss` . Esto evita sobrecargar el botón y explica por qué la gramática necesita composición.
### D.2 Eventos del contrato que no se disparan
- **Status**: **IMPLEMENTATION_CONTRACT** (no doctrina del libro)
- **Decisión del autor**: doctrinalmente peligroso si se presenta mal (parece que el sistema promete eventos inexistentes). NO pasarlo al cuerpo del libro.
- **Tratamiento**: apéndice técnico con metadata explícita:
```ts
emission: 'runtime' | 'host' | 'external' | 'declared-only'
// o:
implemented: true | false
```
- **Acción del proyecto**: añadir flag `emission` al MorfoEvent type en una iteración futura para hacer explícito qué eventos se emiten en runtime vs cuáles son declarados sin emisor (contract surface para testing, analytics, accesibilidad externa).
### D.4 Campo `expression` en el morfo: cómo se rellena la firma sema
- **Status**: **IMPLEMENTATION_CONTRACT** (no doctrina del libro)
- **Decisión del autor (Lectura C)**: un morfo con eventos doctrinales declara su modo de expresión perceptual:
```ts
type SemaExpressionMode = 'pack' | 'family-default' | 'delegated' | 'none';
```
- **`pack`**: el morfo tiene un archivo `src/uix/sema/components/{kebab}.ts` con cascade rules específicas (sonido, háptica, prioridad).
- **`family-default`**: el morfo descansa en `SEMA_MAP.families[family].base` sin tuning per-componente. Apropiado cuando el componente no necesita firma diferenciada.
- **`delegated`**: el componente compone otros morfos que sí emiten (p. ej. picker emite via calendar/time-field/color-area que tienen sus propios eventos).
- **`none`**: el morfo declara contrato pero no participa en sema runtime (reservado para utilidades no perceptuales).
- **Lint**: `npm run morfo:vocabulary` valida que todo morfo con `events.length > 0` cumpla:
1. `scope` incluye `'sema'` (FAIL).
2. Existe un pack en `src/uix/sema/components/{kebab}.ts` **o** `expression !== undefined` (WARN si falla).
- **Cuándo crear pack vs `family-default` ** (criterios para D.4):
- **Crear pack** si: eventos de alta frecuencia + riesgo de fatiga (toggles, form controls), o el componente necesita una firma sobria distinta del family base, o introduce cascades con prioridad (a11y override).
- **`family-default`** si: el family base ya es la firma correcta y el componente no compite con otros del mismo family por intensidad perceptual.
### D.5 Packs para componentes de alta frecuencia (toggles)
- **Status**: **PROJECT_CANON** (decisión arquitectural sin necesidad de pasar al libro)
- **Caso**: `switch` , `toggle` , `toggle-group` emiten `commit-toggle` en bucle (settings panels, toolbars, segmented controls). Sin tuning, heredan el `family.commit.base.gain = 0.3` que es demasiado para una sesión sostenida.
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
- **Solución (2026-05-26, DEROGADA — ver la nota del 2026-08-06 al final)**: tuning `form.toggle.silent = { gain: { op: 'add', value: -0.3 } }` en `src/uix/sema/sounds.ts` . Cancelaba exactamente el `gain` del family base, dejando el default en 0 (silencio). Los intent.deltas que añaden gain (`threat: +0.1`, `fulfill: +0.05` ) seguían surgiendo, así un toggle destructivo sí emitía señal audible.
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
- **Haptic**: tap leve (`intensity: 0.3, duration: 12, delay: 0`) sustituye el tap medio del family. Replaza el `kind` para que la háptica no oscile con el intent — la carga evaluativa de un toggle se lee en `data-color` + (selectivamente) sonido, no en háptica fluctuante.
- **Doctrina**: el libro habla de "componentes de baja intensidad" (cap. 22) — esta es la materialización runtime. NO ir al libro: es decisión de tuning, no de gramática.
- **Packs concretos**: `src/uix/sema/components/{switch,toggle,toggle-group}.ts` — los tres comparten la misma firma porque comparten rol UX (un press → un flip).
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
- **REVERTIDO 2026-08-05 — los toggles recuperan voz (directiva de autor)**: el
silencio de arriba se retira para `switch` , `toggle` y `toggle-group` , que pasan a
** `commit.medium` (gain 0.1)** — audible, y un tercio de una pulsación de botón
(`contact` base 0.25) para que un flip nunca pese más que una activación. Los deltas
de intent siguen montando encima (`threat` +0.1, `fulfill` +0.05). Razón: un silencio
por defecto se percibe como componente roto, no como sobriedad; la fatiga se combate
bajando el nivel, no anulándolo. El háptico ligero de abajo NO cambia.
Se conserva el silencio, con su justificación intacta, sólo donde el silencio ES la
firma: `tooltip` (revela al pasar el ratón — sonaría en cada cruce) y `media-player`
(su propia salida ES audio, D-AP2.7).
Además, **emitir silencio dejó de costar** : `SoundChannel.handle` corta antes de
sintetizar cuando la ganancia resuelta es ≤ 0 (`chans/sound.ts`), así que un
`{family}.silent` ya no levanta dos osciladores, un filtro y una envolvente para no
sonar. Fijado por test, verificado en rojo.
- **Renombrado 2026-08-05 — el prefijo `form.` muere**: este tuning nació como
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
`form.toggle.silent` y pasó a llamarse `commit.silent` — una clave que vivió UN
DÍA: la nota siguiente la retira del catálogo entera. El prefijo `form.` entró el
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
2026-05-19 (`09e261878`) nombrando con verdad a siete controles de formulario, pero
ESTE MISMO commit (`2d562f378`) lo extendió a menús y árboles vía `form.commit.subtle`
— el D.6 de abajo llegó a escribir el nombre correcto (`commit.select`) en la misma
línea que usaba la clave incorrecta. Llegó a 50 packs, de los que exactamente uno era
el componente Form. La ley queda escrita en
[`sema.md` § Tuning naming shapes ](../architecture/sema.md#tuning-naming-shapes ) —
**el primer segmento es la familia cuya base modifica el tuning, nunca un
componente** — y la vigila `src/uix/sema/sounds-grammar.test.ts` . Renombres del
mismo barrido: `form.commit.soft` → `commit.soft` , `form.commit.subtle` →
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
`commit.subtle` , `tooltip.silent` → `emerge.silent` (ambas retiradas al día
siguiente), `tabs.select.soft` → `commit.select.soft` . Sin cambio de
comportamiento: mismos deltas, mismas ganancias. **Claves vivas hoy: sólo
`commit.soft` , `commit.subtle` , `commit.select.soft` , `commit.medium` y las
`emerge.*` ** — el enumerado generado está en
[`canon/vocabularies.md` ](../canon/vocabularies.md#sound-tunings ).
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
- **EL SILENCIO DEJA DE SER ARITMÉTICA — 2026-08-06 (directiva de autor)**: «el silencio
no admite verbos ni intents, es universal, por lo tanto es un valor canónico que cuando
se le envía al canal semántico éste simplemente lo ignora y no envía nada al
soundengine». Las tres claves silenciadoras (`commit.silent`, `emerge.silent` ,
`contact.silent` ) **desaparecen del catálogo** ; en su lugar hay ** `SILENT` **, un único
valor exportado por `$uix/sema` que se declara en el slice del canal y que el resolver
honra **retirando ese canal** de la firma — la forma que el propio motor ya prescribía
(«muting DROPS the channel rather than scaling to zero, because a `0` still buzzes»).
Un delta de intent ya no puede resucitarlo, porque no queda ningún número que mover.
MOTIVO MEDIDO, y desmiente la promesa de la «Solución» de arriba: el cero no era
silencio. Los deltas de intent suman **rugosidad** (`risk` +0.2, `threat` +0.4), lo que
cruza el umbral del AM del motor, y como el modulador se conecta al `AudioParam` de la
envolvente —y conectar a un `AudioParam` SUMA, no multiplica— el trémolo pasaba a ser
la señal entera. Renderizado offline con el grafo real: `risk` ** − 13,9 dBFS** y `threat`
** − 6,7 dBFS** desde una firma declarada a `gain 0` , frente a ** − 9,3 dBFS** de un botón
normal. El «silencio» era lo más fuerte de la interfaz, y lo que sonaba era un zumbido
sin ataque ni caída cortado en seco. Fijado por tests en `resolver.test.ts` (universal
para toda familia e intent, y liftable sólo por REEMPLAZO) y por
`sounds-grammar.test.ts` , que ahora prohíbe tanto una clave `*.silent` como cualquier
afinado que deje su familia en `gain <= 0` .
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
### D.6 Packs para superficies de menú y árboles
- **Status**: **PROJECT_CANON**
- **Caso**: `menubar` , `navigation-menu` , `context-menu` , `dropdown-menu` , `tree-view` , `tree-grid` — superficies navegacionales de alta frecuencia. El usuario abre/cierra menús y expande/contrae nodos decenas de veces por sesión. Sin tuning, heredan `family.emerge.base.gain = 0.2` y `family.commit.base.gain = 0.3` — demasiado prominente.
- **Solución**: packs por componente que combinan tuning emerge soft + commit subtle:
- **emerge.open (menús, expand)**: `emerge.soft` (gain 0.08) — el contenido se revela sin competir con la superficie que lo invoca.
- **emerge.close (menús, collapse)**: `emerge.exit.soft` (gain 0.05, descending) — disciplina de dirección compartida con dialog/drawer/popover.
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
- **commit.select (item de menú, nodo de árbol)**: `commit.subtle` (gain 0.03) + `tap` leve. Más sobrio que radio-group porque la cascada típica es "menú cierra + item commit + nueva superficie aparece" — tres señales en milisegundos, hay que repartir intensidad.
uix(navigation-menu): navegar no fija nada, y el megamenú que se abre solo no debería sonar
T-1 de PLAN-sidebar.md §6. El `Link` emitía `commit-select + affirm` al navegar.
El libro lo nombra: TABLA 9.3, «Success de navegación — cambio de contexto con
logro», corregido como «shift + commit.fulfill si procede»; cap. 27 §2 «shift no
es commit… ir a otra pantalla no implica que la operación haya terminado»; y la
apertura de cap. 10, «una navegación no es exitosa por cambiar de pantalla».
Nada queda fijado al pulsar un enlace del nav: `aria-current="page"` es la huella
que deja el router DESPUÉS, no un estado que la parte fije.
Ahora habla el par de cap. 22 §9 —«Link → contact.press seguido de shift.navigate:
la presión no es la navegación»—, el mismo que la fila del Sidebar declaró ayer:
- `contact-activate` ANCLADO en el enlace pulsado (parte repetida → `partInstance`).
- `shift-navigate` en el `provider`, sin anclar: `data-event-*` es UNA ranura por
elemento, y el sujeto del cruce es el `<nav>` que cruza como unidad, no el
control que lo inicia. Sólo si el `<a>` tiene `href` — aquí no es un opt, viaja
en restProps, así que se lee del elemento que la parte ya tenía atado.
Esto REABRE la decisión del 2026-08-05 (ledger A-54), no la pisa: mover el evento
fuera del marco estaba bien; la familia era el defecto.
El pack estuvo a punto de borrarse, y esa habría sido la equivocación de la
sesión. Al quitarle la regla del commit se quedaba con dos selectores vacíos y
propuse retirarlo como ruido. El autor paró y pidió releer: la pregunta no era
qué escribe el fichero, sino qué debe decir la aparición del megamenú. Se abre
por HOVER, y medido con el default de familia un barrido del puntero por dos
triggers y salir de la barra emitía `open` · `open` · `close` — tres sonidos, 6
osciladores, sin un solo clic. Cap. 17 §3 («emerge — normalmente no necesita
sonido»), cap. 26 §7, cap. 32 §10-§11, cap. 5 §11. Así que `emerge-open` y
`emerge-close` son SILENT, la postura que `tooltip` y el flyout del `sidebar`
(D-SB.3) ya tienen para el mismo gesto. El pack DIFIERE del default y vuelve a
ser un pack.
Enmienda D.6 de book-deviations.md (PROJECT_CANON): `navigation-menu` sale del
alcance del `commit.subtle`, y quedan corregidas tres cláusulas suyas caducadas
— el `emerge-open/close` declarado desde el 2026-08-05, el `commit.subtle` que
murió en 86fa9a1b7 sin sustituto, y el `emerge.soft` (0.08) que el catálogo
absorbió (la base `open` es 0.09). `menubar` tiene la misma clase de defecto en
su trigger y NO se toca: otro componente, otra sesión.
Medido en Chromium headless (la pantalla oculta congela rAF; sonda desde la raíz):
- clic en enlace → `contact-activate` (familia contact, sin intent) sobre el
`[data-navigation-menu-link]` con `press-squeeze` corriendo EN el enlace a +8 y
+30 ms y retirado a +120 · `shift-navigate` sobre `[data-navigation-menu]` ·
4 osciladores · cero estampados de familia `commit`.
- Enter sobre el enlace enfocado: idéntico (`handleListKeydown` no intercepta
Enter; el ancla nativa dispara el click). Sin `href`: sólo contacto, 2 osc.
- RTL: mismo par, sin `data-event-direction` — un `href` no tiene sentido propio.
- El SILENT demostrado por diferencial con la MISMA maquinaria: el barrido sigue
estampando `emerge-open`/`emerge-close` y baja de 6 osciladores a 0.
- Enlace pulsado con el panel abierto: cuatro ocurrencias en tres nodos distintos
(open@trigger · contact@link · shift@nav · close@trigger), 4 osciladores — las
dos silenciosas no compiten con el par del enlace.
La demo clavaba las cuatro previsualizaciones en el `<li>`: con eventos en tres
partes, el ▶ del contacto habría encogido el item entero. Ahora resuelve la parte
del contrato compilado (mismo arreglo que la revisión adversarial del sidebar).
Medido: contacto→link, shift→nav, emerge→trigger.
El README de soma describía el estado ANTERIOR al 2026-08-05 (target `item`,
emisión en `openNow`, cascada por `closest()`): reescrito entero.
Gates: check 72 errores con CERO en los ficheros tocados (el de nav-menu que
queda vive en eidos/navigation-menu-content.svelte, `sideOffset`, intacto) ·
suite nav 8/8, cuatro contratos nuevos · sema 327/327 · morfo:check exit 0 ·
morfo:vocabulary 0 (el WARN es de cropper) · component:audit --only
navigation-menu PASS · eidos-lint 32 morfo-backed / 0 invalid · docs:check 0/640
· rtl:check 0 · blocks:check 0/19.
Queda ABIERTO y no es de este eje: `emerge-open` estampa en el TRIGGER y le
corre `present-rise` encima —el botón «aparece» como si fuera él la superficie—,
y la receta pinta abierto/seleccionado con `background` plano sobre un radio
fijo. Los dos son anteriores a este commit y piden su propio eje (la doctrina ya
tiene la forma: `targetFallback`, resolución por estado de montaje).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **Coherencia**: dropdown-menu y context-menu comparten firma idéntica (el usuario no debe aprender dos "sonidos de menú"). Tree-view y tree-grid idem.
- **ENMIENDA 2026-08-19 — `navigation-menu` sale del alcance de esta entrada.** Su `Link` ya no emite `commit-select` : navegar no fija nada, y un `commit` ahí es el antipatrón «Success de navegación» del libro (TABLA 9.3), reforzado por cap. 27 §2 («shift no es commit») y por la apertura de cap. 10 («una navegación no es exitosa por cambiar de pantalla»). El gesto habla ahora el par de cap. 22 §9 — `contact-activate` en el enlace y `shift-navigate` en el `<nav>` —, y **ninguna de las dos familias se afina** : traen su carácter del mapa (`touch` + `tick` háptico · `slide` ), que es el mismo silencio que guarda el pack del `Sidebar` para el mismo acto. La preocupación que originó D.6 sigue siendo válida y se satisface por otra vía: el par nuevo es más sobrio que el `commit` que sustituye.
- **Dos cláusulas de esta entrada estaban caducadas cuando se enmendó**, y quedan corregidas aquí: (1) «menubar y navigation-menu no tienen evento de open/close declarado en el morfo» dejó de ser cierto el 2026-08-05, cuando `navigation-menu` declaró `emerge-open` / `emerge-close` sobre su `trigger` ; (2) el `commit.subtle` (0.03) que esta entrada prescribía para `navigation-menu` **llevaba tiempo sin estar implementado** — murió en `86fa9a1b7` (2026-08-06, «el sonido se ELIGE, no se modula»), nadie nombró un sonido más quedo en su lugar y el evento sonaba a la base de familia. (3) Y el `emerge.soft` (0.08) de esta entrada lo absorbió el catálogo: la base `open` es 0.09, por eso las reglas `emerge` de los menús de clic están vacías y siguen siendo correctas. Para `navigation-menu` , en cambio, la respuesta NO es «soft» sino ** `SILENT` ** (firmado 2026-08-19): su megamenú se abre por HOVER, y medido con el default de familia un barrido por dos triggers y salir de la barra sonaba tres veces sin un clic — cap. 17 §3, cap. 26 §7, cap. 32 §10; la misma postura que `tooltip` y que el flyout del `sidebar` (D-SB.3). Una desviación PROJECT_CANON que describe una afinación que el código no aplica es una fuente que miente: el registro se actualiza en el mismo pase que el cableado.
- **`menubar` queda pendiente y NO se toca aquí**: su `commit-select` vive en el `trigger` de primer nivel, o sea en el gesto que DESPLIEGA un menú, que por cap. 26 §5 es una aparición. Misma clase de defecto, otro componente, otra sesión (regla `no-cascade-changes` ).
- **Caveat (`tree-view` / `tree-grid` ) — RESUELTO (verificado 2026-07-12, SEM-4)**: la
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
emisión aterriza vía `targetOverride` en el elemento real (`branchEl` / `rowEl` ) y los
packs construyen sus selectores con `onBranch` / `onRow` (`semaSelector(morfo,
'branch'|'row')`) — emisión y cascada casan de punta a punta.
- **Caveat (emisión soma) — RESUELTO (verificado 2026-07-12, SEM-4)**: los 6 providers
emiten vía `runtime.trigger` (dropdown/context: `open` /`close`/`commit-select`;
uix(navigation-menu): navegar no fija nada, y el megamenú que se abre solo no debería sonar
T-1 de PLAN-sidebar.md §6. El `Link` emitía `commit-select + affirm` al navegar.
El libro lo nombra: TABLA 9.3, «Success de navegación — cambio de contexto con
logro», corregido como «shift + commit.fulfill si procede»; cap. 27 §2 «shift no
es commit… ir a otra pantalla no implica que la operación haya terminado»; y la
apertura de cap. 10, «una navegación no es exitosa por cambiar de pantalla».
Nada queda fijado al pulsar un enlace del nav: `aria-current="page"` es la huella
que deja el router DESPUÉS, no un estado que la parte fije.
Ahora habla el par de cap. 22 §9 —«Link → contact.press seguido de shift.navigate:
la presión no es la navegación»—, el mismo que la fila del Sidebar declaró ayer:
- `contact-activate` ANCLADO en el enlace pulsado (parte repetida → `partInstance`).
- `shift-navigate` en el `provider`, sin anclar: `data-event-*` es UNA ranura por
elemento, y el sujeto del cruce es el `<nav>` que cruza como unidad, no el
control que lo inicia. Sólo si el `<a>` tiene `href` — aquí no es un opt, viaja
en restProps, así que se lee del elemento que la parte ya tenía atado.
Esto REABRE la decisión del 2026-08-05 (ledger A-54), no la pisa: mover el evento
fuera del marco estaba bien; la familia era el defecto.
El pack estuvo a punto de borrarse, y esa habría sido la equivocación de la
sesión. Al quitarle la regla del commit se quedaba con dos selectores vacíos y
propuse retirarlo como ruido. El autor paró y pidió releer: la pregunta no era
qué escribe el fichero, sino qué debe decir la aparición del megamenú. Se abre
por HOVER, y medido con el default de familia un barrido del puntero por dos
triggers y salir de la barra emitía `open` · `open` · `close` — tres sonidos, 6
osciladores, sin un solo clic. Cap. 17 §3 («emerge — normalmente no necesita
sonido»), cap. 26 §7, cap. 32 §10-§11, cap. 5 §11. Así que `emerge-open` y
`emerge-close` son SILENT, la postura que `tooltip` y el flyout del `sidebar`
(D-SB.3) ya tienen para el mismo gesto. El pack DIFIERE del default y vuelve a
ser un pack.
Enmienda D.6 de book-deviations.md (PROJECT_CANON): `navigation-menu` sale del
alcance del `commit.subtle`, y quedan corregidas tres cláusulas suyas caducadas
— el `emerge-open/close` declarado desde el 2026-08-05, el `commit.subtle` que
murió en 86fa9a1b7 sin sustituto, y el `emerge.soft` (0.08) que el catálogo
absorbió (la base `open` es 0.09). `menubar` tiene la misma clase de defecto en
su trigger y NO se toca: otro componente, otra sesión.
Medido en Chromium headless (la pantalla oculta congela rAF; sonda desde la raíz):
- clic en enlace → `contact-activate` (familia contact, sin intent) sobre el
`[data-navigation-menu-link]` con `press-squeeze` corriendo EN el enlace a +8 y
+30 ms y retirado a +120 · `shift-navigate` sobre `[data-navigation-menu]` ·
4 osciladores · cero estampados de familia `commit`.
- Enter sobre el enlace enfocado: idéntico (`handleListKeydown` no intercepta
Enter; el ancla nativa dispara el click). Sin `href`: sólo contacto, 2 osc.
- RTL: mismo par, sin `data-event-direction` — un `href` no tiene sentido propio.
- El SILENT demostrado por diferencial con la MISMA maquinaria: el barrido sigue
estampando `emerge-open`/`emerge-close` y baja de 6 osciladores a 0.
- Enlace pulsado con el panel abierto: cuatro ocurrencias en tres nodos distintos
(open@trigger · contact@link · shift@nav · close@trigger), 4 osciladores — las
dos silenciosas no compiten con el par del enlace.
La demo clavaba las cuatro previsualizaciones en el `<li>`: con eventos en tres
partes, el ▶ del contacto habría encogido el item entero. Ahora resuelve la parte
del contrato compilado (mismo arreglo que la revisión adversarial del sidebar).
Medido: contacto→link, shift→nav, emerge→trigger.
El README de soma describía el estado ANTERIOR al 2026-08-05 (target `item`,
emisión en `openNow`, cascada por `closest()`): reescrito entero.
Gates: check 72 errores con CERO en los ficheros tocados (el de nav-menu que
queda vive en eidos/navigation-menu-content.svelte, `sideOffset`, intacto) ·
suite nav 8/8, cuatro contratos nuevos · sema 327/327 · morfo:check exit 0 ·
morfo:vocabulary 0 (el WARN es de cropper) · component:audit --only
navigation-menu PASS · eidos-lint 32 morfo-backed / 0 invalid · docs:check 0/640
· rtl:check 0 · blocks:check 0/19.
Queda ABIERTO y no es de este eje: `emerge-open` estampa en el TRIGGER y le
corre `present-rise` encima —el botón «aparece» como si fuera él la superficie—,
y la receta pinta abierto/seleccionado con `background` plano sobre un radio
fijo. Los dos son anteriores a este commit y piden su propio eje (la doctrina ya
tiene la forma: `targetFallback`, resolución por estado de montaje).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
menubar: `commit-select` ; nav-menu: `emerge-open` /`emerge-close` desde 2026-08-05 y
`contact-activate` /`shift-navigate` desde 2026-08-19, ver la ENMIENDA de arriba;
trees: `emerge-expand` /`emerge-collapse` +
`commit-select` ). Verificado en vivo: stamps `open · emerge · active` y
`commit-select · commit · affirm` en el navegador. Este párrafo quedó STALE varias
semanas y una auditoría clean-room (2026-07-10) lo citó como evidencia de dormancia —
lección: el registro se actualiza EN EL MISMO PASE que el cableado.
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
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
### D.7 Sonido canónico y samples — **RETIRADA el 2026-08-06, por disolución**
- **Status**: **RETIRADA** . No derogada por cambio de opinión: **disuelta por un
cambio de arquitectura que hace imposible el defecto que prohibía.** La
doctrina del autor que la originó sigue siendo cierta, pero ahora la sostiene
el orden de resolución en vez de la disciplina de quien escribe un pack.
- **Qué prohibía y por qué.** «Los samples no deben sustituir la firma semántica
base cuando esa sustitución impide la modulación por intent.» El mecanismo era
real: `sound()` devolvía una firma COMPLETA y la cascada la aplicaba en modo
`replace` DESPUÉS de los deltas de intent, así que canonizar un sample sobre un
evento `commit` borraba el perfil evaluativo — un `fulfill` perdía su +300 Hz
ascendente. La regla se enunció como lista de familias prohibidas, se le
encontró un infractor (`proof-of-human`), se enmendó para sacar a `handle` /
`sustain` / `delegate` (familias sin `base.sound` : donde no hay base no hay
nada que aplastar) y se le añadió un guard.
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
- **Por qué ya no hace falta.** Desde el 2026-08-06 el sonido no se resuelve por
capas: se ELIGE, en dos búsquedas.
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
nombre = per-emit ?? cascada ?? pack ?? morfo ?? familia[verbo] ?? familia.default
sonido = pack[`${nombre}.${intent}`] ?? pack[nombre] ?? nada
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
El intent **selecciona un sonido entero** (`tick.threat` no es un `tick`
deformado) y, si el pack no trae variante para ese intent, se desprecia el
intent y suena la base. No queda nada que aplastar porque no queda aritmética:
un nombre sustituye a un nombre. El tipo de una regla acepta un `SoundName` o
`SILENT` , y ni el producto ni un tema ni la app pueden escribir un parámetro.
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
- **Lo que se conserva de la doctrina, y dónde vive ahora:**
- «El silencio es una firma válida» → `SILENT` , valor canónico honrado por el
resolver retirando el canal (D.5 + `sounds-grammar.test.ts` ).
- «Los packs sólo se crean cuando corrigen una diferencia perceptiva real» →
sigue vigente como criterio de autor, y hoy es barato cumplirlo: un pack que
no tiene nada que decir no tiene nada que escribir.
- «Los samples son recursos de producto, no canon por defecto» → el catálogo
los admite con nombre (`ping`, `error` ) y una app puede autorar los suyos por
`overrides.cascade` , que sigue abierto a propósito.
- **⚠️ EL LÍMITE FÍSICO, medido — lo único de esta entrada que hay que seguir
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
sabiendo.** `playSample` lee **exactamente dos campos** de la firma:
`sampleUrl` y `gain` . No hay `playbackRate` ni `detune` . Luego **sobre una
grabación el intent sólo puede mover el volumen**. Un nombre con fichero que
deba llevar carga evaluativa **necesita un fichero por intent** (`tick.mp3` Y
`tick.threat.mp3` ), no uno solo modificado. Con síntesis el problema no existe
porque cada variante se diseña entera. Es física del audio, no política: no se
diseña alrededor de ella.
Este límite dejó de ser una excepción y pasó a ser **la forma general del
sistema**: un intent siempre selecciona una entrada distinta, venga de un
oscilador o de un fichero. Lo que antes era el caso raro de `signal` es hoy
cómo funciona todo.
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
- **Lo que sigue descartado permanentemente**: `sampleOverlay` (sample como capa
adicional sobre el synth). Sobreingeniería — añade mixing en WebAudio, capa de
resolver y mandos extra al diseñador, para casos raros.
### S-07 — **DISUELTA junto con D.7**
El hallazgo S-07 de [`AUDIT-sema-2026-08-05` ](../process/AUDIT-sema-2026-08-05.md )
decía que las 14 claves de escalera de `SOUND_TUNINGS` fijaban `gain` como número
DESNUDO, y un número desnudo se aplica en `replace` igual que un sample: cambiar
un sample por `soundTuning('commit.soft')` dejaba el intent igual de aplastado.
Era el mismo defecto que D.7 una capa más abajo, y quedó ABIERTO por decisión del
autor («se trata más detenidamente»).
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
Ya no existe: ** `SOUND_TUNINGS` fue retirado el 2026-08-06**, y con él la
aritmética entera. No hay `gain` que fijar ni delta que borrar: un evento y su
intent eligen una entrada del pack. Los ~150 usos que el hallazgo contaba son
hoy nombres, y 135 de las reglas que los llevaban se borraron porque no decían
más que el defecto de su familia.
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
### D.3 Family policy: separar requirement de guidance
- **Status**: **BOOK_CANON** (concepto) + cambio inmediato en el proyecto
- **Decisión del autor**: la policy actual `'allowed' | 'expected' | 'optional'` mezcla dos cosas: requisito de tipo y guía doctrinal. Separar:
```ts
intentRequirement: 'required' | 'optional' | 'forbidden'
intentGuidance: 'expected' | 'contextual' | 'discouraged'
```
- **Policy propuesta**:
| Family | intentRequirement | intentGuidance |
|---|---|---|
| `contact` | optional | discouraged |
| `commit` | required | expected |
| `signal` | required | expected |
| `handle` | optional | contextual |
| `emerge` | optional | contextual |
| `shift` | optional | contextual |
| `sustain` | optional | contextual |
| `delegate` | optional | contextual |
- **Implementación**: aplicar en `src/uix/sema/types.ts:SEMA_FAMILY_POLICY` . TypeScript deriva `IntentExpectedFamily` desde `intentRequirement === 'required'` . `intentGuidance` queda como campo doctrinal de documentación + posible lint en el futuro.
### D.8 Channels: qué es canal y qué no
feat(sema): los toggles recuperan su CONTACTO — la voz vuelve al momento que el libro le da
Tras leer el corpus entero de sema y del motor de sonido (los tres planes, el
handoff vivo, sema.md, CANON, channels, el README del art y D.7/D.8 literales),
que es la precondicion que me estaba saltando.
1) EL CONTACTO EXISTE (directiva del autor: «1 su contact-press»)
El libro le da a un Toggle DOS momentos, y el codigo solo tenia uno:
- cap. 23 §9 empareja el Toggle con `contact.press` Y `commit.toggle`;
- cap. 22 nombra «un switch que muestra estado pressed» como contact;
- CANON §8 regla 1: «contact precede al resultado cuando hay accion directa».
switch, toggle y toggle-group declaran ahora `contact-press` (family contact,
verbo press, sequence 'pre', SIN intent por cap. 22 §11) ademas de su
`commit-toggle`. Los providers los disparan en ese orden. Solo 4 de 91 morfos
con eventos expresaban `contact`; ahora 7.
Y el reparto de la voz cambia de sitio, que es el fondo del asunto:
- el CONTACTO habla — `contact.soft` (gain 0.08, clave nueva): el «click breve
opcional» de la tabla de canales del cap. 22, un tercio de una pulsacion de
boton para que un flip nunca pese mas que una activacion;
- el COMMIT calla — `SILENT`. Es lo que pide la tabla de canales del cap. 23
(«sonido: cierre opcional»), lo que exige el Criterio 12 (ch. 7 §13) de un
control que se pulsa docenas de veces por sesion, y lo que D.5 decidio en
mayo. La consecuencia la lleva `data-state` + color, la huella de ch. 23 §3.3.
`commit.medium` —la clave que invente ayer para que sonaran— queda RETIRADA:
huerfana en cuanto la voz se mudo al contacto.
MEDIDO en navegador: un clic emite `contact-press` -> `commit-toggle`, el estado
pasa a checked, y se levantan 2 osciladores con pico 0.08. UNA sola voz, la del
contacto; el commit no sintetiza nada.
⚠️ REVERSION DOCTRINAL DECLARADA: `compile.test.ts` afirmaba, citando el ANEXO
Tabla 1, que «Toggle/Switch declara un UNICO evento; el contacto es IMPLICITO en
el gesto». El cuerpo del libro dice lo contrario donde trata el caso. El test se
actualiza dejando escrita la reversion y su procedencia, para que quien lea el
anexo sepa por que el codigo diverge.
2) D.7 VUELVE A SER CANON SIN VERSOS SUELTOS (directiva del autor)
`proof-of-human` canonizaba samples en familia `commit`: `sound()` devuelve una
firma COMPLETA y la cascada la aplica en `replace`, asi que aplastaba la
modulacion por intent que la propia entrada existe para proteger — un `fulfill`
perdia su +300 Hz / ascending / +0.05, y el fallback sintetico sonaba ciego al
intent tambien. Su cabecera afirmaba literalmente lo contrario de lo que hacia.
Ahora compone tunings con `{ op: 'add' }`: el intent conserva sus primitivos y
la regla solo aporta caracter. Un producto que quiera el ping lo registra desde
la cascada de app (capa 5b), donde un sample SI es recurso legitimo.
3) D.8 REESCRITA Y FIRMADA
La entrada decia «los packs DEBEN respetar el activeChannels del family … anadir
`sound` a `handle` tambien [es incoherente]», y el framework hace justo eso,
prescrito por sema.md §componentes continuos. La ley queda:
- `activeChannels` es el DEFAULT perceptual de la familia, no una prohibicion.
- `channels` es la palanca por evento/regla y ajusta en las DOS direcciones.
Restringir: dialog `close-after-fail`, transporte del player, VirtualList.
Ampliar: el pack del slider sobre `handle`.
- Ampliar exige justificacion perceptual escrita. La del slider es canonica: el
sonido del arrastre no es firma fija sino payload por emision — por eso
`handle` no declara `base.sound`, y por eso sema conserva TRES resolvers de
gesto cuyo unico proposito es ese sonido.
- PROHIBIDO: declarar una firma de canal que la activacion no incluye. Deja
reglas INERTES. Es comprobable por guard. Infractoras: 2 del dialog + 3 mas.
Y Announce: la propia D.8 dejo la puerta abierta («si en el futuro necesita ser
pluggable … entonces vale convertirlo en canal formal. Hoy no»). Ese futuro
llego el 2026-07-04. No fue deriva; fue no volver a escribirlo aqui.
VERIFICADO: sema+morfo 337/337 · docs:check 0/616 · check 76 = base 75 + 1 del
fichero huerfano de la auditoria · `morfo:vocabulary` limpio · prettier: el
unico aviso mio formateado, los demas ya sucios en HEAD.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
- **Status**: **PROJECT_CANON** (regla arquitectural de límites) — con dos
puntos REESCRITOS el 2026-08-06 tras la lectura completa del corpus de sema y
del motor de sonido, firmados por el autor.
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
- **Origen**: al revisar la sección D.7 emergió la tentación de promocionar ARIA a "canal a11y". Análisis honesto: era confusión categorial. Esta sección fija los límites para que nadie reincida.
feat(sema): los toggles recuperan su CONTACTO — la voz vuelve al momento que el libro le da
Tras leer el corpus entero de sema y del motor de sonido (los tres planes, el
handoff vivo, sema.md, CANON, channels, el README del art y D.7/D.8 literales),
que es la precondicion que me estaba saltando.
1) EL CONTACTO EXISTE (directiva del autor: «1 su contact-press»)
El libro le da a un Toggle DOS momentos, y el codigo solo tenia uno:
- cap. 23 §9 empareja el Toggle con `contact.press` Y `commit.toggle`;
- cap. 22 nombra «un switch que muestra estado pressed» como contact;
- CANON §8 regla 1: «contact precede al resultado cuando hay accion directa».
switch, toggle y toggle-group declaran ahora `contact-press` (family contact,
verbo press, sequence 'pre', SIN intent por cap. 22 §11) ademas de su
`commit-toggle`. Los providers los disparan en ese orden. Solo 4 de 91 morfos
con eventos expresaban `contact`; ahora 7.
Y el reparto de la voz cambia de sitio, que es el fondo del asunto:
- el CONTACTO habla — `contact.soft` (gain 0.08, clave nueva): el «click breve
opcional» de la tabla de canales del cap. 22, un tercio de una pulsacion de
boton para que un flip nunca pese mas que una activacion;
- el COMMIT calla — `SILENT`. Es lo que pide la tabla de canales del cap. 23
(«sonido: cierre opcional»), lo que exige el Criterio 12 (ch. 7 §13) de un
control que se pulsa docenas de veces por sesion, y lo que D.5 decidio en
mayo. La consecuencia la lleva `data-state` + color, la huella de ch. 23 §3.3.
`commit.medium` —la clave que invente ayer para que sonaran— queda RETIRADA:
huerfana en cuanto la voz se mudo al contacto.
MEDIDO en navegador: un clic emite `contact-press` -> `commit-toggle`, el estado
pasa a checked, y se levantan 2 osciladores con pico 0.08. UNA sola voz, la del
contacto; el commit no sintetiza nada.
⚠️ REVERSION DOCTRINAL DECLARADA: `compile.test.ts` afirmaba, citando el ANEXO
Tabla 1, que «Toggle/Switch declara un UNICO evento; el contacto es IMPLICITO en
el gesto». El cuerpo del libro dice lo contrario donde trata el caso. El test se
actualiza dejando escrita la reversion y su procedencia, para que quien lea el
anexo sepa por que el codigo diverge.
2) D.7 VUELVE A SER CANON SIN VERSOS SUELTOS (directiva del autor)
`proof-of-human` canonizaba samples en familia `commit`: `sound()` devuelve una
firma COMPLETA y la cascada la aplica en `replace`, asi que aplastaba la
modulacion por intent que la propia entrada existe para proteger — un `fulfill`
perdia su +300 Hz / ascending / +0.05, y el fallback sintetico sonaba ciego al
intent tambien. Su cabecera afirmaba literalmente lo contrario de lo que hacia.
Ahora compone tunings con `{ op: 'add' }`: el intent conserva sus primitivos y
la regla solo aporta caracter. Un producto que quiera el ping lo registra desde
la cascada de app (capa 5b), donde un sample SI es recurso legitimo.
3) D.8 REESCRITA Y FIRMADA
La entrada decia «los packs DEBEN respetar el activeChannels del family … anadir
`sound` a `handle` tambien [es incoherente]», y el framework hace justo eso,
prescrito por sema.md §componentes continuos. La ley queda:
- `activeChannels` es el DEFAULT perceptual de la familia, no una prohibicion.
- `channels` es la palanca por evento/regla y ajusta en las DOS direcciones.
Restringir: dialog `close-after-fail`, transporte del player, VirtualList.
Ampliar: el pack del slider sobre `handle`.
- Ampliar exige justificacion perceptual escrita. La del slider es canonica: el
sonido del arrastre no es firma fija sino payload por emision — por eso
`handle` no declara `base.sound`, y por eso sema conserva TRES resolvers de
gesto cuyo unico proposito es ese sonido.
- PROHIBIDO: declarar una firma de canal que la activacion no incluye. Deja
reglas INERTES. Es comprobable por guard. Infractoras: 2 del dialog + 3 mas.
Y Announce: la propia D.8 dejo la puerta abierta («si en el futuro necesita ser
pluggable … entonces vale convertirlo en canal formal. Hoy no»). Ese futuro
llego el 2026-07-04. No fue deriva; fue no volver a escribirlo aqui.
VERIFICADO: sema+morfo 337/337 · docs:check 0/616 · check 76 = base 75 + 1 del
fichero huerfano de la auditoria · `morfo:vocabulary` limpio · prettier: el
unico aviso mio formateado, los demas ya sucios en HEAD.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
- **Announce SÍ es canal desde el 2026-07-04 — y esta entrada lo había previsto.**
Su propio cierre decía: «si en el futuro `Announce` necesita ser pluggable …
entonces vale convertirlo en canal formal. Hoy no». Ese futuro llegó: el
`AnnounceChannel` es built-in, opt-in y exportado
(`src/uix/sema/chans/announce.ts`), y [`sema.md` §Announce channel ](../architecture/sema.md )
lo declara supersedente. No fue una deriva: fue la puerta que esta entrada
dejó abierta, cruzada sin volver a escribirlo aquí. Canales runtime reales: 4
([`channels.md`](../theming/channels.md)) — `visual` /`sound`/`haptic`
EXPRESAN, `announce` SUSTITUYE.
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
**Canales runtime declarables en sema (built-in del framework):**
```
sound — SoundSignature (synth/sample, modulable por intent.deltas)
haptic — HapticSignature (vibration, modulable por intent.deltas)
```
**Lo que NO es canal (y no debe convertirse en canal):**
| Cosa | Dónde vive | Razón |
|---|---|---|
| ARIA estructural (`aria-label`, `aria-expanded` , `role` , ...) | `Morfo.parts[].aria` + `.role` | Declarativo. Resuelto desde props/states. Promocionarlo a canal sería convertir lo declarativo en post-hoc DOM manipulation. |
| ARIA dinámico (live regions `aria-live` ) | Soma escribe directo en el live region DOM | Sólo un morfo lo necesita (`Announce`). Hacer canal añadiría engine surface sin caso plural. |
| Visual — motion (animaciones, transiciones) | Eidos CSS `@keyframes` reaccionando a `data-event-*` stampeado por `VisualChannel` | El stamp es la única responsabilidad de sema; el output visual es CSS. |
| Visual — color/intent (data-color, data-event-intent overlays) | Eidos recipes + design tokens | Idem. |
| Visual — presence (z-index, opacity, layout) | Eidos CSS | Idem. |
**Channel activation por familia** (en `SEMA_MAP` ):
```
contact sound + haptic
commit sound + haptic
signal sound + haptic
emerge sound (sin haptic — apariciones no son táctiles)
shift sound (sin haptic — cambio de marco)
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
handle sound + haptic (el trinquete: `step` por emisión, 2026-08-06)
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
sustain ninguno (puramente visual)
delegate ninguno (puramente estructural / visual)
```
feat(sema): los toggles recuperan su CONTACTO — la voz vuelve al momento que el libro le da
Tras leer el corpus entero de sema y del motor de sonido (los tres planes, el
handoff vivo, sema.md, CANON, channels, el README del art y D.7/D.8 literales),
que es la precondicion que me estaba saltando.
1) EL CONTACTO EXISTE (directiva del autor: «1 su contact-press»)
El libro le da a un Toggle DOS momentos, y el codigo solo tenia uno:
- cap. 23 §9 empareja el Toggle con `contact.press` Y `commit.toggle`;
- cap. 22 nombra «un switch que muestra estado pressed» como contact;
- CANON §8 regla 1: «contact precede al resultado cuando hay accion directa».
switch, toggle y toggle-group declaran ahora `contact-press` (family contact,
verbo press, sequence 'pre', SIN intent por cap. 22 §11) ademas de su
`commit-toggle`. Los providers los disparan en ese orden. Solo 4 de 91 morfos
con eventos expresaban `contact`; ahora 7.
Y el reparto de la voz cambia de sitio, que es el fondo del asunto:
- el CONTACTO habla — `contact.soft` (gain 0.08, clave nueva): el «click breve
opcional» de la tabla de canales del cap. 22, un tercio de una pulsacion de
boton para que un flip nunca pese mas que una activacion;
- el COMMIT calla — `SILENT`. Es lo que pide la tabla de canales del cap. 23
(«sonido: cierre opcional»), lo que exige el Criterio 12 (ch. 7 §13) de un
control que se pulsa docenas de veces por sesion, y lo que D.5 decidio en
mayo. La consecuencia la lleva `data-state` + color, la huella de ch. 23 §3.3.
`commit.medium` —la clave que invente ayer para que sonaran— queda RETIRADA:
huerfana en cuanto la voz se mudo al contacto.
MEDIDO en navegador: un clic emite `contact-press` -> `commit-toggle`, el estado
pasa a checked, y se levantan 2 osciladores con pico 0.08. UNA sola voz, la del
contacto; el commit no sintetiza nada.
⚠️ REVERSION DOCTRINAL DECLARADA: `compile.test.ts` afirmaba, citando el ANEXO
Tabla 1, que «Toggle/Switch declara un UNICO evento; el contacto es IMPLICITO en
el gesto». El cuerpo del libro dice lo contrario donde trata el caso. El test se
actualiza dejando escrita la reversion y su procedencia, para que quien lea el
anexo sepa por que el codigo diverge.
2) D.7 VUELVE A SER CANON SIN VERSOS SUELTOS (directiva del autor)
`proof-of-human` canonizaba samples en familia `commit`: `sound()` devuelve una
firma COMPLETA y la cascada la aplica en `replace`, asi que aplastaba la
modulacion por intent que la propia entrada existe para proteger — un `fulfill`
perdia su +300 Hz / ascending / +0.05, y el fallback sintetico sonaba ciego al
intent tambien. Su cabecera afirmaba literalmente lo contrario de lo que hacia.
Ahora compone tunings con `{ op: 'add' }`: el intent conserva sus primitivos y
la regla solo aporta caracter. Un producto que quiera el ping lo registra desde
la cascada de app (capa 5b), donde un sample SI es recurso legitimo.
3) D.8 REESCRITA Y FIRMADA
La entrada decia «los packs DEBEN respetar el activeChannels del family … anadir
`sound` a `handle` tambien [es incoherente]», y el framework hace justo eso,
prescrito por sema.md §componentes continuos. La ley queda:
- `activeChannels` es el DEFAULT perceptual de la familia, no una prohibicion.
- `channels` es la palanca por evento/regla y ajusta en las DOS direcciones.
Restringir: dialog `close-after-fail`, transporte del player, VirtualList.
Ampliar: el pack del slider sobre `handle`.
- Ampliar exige justificacion perceptual escrita. La del slider es canonica: el
sonido del arrastre no es firma fija sino payload por emision — por eso
`handle` no declara `base.sound`, y por eso sema conserva TRES resolvers de
gesto cuyo unico proposito es ese sonido.
- PROHIBIDO: declarar una firma de canal que la activacion no incluye. Deja
reglas INERTES. Es comprobable por guard. Infractoras: 2 del dialog + 3 mas.
Y Announce: la propia D.8 dejo la puerta abierta («si en el futuro necesita ser
pluggable … entonces vale convertirlo en canal formal. Hoy no»). Ese futuro
llego el 2026-07-04. No fue deriva; fue no volver a escribirlo aqui.
VERIFICADO: sema+morfo 337/337 · docs:check 0/616 · check 76 = base 75 + 1 del
fichero huerfano de la auditoria · `morfo:vocabulary` limpio · prettier: el
unico aviso mio formateado, los demas ya sucios en HEAD.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
**`activeChannels` es el DEFAULT perceptual de la familia, no una prohibición**
(ley reescrita y FIRMADA el 2026-08-06; la redacción anterior decía «los packs
DEBEN respetar el `activeChannels` del family … añadir `sound` a `handle`
también [es incoherente]», y el framework hacía justo eso, prescrito):
- **`channels` es la palanca declarativa por evento o por regla, y ajusta en las
DOS direcciones.** Restringir: el morfo del dialog usa `channels: ['haptic']`
en `close-after-fail` para no competir con la live region; el transporte del
player hace lo mismo (D-AP2.7 v2); `VirtualList` usa `channels: []` . Ampliar:
[`sema.md` §componentes continuos ](../architecture/sema.md ) MANDA que el pack
del slider ponga `channels: ['sound', 'haptic']` sobre la familia `handle` .
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
- **Ampliar exige justificación perceptual escrita en el sitio.** El ejemplo
canónico era el slider, cuyo arrastre se resolvía con un payload CALCULADO por
emisión (pitch/gain/contour desde posición y velocidad), sostenido por tres
resolvers dedicados. **Eso murió el 2026-08-06** : un gesto continuo suena por
REPETICIÓN — `step` (18 ms) por emisión, a la cadencia del propio gesto, como
una rueda dentada — y los tres resolvers se borraron con él. `handle` declara
hoy `sounds: { default: 'step' }` y activa los dos canales, y queda EXENTA de
la memoria de frecuencia, que si no estrangularía el trinquete al primer
arrastre. Contrapartida firmada: el ritmo lleva la velocidad, pero la posición
ya no mapea a altura.
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
(Nota 2026-08-12: «los tres resolvers se borraron con él» se adelantó a los
hechos — `git log -S` demostró que el borrado nunca se ejecutó; una retirada
intermedia del mismo 2026-08-12 se revirtió por proceso, y la definitiva la
hizo la sesión del eje ese día, firmada. Ledger
[`AUDIT-docs-code-ledger.md` §D10 ](../process/AUDIT-docs-code-ledger.md ).
Hoy la frase es verdad.)
feat(sema): los toggles recuperan su CONTACTO — la voz vuelve al momento que el libro le da
Tras leer el corpus entero de sema y del motor de sonido (los tres planes, el
handoff vivo, sema.md, CANON, channels, el README del art y D.7/D.8 literales),
que es la precondicion que me estaba saltando.
1) EL CONTACTO EXISTE (directiva del autor: «1 su contact-press»)
El libro le da a un Toggle DOS momentos, y el codigo solo tenia uno:
- cap. 23 §9 empareja el Toggle con `contact.press` Y `commit.toggle`;
- cap. 22 nombra «un switch que muestra estado pressed» como contact;
- CANON §8 regla 1: «contact precede al resultado cuando hay accion directa».
switch, toggle y toggle-group declaran ahora `contact-press` (family contact,
verbo press, sequence 'pre', SIN intent por cap. 22 §11) ademas de su
`commit-toggle`. Los providers los disparan en ese orden. Solo 4 de 91 morfos
con eventos expresaban `contact`; ahora 7.
Y el reparto de la voz cambia de sitio, que es el fondo del asunto:
- el CONTACTO habla — `contact.soft` (gain 0.08, clave nueva): el «click breve
opcional» de la tabla de canales del cap. 22, un tercio de una pulsacion de
boton para que un flip nunca pese mas que una activacion;
- el COMMIT calla — `SILENT`. Es lo que pide la tabla de canales del cap. 23
(«sonido: cierre opcional»), lo que exige el Criterio 12 (ch. 7 §13) de un
control que se pulsa docenas de veces por sesion, y lo que D.5 decidio en
mayo. La consecuencia la lleva `data-state` + color, la huella de ch. 23 §3.3.
`commit.medium` —la clave que invente ayer para que sonaran— queda RETIRADA:
huerfana en cuanto la voz se mudo al contacto.
MEDIDO en navegador: un clic emite `contact-press` -> `commit-toggle`, el estado
pasa a checked, y se levantan 2 osciladores con pico 0.08. UNA sola voz, la del
contacto; el commit no sintetiza nada.
⚠️ REVERSION DOCTRINAL DECLARADA: `compile.test.ts` afirmaba, citando el ANEXO
Tabla 1, que «Toggle/Switch declara un UNICO evento; el contacto es IMPLICITO en
el gesto». El cuerpo del libro dice lo contrario donde trata el caso. El test se
actualiza dejando escrita la reversion y su procedencia, para que quien lea el
anexo sepa por que el codigo diverge.
2) D.7 VUELVE A SER CANON SIN VERSOS SUELTOS (directiva del autor)
`proof-of-human` canonizaba samples en familia `commit`: `sound()` devuelve una
firma COMPLETA y la cascada la aplica en `replace`, asi que aplastaba la
modulacion por intent que la propia entrada existe para proteger — un `fulfill`
perdia su +300 Hz / ascending / +0.05, y el fallback sintetico sonaba ciego al
intent tambien. Su cabecera afirmaba literalmente lo contrario de lo que hacia.
Ahora compone tunings con `{ op: 'add' }`: el intent conserva sus primitivos y
la regla solo aporta caracter. Un producto que quiera el ping lo registra desde
la cascada de app (capa 5b), donde un sample SI es recurso legitimo.
3) D.8 REESCRITA Y FIRMADA
La entrada decia «los packs DEBEN respetar el activeChannels del family … anadir
`sound` a `handle` tambien [es incoherente]», y el framework hace justo eso,
prescrito por sema.md §componentes continuos. La ley queda:
- `activeChannels` es el DEFAULT perceptual de la familia, no una prohibicion.
- `channels` es la palanca por evento/regla y ajusta en las DOS direcciones.
Restringir: dialog `close-after-fail`, transporte del player, VirtualList.
Ampliar: el pack del slider sobre `handle`.
- Ampliar exige justificacion perceptual escrita. La del slider es canonica: el
sonido del arrastre no es firma fija sino payload por emision — por eso
`handle` no declara `base.sound`, y por eso sema conserva TRES resolvers de
gesto cuyo unico proposito es ese sonido.
- PROHIBIDO: declarar una firma de canal que la activacion no incluye. Deja
reglas INERTES. Es comprobable por guard. Infractoras: 2 del dialog + 3 mas.
Y Announce: la propia D.8 dejo la puerta abierta («si en el futuro necesita ser
pluggable … entonces vale convertirlo en canal formal. Hoy no»). Ese futuro
llego el 2026-07-04. No fue deriva; fue no volver a escribirlo aqui.
VERIFICADO: sema+morfo 337/337 · docs:check 0/616 · check 76 = base 75 + 1 del
fichero huerfano de la auditoria · `morfo:vocabulary` limpio · prettier: el
unico aviso mio formateado, los demas ya sucios en HEAD.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2 months ago
- **LO PROHIBIDO — y es lo que produce el defecto real: declarar una firma de
canal que la activación resultante no incluye.** Eso deja reglas INERTES,
mudas y muertas, que se leen como si hicieran algo. Es mecánicamente
comprobable y merece guard. Infractoras detectadas por la auditoría
2026-08-05: el pack de `dialog` declara háptico sobre eventos de familia
`emerge` (dos reglas), más otras tres del mismo tipo en el catálogo. Cada una
o justifica su ampliación con `channels` , o se borra.
El espíritu de la redacción vieja se conserva —no pongas háptico donde no hay
tacto— pero era una prohibición sobre el mecanismo equivocado: prohibía ajustar
en vez de prohibir la incoherencia.
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
**Regla operativa**: algo es canal sólo si cumple las tres:
```
(a) recibe SemanticSignal y emite output perceptual,
(b) acepta modulación por intent.deltas (perceptual loading),
(c) tiene signature paramétrica análoga a SoundSignature / HapticSignature.
Si falla (b), no es canal — es declarativo o ad-hoc.
```
ARIA dinámico falla (b): `signal-announce + threat` produce el MISMO texto + el MISMO ARIA. La carga evaluativa del intent vive en sound + visual, no en el texto del anuncio. Por eso no es canal.
**Channels extensibles (no built-in, opt-in por la app):**
El registry `SemaChannelSignatures` es OPEN vía declaration merging. Una app puede:
```ts
declare module '$uix/sema' {
interface SemaChannelSignatures {
voice: { phrase: string; rate?: number; ... }; // TTS
a11y: { ariaPayload: string; politeness: 'polite' | 'assertive' }; // si la app lo quiere formal
}
}
```
E implementar un `Channel` con `prepare(signal, target)` + `play(effective)` . El framework no envía ninguno de éstos — son extensión de producto.
**Pendiente sin urgencia**: si en el futuro `Announce` necesita ser pluggable (apps que quieran enviar a logger, telemetría, voice UI), entonces vale convertirlo en canal formal. Hoy no.
---
### D.9 Persistence: separar hold expresivo de lifecycle de la señal
- **Status**: **PROJECT_CANON** (codifica libro Cap 24 §6.1 — primera implementación operativa)
- **Origen**: libro Cap 24 §6.1 distingue `hold` (duración mínima perceptible) de `persistence` (cuánto tiempo dura realmente la señal). La implementación trataba todo como transient con un hold numérico — regresión: un `signal.warn + risk` de validación desaparecía a los 240 ms aunque el formulario siguiera inválido.
**Tipos** (`src/uix/sema/types.ts`):
```ts
export type SignalPersistence = 'transient' | 'untilAction' | 'untilFix' | 'stateBound';
```
| Valor | Lifecycle | Caso típico |
|---|---|---|
| `transient` | Engine auto-limpia tras `hold` . Default. | contact.press, commit.save, emerge.open |
| `untilAction` | Persiste hasta acción del usuario. | signal.alert + threat (banner crítico) |
| `untilFix` | Persiste hasta corrección. | signal.warn + risk (validación de campo) |
| `stateBound` | Lifecycle = duración del estado. | sustain.progress, caps-lock indicator |
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
**Tabla canónica `SEMA_HOLDS_BY_INTENT` ** — vive en
[`src/uix/sema/holds.ts` ](../../src/uix/sema/holds.ts ) y se enumera generada en
[`docs/canon/vocabularies.md` ](../canon/vocabularies.md ). Codifica el libro §6.2
separando los dos ejes (hold expresivo · persistencia de la señal).
> **Aquí había una transcripción literal de esa tabla, y se pudrió.** D.12
> corrigió dos valores el 2026-07-06 —`commit.fulfill` de `noticed` a `settled`
> y `signal.loss` de `noticed` a `brief`, ambos contra el texto del libro— y la
> copia de esta entrada siguió afirmando los viejos durante un mes. La ley del
> corpus es enlazar, no copiar (`docs/authoring.md` §1); esta entrada la
> incumplía. Retirada el 2026-08-06.
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
**Implementación**:
- `EngineSemantic.emit()` ahora devuelve el `id` del signal. Para `persistence !== 'transient'` mantiene la proyección viva pasado el hold; el caller posee el cleanup vía `engine.clear(id)` o `engine.clearTarget(target)` .
- `SomaRuntime.trigger()` devuelve `TriggerResult { id?, persistence? }` . Expone `runtime.clearSignal(id)` y `runtime.clearTarget(target)` para que providers cierren el ciclo.
- Default conservador: cuando un morfo NO declara `persistence` , el runtime asume `'transient'` . La tabla canónica es REFERENCIA — los autores la declaran explícitamente en cada morfo. No se aplica de oficio para no introducir regresiones silenciosas.
**Morfos actualizados** (consumidores reales):
| Morfo / evento | persistence | Por qué |
|---|---|---|
| `announce.signal-alert` | `untilAction` | El banner crítico debe esperar gesto del usuario |
| `dialog.close-after-fail` | `transient` (explícito) | El dialog se desmonta; la persistencia del fallo vive en Toast/Announce externo |
| `drawer.close-after-fail` | `transient` (explícito) | Misma razón |
| `file-upload.signal-warn-reject` | `untilFix` | El archivo rechazado sigue presente hasta que el usuario lo quita |
| `form.signal-warn-invalid` | `untilFix` | El warning persiste hasta que la validación pase |
| `password-field.signal-notify-caps-state` | `stateBound` | El indicator vive mientras caps lock esté on |
**Providers cabledados** (form / file-upload / password-field): cada uno llama `runtime.clearTarget(provider)` antes de re-emitir, o sobre la transición a estado "fix aplicado". Ver providers de los tres componentes.
**Texto doctrinal para el libro**:
> Cada señal perceptiva tiene dos duraciones independientes: un `hold` que es la duración mínima necesaria para que el usuario la registre como evento, y una `persistence` que dice cuánto tiempo permanece visible una vez registrada. Para la mayoría de eventos coinciden: la señal aparece, dura `hold` ms, y desaparece. Pero para `signal.warn + risk` y `signal.alert + threat`, la duración real depende del estado del sistema o de la acción del usuario, no de un cronómetro: una advertencia de validación debe seguir visible mientras el problema exista, y una alerta crítica debe seguir visible hasta que el usuario reconozca la situación.
---
### D.10 Accesibilidad semántica por evento (`a11ySemantic`)
- **Status**: **PROJECT_CANON** (codifica libro Cap 24 §9 — primera implementación operativa)
- **Origen**: el libro §9 define un contrato a11y por evento (live region, focus move, persistent trace, reduced-motion fallback). La implementación lo respetaba ad-hoc en cada provider. Ahora se declara en el morfo y el runtime lo honra centralizadamente.
**Tipo** (`src/uix/morfo/types.ts`):
```ts
export interface MorfoA11ySemantic {
requiresPersistentTrace?: boolean; // app debe mostrar trace externo
requiresLiveRegion?: boolean; // runtime pushes message a aria-live
requiresFocusMove?: boolean; // runtime mueve foco al target
keyboardEquivalent?: boolean; // contrato — handle.* drag etc.
reducedMotionFallback?: 'state' | 'text' | 'focus' | 'none';
}
```
Y en `MorfoEvent` :
```ts
{ name: 'signal-warn-invalid', semantic: {...}, a11ySemantic: { requiresPersistentTrace: true, requiresFocusMove: true, reducedMotionFallback: 'text' } }
```
**Infraestructura nueva**:
- `ActiveDom.prefersReducedMotion` : tracker reactivo del media query, vive en `src/arts/adom/reduced-motion.svelte.ts` . SSR-safe (devuelve `false` cuando no hay `matchMedia` ).
- `ActiveUix.announce(message, priority?, timeout?)` : live region compartida lazy-creada en document body. NO depende de soma — usa `dom.writeNode` directo. Lower-level que `<Announce>` soma (que ofrece snippet props y A/B alternation para repetidos).
- `SomaRuntime.trigger` honra `a11ySemantic` después del emit:
- `requiresLiveRegion` ∧ `opts.message` ∧ `sources.announce` → llama `announce(message, priority)` donde la prioridad se deriva de family/intent (`signal + threat/loss → assertive`, resto polite).
- `requiresFocusMove` ∧ target → `dom.focus(target)` .
- `reducedMotionFallback === 'state'` ∧ user prefers reduced → fuerza `channels: []` (silencia toda la señal perceptiva; sólo state attrs).
- `reducedMotionFallback === 'text'` ∧ user prefers reduced → llama announce aunque `requiresLiveRegion` no esté seteado.
- `reducedMotionFallback === 'focus'` ∧ user prefers reduced → focusea target aunque `requiresFocusMove` no esté seteado.
- `reducedMotionFallback === 'none'` → no hace nada (el motion era incidental).
**Morfos anotados** (mismos 6 consumidores que persistence):
| Morfo / evento | `a11ySemantic` |
|---|---|
| `announce.signal-alert` | `{ requiresPersistentTrace, requiresLiveRegion }` |
| `dialog.close-after-fail` | `{ requiresPersistentTrace, requiresLiveRegion, reducedMotionFallback: 'text' }` |
| `drawer.close-after-fail` | idem dialog |
| `form.signal-warn-invalid` | `{ requiresPersistentTrace, requiresFocusMove, reducedMotionFallback: 'text' }` |
| `file-upload.signal-warn-reject` | `{ requiresPersistentTrace, reducedMotionFallback: 'text' }` |
| `password-field.signal-notify-caps-state` | `{ requiresLiveRegion, reducedMotionFallback: 'text' }` |
**Mensaje del live region**: el caller pasa `opts.message` en `runtime.trigger` . El runtime NO infiere texto del nombre del evento — los nombres son técnicos (`signal-warn-invalid`), no user-facing. Esto deja el control de fraseo en el provider (que sabe en qué idioma y con qué contexto).
**`requiresPersistentTrace` no es ejecutable por el runtime**: declara un contrato que el provider/app debe cumplir mostrando un afford persistente (banner, inline error, undo toast). Es una nota declarativa que lint/docs/audit pueden chequear, pero no algo que el runtime pueda forzar — el "trace" vive en código de aplicación.
---
### D.11 Eventos polimórficos (`allowedFamilies`)
- **Status**: **PROJECT_CANON** (codifica libro Cap 5 §3 — implementación operativa diferida)
- **Origen**: libro §5.3 documenta que un morfo puede declarar CAPACIDAD para varios shapes semánticos en lugar de comprometerse a uno. Hasta ahora la implementación sólo soportaba shape fijo. No había consumidor concreto, pero el tipo + runtime quedan disponibles para futuras decisiones (Dialog `close` con/sin cambios sin guardar, etc.).
**Shape**: ADITIVO sobre el shape concreto, no variante separada. El morfo declara su `family` + `intent` + `verb` como default; añade `allowedFamilies` para autorizar overrides:
```ts
{
name: 'close',
semantic: {
family: 'shift', // default
verb: 'exit-mode',
target: v.partRef('content'),
allowedFamilies: ['shift', 'commit', 'emerge'] // polymorphic capacity
}
}
```
Trigger:
```ts
runtime.trigger('close'); // emite { family: 'shift', verb: 'exit-mode' }
runtime.trigger('close', { semantic: { family: 'commit', verb: 'discard', intent: 'loss' } });
runtime.trigger('close', { semantic: { family: 'signal', verb: 'alert' } }); // → throws (signal no en allowedFamilies)
```
**Reglas**:
- El `family` declarado en el morfo es IMPLÍCITAMENTE allowed; no hace falta repetirlo en `allowedFamilies` (que enumera SOLO las alternativas).
- El override falla con `SomaRuntimePolymorphicError` si la family no está en allowedFamilies y no es el default.
- `TriggerOptions.semantic` opcional. Sin él, la trigger usa el shape canónico del morfo (comportamiento original).
**Por qué no la forma del libro literal** (`{ allowedFamilies, defaultSemantic: { family, verb, intent } }`):
- Backwards-compat: los morfos existentes —29 en aquel momento— acceden a `event.semantic.family` /`intent`/`verb`/`sequence`. Una variante separada `{ defaultSemantic: { family: ... } }` rompía cientos de demos que hacen visualizaciones de la morfo en tablas.
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
- Equivalencia funcional: declarar `family: 'shift', verb: 'exit-mode'` Y `allowedFamilies: ['shift', 'commit', 'emerge']` cumple la misma intención que el shape del libro con menos anidamiento.
- Cero overhead para no-polymorphic: morfos sin `allowedFamilies` no pagan ningún coste de tipos ni runtime.
**Texto doctrinal para el libro** (si se canoniza):
> Un evento puede declarar no sólo qué es, sino qué podría ser. La forma canónica (`family`, `verb`, `intent`) describe el caso por defecto, pero un campo opcional `allowedFamilies` puede enumerar las alternativas que el provider está autorizado a emitir según contexto. Por ejemplo, el `close` de un diálogo es típicamente `shift.exit-mode`, pero si hay cambios sin guardar puede convertirse en `commit.discard + loss`, o si simplemente se descarta sin acción, en `emerge.close`. El provider decide la family concreta en tiempo de ejecución; el morfo establece el catálogo de las shapes válidas.
**Aplicación real — Dialog (sprint 2026-05-27 / segunda mitad)**:
Dialog cabledaba 5 eventos `close-*` distintos (close-save / close-cancel / close-dismiss / close-dismiss-outside / close-after-fail), cada uno con su propio prewrite de `data-last-action` y su semantic concreta. La refactorización los colapsó en UN evento polymorphic `close` :
```ts
{
name: 'close',
semantic: {
family: 'emerge', // default
verb: 'close',
target: v.partRef('content'),
sequence: 'pre',
persistence: 'transient',
allowedFamilies: ['emerge', 'commit', 'signal']
},
regime: 'lock',
commits: { part: v.partRef('content'), attr: 'data-state', value: 'closed' }
// NO prewrite — el provider escribe data-last-action imperativamente
}
```
El `DialogProvider.dismissWith(action, opts?)` traduce la acción al shape correcto:
```ts
const DISMISS_CAUSES = {
save: { lastAction: 'saved', semantic: { family: 'commit', verb: 'save', intent: 'fulfill' } },
cancel: { lastAction: 'cancelled', semantic: { family: 'emerge', verb: 'close' } },
dismiss: { lastAction: 'dismissed', semantic: { family: 'emerge', verb: 'dismiss' } },
'dismiss-outside': { lastAction: 'dismissed-outside', semantic: { family: 'emerge', verb: 'dismiss' } },
fail: { lastAction: 'failed', semantic: { family: 'signal', verb: 'alert', intent: 'threat' } }
};
```
El provider hace `dom.apply({ target, attrs: { 'data-last-action': cause.lastAction } })` antes de `runtime.trigger('close', { semantic: cause.semantic, ... })` .
**Cambios colaterales necesarios**:
- **Validador del morfo** (`src/uix/morfo/schema.ts`): se relajó el invariante "cada `data-last-action.values[]` debe ser prewritten por algún event". El otro sentido sigue estricto (un prewrite con valor fuera de `values[]` falla). Razón: con polymorphism, el provider escribe imperativamente — la sincronía bidireccional dejaba de tener sentido.
- **Cascade sema de Dialog** (`src/uix/sema/components/dialog.ts`): los selectores que matcheaban `eventName: 'close-dismiss-outside'` o `eventNamePrefix: 'close-'` se reescribieron para usar `eventName: 'close'` + matchers adicionales (`state: { attr: 'data-last-action', value: 'dismissed-outside' }` y `eventFamily: 'emerge'` ). El helper `semaSelector` soporta el matcher `state` nativamente.
- **Eidos CSS** (`dialog.css`): NO requirió cambios — los selectores ya leen `data-last-action` para tintar la animación de salida, no los nombres de evento.
- **Tests del morfo/runtime**: actualizados para esperar `close` en lugar de `close-cancel` /etc. El test de prewrite del compiler se movió a `drawerMorfo` (que mantiene su shape per-event).
**Drawer y Popover**: refactorizados con el mismo patrón en sprint 2026-05-27 #3 . Cada uno:
- 5 close-* events → 1 polymorphic `close` event en su morfo
- DISMISS_CAUSES + dismissWith adaptado en su provider
- Cascade sema reescrito (`eventName: 'close'` + `state` matchers en `data-last-action` )
- Internal callsites (escape, outside-click, close button) migrados a `dismissWith`
- Tests actualizados
- Eidos CSS sin tocar (ya leía `data-last-action` )
**Picker family** (color-picker, date-picker, date-range-picker, time-picker, time-range-picker): refactorizados al patrón polymorphic close en sprint 2026-05-27 #4 .
Detalle del refactor:
- Cada picker tenía 4– 5 eventos `close-*` (close-commit / close-cancel / close-dismiss / close-dismiss-outside, + variantes como `close-range-commit` en date-range-picker), todos con prewrite individual de `data-last-action` .
- Colapsados a 1 evento `close` polymorphic con `family: 'emerge', allowedFamilies: ['emerge', 'commit', 'signal']` , sin prewrite.
- **Hallazgo**: los providers de los pickers NO disparan los close events vía `runtime.trigger` . Sólo togglean `opts.open = false` . Los eventos estaban declarados pero **inertes** — su único consumidor era el schema validator y el compiler tests. El refactor es alineación doctrinal, no de comportamiento.
- Sema cascade: solo `color-picker` tiene un sema pack y NO referenciaba close-* (sólo handle-*). Nada que actualizar.
**Test fixtures decoupling**: antes de tocar los pickers, los tests `compile.test.ts` + `runtime.svelte.test.ts` se migraron a un fixture sintético `prewriteFixtureMorfo` (en `src/uix/morfo/test-fixtures.ts` ). Esto desacopla los tests de las decisiones del catálogo de componentes — los tests validan el contrato del compiler / runtime, no qué morfos lo usan.
**Resultado del rollout polymorphic completo**:
- **3 overlays** (Dialog / Drawer / Popover): polymorphic close cabledado al runtime (providers disparan vía `dismissWith` ).
- **5 pickers** (color / date / date-range / time / time-range) — **CERRADO 2026-07-12
(SEM-4, `b55ca6ee` )**: tras la reconciliación de-dialoged (2026-06-27) sus morfos ya no
declaran `close` propio (`expression: 'delegated'` — la firma pertenece al Popover
compuesto); el cierre programático (commit/cancel/select-close) ahora enruta por causa
vía `PickerShellHandle.setPopoverDismiss` → `popover.dismissWith('save'|'cancel')`
(delegado inyectado por el eidos PickerShell root; fallback raw para composiciones
headless). Verificado en vivo: Done → `close · commit · fulfill` · Cancel →
`close · emerge` .
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
- Único morfo con shape pre-polymorphic restante: el fixture sintético `prewriteFixtureMorfo` — vivo sólo para tests.
**API pública preservada** en todos: ningún cambio observable para el consumidor de los componentes.
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
### D.12 Holds/duraciones: materialización numérica de las regiones cualitativas del libro (+ "el hold es suelo, no tijera")
- **Status**: **PROJECT_CANON** (materialización propia; el libro rehúsa dar números a propósito)
- **Origen**: auditoría clean-room 2026-07-06. La cabecera de `holds.ts` citaba un
"cap. 24 §6.2 (Holds por familia e intent)" **que no existe** (el cap. 24 §6 real
es "Canales, texto e intent") y reclamaba tablas "verbatim" con números
("commit.fulfill: 280") **que el libro jamás da** . La doctrina temporal real del
libro es CUALITATIVA: cap. 4 §13 (duración expresiva · estado · resultado ·
huella — "un evento no termina siempre cuando acaba su animación") · cap. 12 §4-§9
(duración/persistencia/huella/caducidad; "si un evento importante solo existe
durante un instante, muchos usuarios no lo recibirán") · cap. 32 TABLAS 32.1/32.2
("regiones de diseño, no números sagrados": affirm "breve" · fulfill "breve-media,
más resolutivo" · risk "hasta corrección" · threat "entrada rápida + persistencia
hasta acción" · loss "breve + huella").
**Decisiones (usuario, 2026-07-06):**
1. **Los ms son autoría del framework** (materialización de las regiones sobre
`SEMA_DURATIONS` ), nunca "transcripción del libro". Procedencia corregida en
`holds.ts` /`durations.ts`.
2. **Peldaño nuevo `settled` (400 ms)** — la escala no tenía paso entre `brief`
(240) y `noticed` (600) y la región "breve-media" lo exigía. `commit.fulfill`
600→400 (`settled`); `signal.loss` 600→240 (`brief` — la huella es del caller:
undo/estado, no señal más larga).
3. **Tabla única** : `SEMA_HOLDS_BY_INTENT` (familia+intent) es LA fuente de holds;
el `hold` por-familia duplicado de `SEMA_MAP` se eliminó (había derivado:
signal 600 contra la región "breve o contextual" → vuelve a 240). El resolver
compone `signal.hold ?? resolveHoldsByIntent(family, intent)` .
4. ** "El hold es suelo, no tijera"** — el des-estampado ya no amputa la expresión:
tras el hold (mínimo de registro), el canal visual espera el `finished` de las
animaciones activas del target (`VisualChannel.awaitExpression`), con tope
ABSOLUTO `MAX_EXPRESSION_WAIT_MS = 1500` (constante de ingeniería — derivarlo
del hold re-acoplaría los presupuestos que el cap. 4 §13 separa; el corte era
el antipatrón del cap. 32 §1: "una señal necesaria, por desaparecer demasiado
pronto"). La persistencia sigue siendo declaración del morfo (la huella SE
DECLARA), nunca default del runtime.
5. **Firmas re-materializadas a las regiones** : announce neutral/affirm
`deliberate(600)` →`moderate(240)` ("breve"); fulfill →`slower(400)`
("breve-media"); risk `emphatic(800)` / threat `sustained(1000)` conservan la
escalación que el libro sí quiere saliente/persistente.
6. **Triple guarda** : suelo (attrs viven ≥ hold), espera de expresión (test del
canal), y lint de diseño (ninguna firma transitoria > tope; subirla exige subir
la constante conscientemente). `vocabularies.md` (generado de `holds.ts` ) queda
veraz sin tocarlo.
**Candidato editorial** (si el autor lo quiere para el ApD, "Lo que la práctica
corrigió"): esta es la historia inversa a las demás — aquí **el libro corrigió a la
práctica**: el runtime había convertido el suelo en tijera y la tabla derivada en
canon; releer la fuente restauró ambos.
---
### D.13 El diálogo declara `emerge.open`, no `shift.enter-mode` (la desviación emerge/shift del diálogo)
- **Status**: **DESVIACIÓN REGISTRADA Y BENDECIDA POR EL LIBRO** (edición FINAL,
Apéndice D, ancla **BK-D11** ; pass de verbos C2, checkpoint 2026-07-07)
- **Origen**: el libro doctrina el modal bloqueante como `shift.enter-mode`
(cap. 8 §5 lo usa así; cap. 26 §8: "el dropdown es emerge.open y el modal es
shift.enter-mode"; cap. 27 §1: "abrir un modal… todo eso es shift"). El
contrato real de `dialog` declara `emerge-open` /`emerge-close`, y su cierre
polimórfico admite emerge/commit/signal — shift no está en la lista. Esta
entrada es el registro que el propio Apéndice D exige ("registrada en el
cuaderno de desviaciones del proyecto, con su razón").
**La razón (del propio Apéndice D del libro):**
> "En el componente genérico pesó más la aparición que el cruce de marco. Y el
> cruce quedó reservado a los usos que de verdad bloquean el fondo y capturan
> el foco — el mismo componente puede ser una cosa u otra según cómo se use.
> La doctrina del libro no cambia: el modal pesado sigue siendo shift. Lo que
> la práctica enseñó es que **la frontera emerge/shift no pasa entre
> componentes, sino por dentro de ellos**."
Y la regla de convivencia (pág. 411): *"Ambas lecturas son defendibles… La
gramática no exige que todas las implementaciones lean igual el caso frontera;
exige que cada una **elija, declare y sea consecuente** . El desacuerdo,
mientras esté declarado, es información."*
**Consecuencias operativas:**
1. `dialog` (y `alert-dialog` , que delega en sus eventos) CONSERVA
`emerge-open` /`emerge-close`. No hay migración a shift.
2. Un uso que de verdad cambie el régimen (bloquea el fondo, captura el foco,
exige reorientación como MODO) puede componer `shift.enter-mode` a nivel de
aplicación — la frontera se decide POR USO, no por componente.
3. El caso queda como "lo que sigue abierto" nº1 del propio libro: señala dónde
la frontera emerge/shift necesita más trabajo teórico. Si el libro la
redefine en una edición futura, esta entrada se revisa.
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
---
## E. Resumen ejecutivo
**Familias** (libro Cap 8): 8 — sin cambios. (`contact, commit, signal, handle, emerge, shift, sustain, delegate`)
**Intents** (libro Cap 10): 6 — sin cambios. (`neutral, affirm, fulfill, risk, threat, loss`)
### Verbos / casos que pasan al libro (BOOK_CANON)
- `handle.scroll` (A.1)
- `commit.remove` (A.3, con distinción remove/delete/unselect)
- `commit.set` (A.5)
- `commit.apply` (A.6)
- `commit.move` (A.7, distinto de reorder)
- `commit.unselect` (A.11)
- Cancelación de drag = `commit.cancel` (B.1)
- Scroll programático = `shift.navigate` (B.2)
- Sort = `commit.set` (B.4)
- Eventos no perceptibles no son eventos (B.5)
- Toggle con dos eventos direccionales (B.6, sin canonizar intents)
- Intent en contact visual-only (B.7)
- Cada actor declara sus eventos (D.1)
- Family policy `intentRequirement` + `intentGuidance` (D.3)
- `clear` = `commit.reset` (C.1)
### Pendientes — CANDIDATE (mantener en canon de implementación, NO al libro todavía)
- `commit.acknowledge` (A.2) — necesita casos fuertes
- `commit.confirm` (A.4) — solapa con submit/apply/acknowledge
- `commit.upload` (A.8) — probable redundancia con complete
- `commit.partial` (A.9) — probable estado, no verbo
- `commit.block` (A.10) — probable estado/señal, no commit
- Data-size auto-change (B.3) — caso por caso
### IMPLEMENTATION_CONTRACT (no doctrina)
- Eventos declarados pero no emitidos (D.2)
- Campo `expression` en el morfo (D.4)
- Packs sema soft-tuned para alta frecuencia (D.5, toggles)
- Packs sema para superficies de menú y árboles (D.6)
- Doctrina sonido canónico vs samples (D.7) + packs tooltip / collapsible
- Channel scope: qué es canal y qué no (D.8)
---
## F. Cómo proceder
Para cada entrada el autor decidió un status. La implementación:
1. **BOOK_CANON aceptados** : ya están en `SEMA_VERBS` del proyecto. La próxima edición del libro puede formalizarlos. Los textos doctrinales recomendados están en bloques citados arriba.
2. **CANDIDATE** : mantener en `SEMA_VERBS` pero no promover al libro hasta acumular casos.
3. **IMPLEMENTATION_CONTRACT** : requiere cambios en types (flag `emission` ) en una iteración futura.
4. **Cambio inmediato pendiente en proyecto** : split de `intentPolicy` en `intentRequirement` + `intentGuidance` (D.3) — commit separado.
Hasta que el libro se actualice, este documento es la fuente de verdad sobre dónde el proyecto se ha desviado del libro literal y con qué status.
---
## G. Anti-mezclas
Este documento mezclaría planos peligrosamente si no se mantiene la disciplina de:
- **No copiar el contenido de este documento al libro tal cual.** El libro necesita gramática estable; este documento es bitácora.
- **No promover automáticamente `PROJECT_CANON` a `BOOK_CANON` .** Solo entra al libro lo que mejora la teoría general.
- **No usar lenguaje interno del proyecto** ("Capa 2", "Cluster 6", "Plan B commit X") en texto editorial.
- **Versionar el documento** cuando cambie un veredicto del autor.
Las familias son el núcleo estable. Los verbos son extensibles bajo criterios. La implementación puede tener aliases y extensiones locales. Solo las extensiones que revelan una diferencia recurrente y general deben pasar al libro.
docs: la doctrina alcanza a los cambios de la jornada — cinco backlogs y una llave de mas
Auditoria de deriva doc<->codigo sobre los 33 commits del 2026-08-13/14: cinco
sitios seguian describiendo lo que el codigo dejo de hacer ayer. Se corrigen
COMO BITACORA, al final de cada fichero (el cuerpo es el acta de lo que se
firmo, no el estado del codigo; reescribirlo falsearia la firma). El formato
es el que ya existia en `arts/adom` y `soma/textarea`: `## Backlog`.
- `decisions/book-deviations.md` — dos entradas. D.7 nombraba
`IntentExpectedFamily`, tipo que M6 (13246a2c2) borro, y describia una
derivacion de DOS cubos que S-33 (1a174d5a6) hizo positiva y TRIPLE. Y el
caveat SEM-4 de tree-view/tree-grid nombraba `targetOverride` en presente:
b8aa333fd lo borro, hoy se ancla por identidad (`partInstance`).
- `theming/channels.md` — decia «built-in opt-in channel» de announce.
S-19(ii) (23b20fff5) lo encendio por defecto en las DOS raices; ese commit
actualizo `sema.md` y se dejo este atras.
- `architecture/morfo.md` — el §semaSelector no nombraba los dos matchers que
M5 (b53c93e42) anadio: `state` tipado contra `DataPairOf<M>` y el escape
`undeclaredState`, que LANZA si el attr resulta estar declarado — es lo que
mantiene obligatorio el tipado.
- READMEs de virtual-list / virtual-grid — su columna informal «Emitted? NO»
precede al campo del contrato. c73cae022 hizo que el morfo diga QUIEN
dispara: `emission: 'host'`. La conducta no cambia; cambia su estatus.
Ademas, `architecture/sema.md`: `{{ announce: false }}` -> `{ announce: false }`,
llave doblada que introduje ayer en 23b20fff5.
Verificado: docs-check 0/625 · prettier sin regresion (los 6 ficheros que
avisan ya avisaban en HEAD, medido con stash). Los ficheros de blocks
(`blocks.md`, `AUDIT-blocks-ledger.md`, `CONTINUE-blocks.md`, `PLAN-blocks.md`)
son de la otra sesion y quedan fuera.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
## Backlog · actualizaciones posteriores
Registro de lo que la implementación cambió DESPUÉS de firmar cada deviación.
El cuerpo de arriba se deja intacto a propósito: es el acta de lo que se firmó,
no el estado del código. Cada entrada nombra la sección que corrige.
### 2026-08-13 — D.7: el eje de intent implementa TRES cubos, y `IntentExpectedFamily` ya no existe
Corrige ** §D.7 · Implementación** («TypeScript deriva `IntentExpectedFamily`
desde `intentRequirement === 'required'` »).
- El alias `IntentExpectedFamily` se borró en `13246a2c2` (M6, «un nombre por
concepto»). El nombre vivo es ** `IntentRequiredFamily` **.
- La derivación ya no son dos cubos. `1a174d5a6` (S-33) la hizo **positiva y
triple** sobre `intentRequirement` : `IntentRequiredFamily` (`'required'`),
`IntentOptionalFamily` (`'optional'`) e `IntentForbiddenFamily`
(`'forbidden'`). Derivar el segundo cubo con `Exclude<…, Required>` era una
derivación de mundo abierto: cualquier familia nueva caía dentro por
omisión, sin que nadie hubiera decidido su política.
- `intentGuidance` sigue siendo campo doctrinal, tal como se firmó.
### 2026-08-13 — la emisión anclada ya no pasa por `targetOverride`
Corrige el **Caveat (`tree-view` / `tree-grid`) — RESUELTO (SEM-4)** , que
nombra `targetOverride` como el vehículo del anclaje.
La opción de elemento crudo `targetOverride` se **borró** en `b8aa333fd` , una
vez el censo F3 llegó a cero: el estado ilegal del eje quedó inexpresable. El
anclaje se hace hoy por identidad contra el registro —
`runtime.partInstance('branch'|'row', el).trigger` en esos dos providers—,
declarado en el morfo con `semantic.allowedTargets`
([`architecture/morfo.md`](../architecture/morfo.md)). Lo demás del caveat
sigue en pie: los packs construyen sus selectores con `onBranch` / `onRow` y
emisión y cascada casan de punta a punta.