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

21 KiB

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 §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 (44 hallazgos) · CONTINUE-sema-audit.md (la cola) · architecture/sema.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 —«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

// 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) 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.