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

385 lines
21 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# PLAN — El sonido se NOMBRA: un nombre y punto
> ⛔ **SUPERADO EL MISMO DÍA (2026-08-06). No ejecutar nada de aquí.**
>
> Este plan entregó un modelo en el que un NOMBRE modificaba la base de familia
> y el intent modulaba después. Se ejecutó entero… y al oírlo, el autor lo
> rechazó: los dieciséis nombres sonaban prácticamente igual, porque cinco eran
> la misma nota a cinco volúmenes y las variantes se separaban 20 Hz. La
> directiva que lo sustituye fue literal: _«evento.intent = sonido, y punto y
> nada de mierdas de que si el intent modifica nada»_.
>
> **El modelo vigente** —el intent SELECCIONA un sonido entero, dos búsquedas,
> nada modula nada— vive en [`architecture/sema.md`](../architecture/sema.md)
> §the sound pack y en las páginas `/uix/docs/sound`. Este documento se conserva
> como crónica de por qué NO se hizo así: la lección es que un sistema de
> modulación produce variantes que difieren sobre el papel y son idénticas al
> oído, y que sólo se detecta escuchando.
> **Tipo**: plan de diseño + ejecución por fases (process — efímero, NO fuente de verdad).
> **Fecha**: 2026-08-06 · **Estado**: **EJECUTADO — F1…F5 ENTREGADAS** el mismo
> día, por orden directa del autor («aplícalo»). Queda **F6**: la doctrina
> (D.7 / S-07 retiradas con su motivo, `sema.md` §tunings reescrito, el límite
> del WAV de §3.2 escrito). El vocabulario de §5 se aplicó con las colapsaciones
> anotadas en §5.1 — reversibles editando UN fichero.
> **Kickoff para sesión nueva**: _«Lee `docs/process/PLAN-sound-names.md` y cierra
> F6.»_
> **Antecedentes obligatorios**: [`AUDIT-sema-2026-08-05.md`](./AUDIT-sema-2026-08-05.md)
> (44 hallazgos) · [`CONTINUE-sema-audit.md`](./CONTINUE-sema-audit.md) (la cola) ·
> [`architecture/sema.md`](../architecture/sema.md) · [`CANON.md`](../CANON.md).
---
## 1. El mandato (2026-08-06, palabras del autor)
> «Yo sólo quiero en la semántica en sonido darle el nombre de un sonido y punto,
> y me da igual que sea generado o sea un wav. Todo lo demás es una puta mierda
> sobreingeniería para algo que es anecdótico y que convierte al sistema en
> supercomplejo.»
Y antes, sobre los literales:
> «Hace ya que se hizo que los sonidos tenían que estar canonizados y se hizo un
> repositorio con los sonidos, y ahora veo que se meten valores y mierdas a nivel
> de componente.»
El mandato **no es una simplificación de conveniencia**: restaura la ley que ya
estaba escrita en [`sema.md:390`](../architecture/sema.md) —_«components reference
names; URLs and parameters live in one place»_— y que nada vigilaba.
---
## 2. La medida — por qué el mandato es correcto
Censo en runtime sobre los 71 packs (2026-08-06, HEAD `2f63525da`):
**214 reglas de cascada. 33 firmas distintas. Las 8 primeras cubren el 76%.**
| firma autorada | reglas |
| ------------------------------------------------- | ------ |
| `{ gain: 0.05 }` | 35 |
| `{ gain: 0.03 }` | 35 |
| _(sin sonido — sólo háptico/channels)_ | 34 |
| `{ gain: 0.08 }` | 17 |
| `{ contour:'descending', gain:0.05, pitch:−120 }` | 13 |
| `{ contour:'descending', gain:0.03, pitch:−80 }` | 11 |
| `SILENT` | 10 |
| `{ contour:'ascending', gain:0.18, pitch:−90 }` | 7 |
| … 25 firmas más, casi todas ×1 | 42 |
Anatomía de lo que dicen esas reglas:
- **92 de 214 (43%) no dicen más que un volumen.** Su contenido íntegro es `gain`.
- **2 de 214** nombran un WAV. De los 5 `.wav` embarcados, **3 no los usa nadie**
(`whoosh`, `pop`, `ding` — S-26, verificado).
- Ejes tocados: `gain` 165 · **`contour` 69** · **`pitch` 67** · `centroid` 30 ·
`decay` 29 · **`roughness` 23** · `duration` 23 · `attack` 22.
`pitch`, `contour` y `roughness` **son ejes del intent**. `contour` es un enum:
no admite `{op:'add'}`, sólo reemplazo — así que **69 reglas borran el contorno
que el intent acababa de poner, y no pueden hacer otra cosa**. El guard nacido el
2026-08-06 para proteger el intent (`d7-intent-survives.test.ts`) comprueba
`pitch`, `gain` y `roughness`: **está ciego justo en el único eje incomponible**.
Y `centroid` (30 usos) **es un eje de la FAMILIA**, no del intent: los 6 intents
lo tocan **cero** veces; las familias lo fijan (contact 2000 · commit 1800 ·
signal 2400 · emerge 1500 · shift 1400 Hz). Es la huella tímbrica que distingue
una familia de otra — y 5 componentes le suman +2800 por copia-pega, dejando su
`commit` en 4600 Hz, casi el doble de brillante que la familia más brillante del
mapa.
**Conclusión medida**: la capa de packs autora 33 sonidos usando una superficie
de 8 ejes continuos, invade los ejes del intent 159 veces y dedica el 43% de sus
reglas a decir «más bajito». El coste de entrada para «meter un sonido» es
conocer 5 capas de cascada, `replace` vs `add`, D.7, D.8, S-07 y la ley de
nombrado. **La complejidad no está pagando nada.**
---
## 3. El diseño
```ts
// HOY — color-picker, commit-set
sound: {
gain: { op: 'add', value: -0.25 },
centroid: { op: 'add', value: 2800 },
decay: { op: 'add', value: 20 }
}
// OBJETIVO
sound: 'settle.bright'
```
Tres piezas, **ninguna nueva** — las dos primeras ya existen en el repo:
1. **UN catálogo de sonidos con nombre.** Se fusionan `SOUND_LIBRARY` (que ya
resuelve nombre → WAV con reserva sintética) y `SOUND_TUNINGS` (que ya es un
catálogo, sólo que de aritmética). Cada nombre es una definición completa:
receta sintética **o** sample con reserva. **Al consumidor le da igual cuál
sea** — que es literalmente el mandato. Los parámetros viven ahí y en ningún
otro sitio.
2. **El componente escribe un nombre, o `SILENT`.** El tipo de la regla pasa de
bolsa-de-8-ejes a `sound?: SoundName | typeof SILENT`. **La ley deja de ser
prosa: la impone el compilador.** Se acabaron `op:'add'`, el número desnudo y
el `centroid` copiado cinco veces.
> Precedente en el propio repo: el canal háptico YA funciona así.
> `haptic: { kind: 'tick' }` es un nombre categórico y el canal resuelve qué
> significa; nadie escribe milisegundos por componente.
3. **El nombre entra como BASE de la ocurrencia; el intent modula DESPUÉS**, en
el motor, invisible para el componente (§4, D-SN.1).
### 3.1 El reorden — la pieza que disuelve toda una clase de defectos
Orden **de hoy** (`resolver.ts:135-180`):
```
1 base de familia → 2 deltas de intent → 3 overrides de evento → 5a packs
```
El pack llega **el último** y se aplica en `replace`: por eso aplasta el intent.
D.7, S-07 y `d7-intent-survives.test.ts` existen los tres para vigilar esa
inversión.
Orden **propuesto**:
```
1 base = el NOMBRE que la cascada seleccione (o la base de familia si no hay)
2 deltas de intent
3 overrides de evento
5b cascada de app
```
La cascada sigue casando por selector igual que hoy (el `target` ya está en la
mano del resolver); lo único que cambia es **qué produce**: en vez de un delta
que pisa, **elige la base sobre la que el intent trabaja**.
Con el nombre DEBAJO, **D.7 y S-07 dejan de poder existir**. No se arreglan: se
disuelven. Un `commit-save` con `fulfill` sonará más brillante y más arriba que
con `neutral` **sin que ningún componente sepa que eso ocurre**.
### 3.2 El límite físico, ya medido
`playSample` ([`engine-sound.ts:694-698`](../../src/arts/sound/engine-sound.ts))
sólo lee **dos** campos: `sampleUrl` y `gain`. No hay `playbackRate` ni `detune`.
Luego **sobre un WAV el intent sólo puede mover el volumen**: medido, `risk` es
indistinguible de `neutral` (ambos gain 0.05; `risk` sólo aporta `roughness`, que
la ruta de sample ignora).
Consecuencia para el vocabulario: **un nombre-WAV que deba llevar carga
evaluativa necesita un fichero por intent** — que es exactamente lo que ya hace
la familia `signal` (`notification.ping` vs `alert.error`) y la razón de que D.7
la declare excepción. No es un defecto del plan: es física del audio, y hay que
escribirlo en la doctrina para que nadie lo redescubra.
---
## 4. Decisiones FIRMADAS (2026-08-06)
- **D-SN.1 — El intent SIGUE modulando encima, en el motor.** El nombre es la
base de la ocurrencia; la carga evaluativa se aplica después y es invisible al
componente. Es la tesis del libro con la complejidad en el piso que le toca:
**cero en el componente**. Sobre nombres-WAV, la modulación se reduce a volumen
(§3.2).
- **D-SN.2 — Plan firmado antes de ejecutar.** Este documento. Sin firma del
vocabulario (§5) no se toca código.
- **D-SN.3 — NO se congela el estado actual.** Es un framework en desarrollo: no
hay consumidor, no hay contrato de compatibilidad y la salida de hoy está
medida como defectuosa. No se hace A/B contra ella; la referencia es el
catálogo nuevo. Razonado en §7.1.
---
## 5. El vocabulario — PROPUESTA, PENDIENTE DE FIRMA
⚠️ **Esto es diseño del autor, no mío.** Lo que sigue es la colapsación mecánica
de las 33 firmas medidas; los NOMBRES son una propuesta a enmendar.
Las 33 firmas colapsan a ~12–15 nombres. Ejes reales que las separan: **nivel**
(3 escalones cubren 87 reglas), **dirección** (sube / baja / plana), y **carácter**
(un puñado de timbres con identidad propia).
| firma medida | reglas | nombre propuesto |
| --------------------------------- | ------ | -------------------- |
| `gain 0.03` | 35 | `subtle` |
| `gain 0.05` | 35 | `soft` |
| `gain 0.08` | 17 | `medium` |
| `gain 0.10 / 0.15` | 2 | `strong` |
| descending, −80, 0.03 | 11 | `subtle.fall` |
| descending, −120, 0.05 | 13 | `soft.fall` |
| descending, −150 | 4 | `deep.fall` |
| ascending, +60…+120 | 3 | `soft.rise` |
| pitch 1080 · centroid 5200 (aire) | 12 | `air` (3 niveles) |
| pitch 920 · centroid 4600 | 4 | `settle` |
| pitch 1040 · centroid 5400 · arc | 4 | `snap` |
| centroid +2800 (residuo de ayer) | 5 | → `settle` |
| centroid +3600 (residuo de ayer) | 2 | → `snap` |
| sample ping | 1 | `ping` |
| sample error | 1 | `error` |
| `SILENT` | 10 | `SILENT` (ya existe) |
### 5.1 Lo que se entregó, y las colapsaciones que lleva dentro
Catálogo final: **16 nombres** + `SILENT`, en `src/uix/sema/sound-names.ts`.
Niveles `subtle` · `soft` · `medium` · `strong` · `loud`; direcciones
`subtle.rise` · `soft.rise` · `subtle.fall` · `soft.fall` · `deep.fall`;
carácter `air` · `air.strong` · `settle` · `snap`; samples `ping` · `error`.
Los nombres NO llevan familia por delante (pregunta 1, resuelta por su motivo):
la ley `{family}.{tail}` existía porque un tuning era un delta SOBRE una familia.
Un nombre es una base, y el mismo `soft` sirve a un commit y a un emerge porque
la familia sigue poniendo su identidad debajo. Encabezarlos con familia sería
hoy la mentira, no la verdad.
Las 32 firmas medidas colapsan a esos 16 nombres. Estas son **todas** las
colapsaciones, con su consecuencia audible — cada una se revierte editando UNA
línea del catálogo:
| firma vieja | nombre | consecuencia |
| --------------------------------- | ------------- | -------------------------------------- |
| `gain 0.04` (tabs) | `subtle` | −0.01 |
| `gain 0.06` (popover dismiss) | `soft` | −0.01 |
| desc −100 / 0.03 (×3) | `subtle.fall` | pitch −80 en vez de −100 |
| desc −120 / 0.06 (×2) | `soft.fall` | −0.01 |
| desc sin pitch / 0.05 (×2) | `soft.fall` | gana la caída de −120 |
| asc +80 / 0.03 (editable) | `subtle.rise` | +60 en vez de +80 |
| asc +120 / 0.05 (stepper) | `soft.rise` | +80 en vez de +120 |
| `air` @ 0.10 (×3) | `air.strong` | +0.02 |
| delta `centroid +2800` (×5) | `settle` | ninguna — era esa firma, en aritmética |
| delta `centroid +3600` (×2) | `snap` | ninguna — ídem |
| proof-of-human confirm | `strong` | pierde su +600 de centroide |
| proof-of-human fail | `error` | pasa a ser el WAV de error |
| timeline reveal | `strong` | −0.02 |
| **calendar/chronos navegar (×7)** | `soft.rise` | **0.18 → 0.05** |
⚠️ La última es la única con consecuencia grande, y es deliberada: `gain 0.18`
era el valor más alto de todo el sistema —más que una alerta— para navegar un
calendario. Ninguna doctrina lo sostenía; era el residuo de
`soundTuning('commit.subtle', { gain: 0.18 })`, uno de los diez cabezas de
tuning que mentían (S-39). Si quieres que navegar suene fuerte, es una línea.
**Pregunta 3 (los 3 WAV muertos) — resuelta por omisión**: `whoosh`, `pop` y
`ding` NO entran al catálogo. Ningún pack los usaba y el catálogo es ahora el
conjunto cerrado de lo que un componente puede nombrar; meterlos sería
declararlos vivos sin que nadie los pida. Los ficheros siguen en
`static/sounds/` — retirarlos es decisión aparte.
**Las preguntas que quedaban, y cómo se cerraron:**
1. **¿Los nombres llevan familia por delante?** Hoy la ley de `SOUND_TUNINGS`
exige `{family}.{tail}` porque un tuning es un delta SOBRE una familia. Con
nombres que son BASES completas, esa razón desaparece: `soft` sirve a un
commit y a un emerge por igual. Mi lectura: **nombres sin familia** y la ley de
nombrado se retira con su motivo. Decide.
2. **¿`subtle`/`soft`/`medium`/`strong` es la escala, o prefieres otra?** Es la que
ya usa el catálogo de hoy.
3. **¿Los 3 WAV muertos (`whoosh`, `pop`, `ding`) entran al catálogo con nombre, o
se retiran?**
---
## 6. Qué muere y qué sobrevive
**Muere**
- `SOUND_TUNINGS`, `soundTuning()`, `op:'add'` y `{ gain: número }` en packs.
- Las 9 bolsas de literales inline de `4fccf1662` (color-picker, gradient-builder,
gradient-picker ×3, proof-of-human ×2, splitter) y las viejas de knob/timeline.
- **S-07 entero** (14 afinados en `replace`, ~150 usos) — disuelto por el reorden.
- **Q3 de la cola** (las 10 cabezas de tuning que mienten) — moot: serán nombres.
- La ley de nombrado `{family}.{tail}` y media `sounds-grammar.test.ts`.
- El invariante 3 de `pack-census.test.ts` → se reduce a «¿es un nombre vivo?».
**Sobrevive intacto**
- Morfo, soma, eidos, la proyección `data-event-*`, los holds, el háptico.
- El corazón semántico: **familia + intent deciden la percepción** — pero desde
el motor, no desde 71 ficheros.
- `SILENT` y su honra por el resolver.
- El censo de packs (invariantes 1, 2 y 4) y `d7-intent-survives.test.ts`, que
pasa de vigilar una inversión a **certificar que el reorden funciona**.
---
## 7. Fases — PENDIENTE DE FIRMA
| # | Fase | Verificación |
| ------ | ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
| **F1** | Catálogo unificado + `SoundName`. Sin tocar packs | `check` 75 · suites verdes |
| **F2** | **Instantánea del CATÁLOGO**: ~15 nombres × 6 intents, la firma resuelta de cada uno | La tabla existe; editar el catálogo la rompe |
| **F3** | Reorden del resolver (nombre = base, intent después) | La instantánea F2 certifica que el intent sobrevive a cada nombre |
| **F4** | Estrechar el tipo de regla a `SoundName \| SILENT` | Rojo en los 71 packs — **la enumeración es del compilador** |
| **F5** | Migración pack a pack, leyendo cada regla y su comentario | `check` a cero errores nuevos · censo verde |
| **F6** | Doctrina: D.7/S-07 retiradas con su motivo · `sema.md` §tunings reescrito · el límite del WAV (§3.2) escrito | `docs:check` 0 |
### 7.1 Por qué NO hay instantánea del estado actual (corregido 2026-08-06)
La primera redacción de este plan abría con una instantánea perceptual del
sistema de HOY, declarada innegociable, para poder hacer A/B durante la
migración. **Era un error, y el autor lo señaló**: un A/B necesita una
referencia que merezca conservarse, y la salida de hoy no lo es.
- 92 de 214 reglas son un recorte de volumen accidental; 69 aplastan el
`contour` del intent; 5 packs llevan un `centroid` copiado que deja su
`commit` en 4600 Hz. TextArea sonaba 6×/13× por encima de su firma escrita
hasta ayer, los toggles llevaban mudos desde mayo y todo lo que tiene
`roughness` se movió 1,6–2,7 dB anteayer. **Congelar eso es congelar el bug.**
- **La instantánea de §3.5 fue diseñada para un sistema que se quedaba como
estaba** («cualquier cambio en algo que el usuario percibe rompe el test»).
Esa premisa muere en cuanto lo que se sustituye es el modelo. Se importó la
conclusión sin volver a derivarla.
- **git YA es la instantánea.** Cada valor viejo es recuperable para siempre
(`git show 2f63525da`). Una tabla commiteada de números que estamos a punto de
borrar no añade nada.
- **El compilador es mejor guard que una instantánea.** F4 convierte cada regla
no conforme en error de tipos: enumeración del 100% por construcción. Una
instantánea sólo comprueba lo que alguien se acordó de meter en ella.
Comprobado además que no hay materia que preservar: de las **17 firmas que
aparecen ≤2 veces**, 5 ya son claves del catálogo (`emerge.medium`,
`emerge.exit`, `emerge.dismiss.passive`, `emerge.strong`, `commit.select.soft`),
3 son el residuo de `4fccf1662` (los `centroid` +2800/+3600/+600), 2 son samples
que **ya tienen nombre** (`ping` en chat-log, `error` en form) y las 7 restantes
son empujones de ±60…±120 de `pitch` sobre una clave del catálogo. Lo único
deliberado —**dirección** (sube/baja), **tres niveles** y **dos samples**—
sobrevive al nombrado trivialmente.
La instantánea sí se construye (F2), pero **sobre el catálogo, no sobre los
packs**: ~15 nombres × 6 intents ≈ 90 filas. Ese es el guard permanente que
§3.5 quería de verdad — fija qué suena cada NOMBRE, así que tocar el catálogo
sale en el diff. Es más pequeño, es estable, y no ancla en basura.
---
## 8. Riesgos
- **Pérdida de matices legítimos: MEDIDA Y DESCARTADA** (§7.1). Las 17 firmas
raras se reparten en claves del catálogo, residuo de ayer, samples ya
nombrados y empujones de pitch. Aun así F5 migra **leyendo cada regla y su
comentario**, que es donde vive el razonamiento — no en los números.
- **Rama compartida.** Otra sesión trabaja en `blocks`. F4/F5 tocan 71 ficheros:
clasificar «míos vs ajenos» por contenido del diff, siempre.
- **Sin flecos** (directiva del autor, 2026-08-06). El plan se ejecuta entero: no
se queda un tier a medio migrar ni conviven dos vocabularios. F4 es la puerta
que lo garantiza — mientras quede una regla sin nombre, el árbol no compila.
- **Se cruza con la cola abierta.** Q2 (5 reglas hápticas inertes) y Q4 (14
eventos huérfanos) son **independientes** — no los bloquea este plan. Q3 sí
queda absorbido. S-07 queda absorbido. **chronos: la exclusión de escritura se
levantó el 2026-08-10 (directiva del autor) — ya es accionable.**
- **`preload` y el fallback mudo** (S-04/S-24/S-25) siguen rotos. Si el catálogo
va a poblarse de WAVs, **S-24 debe arreglarse antes** o un 404 será invisible
para siempre.
---
## 9. Lo que este plan NO hace
No toca el eje del verbo. La medida sugiere que falta un piso de **verbo** en
`SEMA_MAP` (hoy sólo hay `families` e `intents`), y que por eso «un cierre baja»
se re-escribe en 16 packs. Con nombres, esas 16 pasan a decir `soft.fall` — el
síntoma se cura. **La causa —que la dirección de un cierre es un hecho del verbo,
no del componente— queda anotada aquí y sin abrir.** Es el siguiente eje, y es
otra conversación.

Powered by TurnKey Linux.