docs(process): los nueve defectos abiertos salen de mi memoria y entran en el repo
Los defectos que dejo el barrido docs-codigo del 2026-08-11 vivian solo en la
memoria de la sesion que los encontro. Eso es una superficie de recuerdo del
agente, no del proyecto: un handoff que no se carga los pierde, y son la unica
huella de nueve averias que se decidio NO tocar. Ahora tienen casa, con la forma
del ledger de blocks: escritura por `id`, un ARREGLADO lleva su sha, y una fila
de gap no se borra nunca.
D1 · D2 · D3 · D4 arreglados (`f4e414e2e`, `6f42eebfe`). D5…D9 confirmados y
abiertos. D10 es nuevo y nace de un error mio de metodo.
D10 — la migracion a medias
---------------------------
El 2026-08-06 `dragSignalOverrides` paso a nombrar `step` (el gesto suena por
REPETICION) y eso dejo a los tres resolvers de gesto sin un solo llamador. Yo
lei «cero llamadores» y propuse retirarlos. Cinco documentos dicen lo contrario,
y dos de ellos estaban en la salida de mi propio grep sin que los abriera:
`PLAN-sound-engine.md` §4 los pone en la columna «sema conserva» de la LINEA DE
CORTE con `$sound`, y `PLAN-audio-player.md` D-AP.7 los da por medidos con un
check verde. No es codigo muerto: es una migracion que no se adjudico.
De ahi la regla 4 del ledger. «No lo referencia nadie» es una observacion, nunca
un veredicto — la misma leccion que la fila de «Gaps» que dos agentes borraron.
Verificado antes de escribir cada fila, no copiado de la memoria: D2 esta
arreglado y mi registro lo daba por abierto; y la primera lectura de D9 decia
que los tres `commit-*` de chronos tampoco se disparan — falso, se despachan por
variable en `emitOnChip`, invisibles a un grep de `trigger('literal')`.
Y el handoff del plan
---------------------
`PLAN-event-name-normalization.md` no tenia. El eje esta cerrado (256/256 con
prefijo, guard visto fallar, barrido sobre los 172 morfos), pero quedan dos
decisiones tuyas bloqueando trabajo — D10 y el `present-rise` anclado al trigger
— mas tres cosas que el eje destapo sin cerrar: el `grid` repetido con
`numberOfMonths=2`, el nombre `handle-drag-progress`, y los cinco defectos.
`docs:check` 0 errores sobre 623 docs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
# AUDIT — contradicciones docs↔código: registro de defectos (ledger)
> **Fuente única del estado de los defectos que salieron del barrido
> docs↔morfo del 2026-08-11.** Hasta hoy vivían sólo en la memoria de la
> sesión que los encontró, que es una superficie de recuerdo del agente y no
> del proyecto: un handoff que no se carga los pierde. Este fichero es la casa.
## Por qué existe este fichero
El 2026-08-11 un barrido de alta precisión sacó **101 contradicciones** entre la
documentación y el morfo. La instrucción inicial fue «borra toda la basura», y
fue corregida en el acto: *«puede ser que la documentación esté desfasada o que
el código esté obsoleto, hay que evaluar primero cuál es el caso»*. Sin esa
corrección los 101 hallazgos se habrían aplanado contra el morfo y **habría
desaparecido la única huella de nueve averías reales**.
De ahí el veredicto por sitio, con evidencia (`git log -S`, docs de decisión, el
componente vivo):
- **DOC-DESFASADA** — la documentación miente sobre código correcto → se arregla.
- **CÓDIGO-OBSOLETO** — el código miente sobre documentación correcta → **se
reporta, no se toca**. Son las filas de abajo.
- **FALSO-POSITIVO** — el script se equivocó.
⚠️ Aun con la instrucción explícita, **dos agentes borraron filas de «Gaps» que
documentaban un defecto abierto**. Repuestas a mano. La lección es la regla 3.
## Las reglas de este registro
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
1. **Se escribe por `id`.** `D1` …`D14` no se renumeran nunca. Un defecto que
docs(process): los nueve defectos abiertos salen de mi memoria y entran en el repo
Los defectos que dejo el barrido docs-codigo del 2026-08-11 vivian solo en la
memoria de la sesion que los encontro. Eso es una superficie de recuerdo del
agente, no del proyecto: un handoff que no se carga los pierde, y son la unica
huella de nueve averias que se decidio NO tocar. Ahora tienen casa, con la forma
del ledger de blocks: escritura por `id`, un ARREGLADO lleva su sha, y una fila
de gap no se borra nunca.
D1 · D2 · D3 · D4 arreglados (`f4e414e2e`, `6f42eebfe`). D5…D9 confirmados y
abiertos. D10 es nuevo y nace de un error mio de metodo.
D10 — la migracion a medias
---------------------------
El 2026-08-06 `dragSignalOverrides` paso a nombrar `step` (el gesto suena por
REPETICION) y eso dejo a los tres resolvers de gesto sin un solo llamador. Yo
lei «cero llamadores» y propuse retirarlos. Cinco documentos dicen lo contrario,
y dos de ellos estaban en la salida de mi propio grep sin que los abriera:
`PLAN-sound-engine.md` §4 los pone en la columna «sema conserva» de la LINEA DE
CORTE con `$sound`, y `PLAN-audio-player.md` D-AP.7 los da por medidos con un
check verde. No es codigo muerto: es una migracion que no se adjudico.
De ahi la regla 4 del ledger. «No lo referencia nadie» es una observacion, nunca
un veredicto — la misma leccion que la fila de «Gaps» que dos agentes borraron.
Verificado antes de escribir cada fila, no copiado de la memoria: D2 esta
arreglado y mi registro lo daba por abierto; y la primera lectura de D9 decia
que los tres `commit-*` de chronos tampoco se disparan — falso, se despachan por
variable en `emitOnChip`, invisibles a un grep de `trigger('literal')`.
Y el handoff del plan
---------------------
`PLAN-event-name-normalization.md` no tenia. El eje esta cerrado (256/256 con
prefijo, guard visto fallar, barrido sobre los 172 morfos), pero quedan dos
decisiones tuyas bloqueando trabajo — D10 y el `present-rise` anclado al trigger
— mas tres cosas que el eje destapo sin cerrar: el `grid` repetido con
`numberOfMonths=2`, el nombre `handle-drag-progress`, y los cinco defectos.
`docs:check` 0 errores sobre 623 docs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
resulta ser dos se parte en `D3a` /`D3b`, no desplaza a los siguientes.
2. **Un `ARREGLADO` lleva su commit.** Sin sha no es un arreglo, es una opinión.
3. **Una fila de gap o de known issue NUNCA es basura** , aunque cite nombres
muertos: es la huella de una avería. Borrarla es borrar el defecto, no
arreglarlo.
4. ** «No lo referencia nadie» no es un veredicto.** Es una observación. Antes de
proponer retirar algo hay que abrir TODOS los hits de `docs/` que lo nombren
— `D10` nació precisamente de saltarse esto.
Estados: `CONFIRMADO` (medido, abierto) · `ARREGLADO` (con sha) ·
`PENDIENTE` (sin re-medir) · `DIFERIDO` (confirmado, disposición firmada).
## La tabla
| id | Componente | Estado | Prioridad | Una línea |
| --- | --- | --- | --- | --- |
| D1 | AlertDialog | `ARREGLADO` `f4e414e2e` | P0 | Action y Cancel cerraban sin causa: mudos |
| D2 | Splitter (eidos) | `ARREGLADO` `6f42eebfe` | P0 | regla CSS enganchada a un evento renombrado en mayo |
| D3 | 5 pickers | `ARREGLADO` `f4e414e2e` | P0 | `commit-reset` declarado y jamás disparado |
| D4 | ColorPicker | `ARREGLADO` `f4e414e2e` | P0 | swatch y eyedropper commitean en silencio |
fix(soma): en `modal`, un cierre sin causa es un descarte — y un descarte no commitea
El contrato que los cinco pickers documentan tiene dos salidas: Save confirma,
Cancel revierte al valor con el que se abrio. Escape no es ninguna de las dos, y
tampoco esta bloqueado — descarta en ambos modos por diseño (APG `combobox`; el
framework bloquea Escape en exactamente un sitio, `alertdialog`).
Medido el 2026-08-12: en `modal` el popover no autocerraba al elegir, pero Escape
cerraba Y SE QUEDABA la edicion (05/20 → 05/10). Un tercer camino de salida que
se comportaba como Save, y que ningun documento describe.
Tercera afirmacion falsa de la fila D5
--------------------------------------
Escribi que «`'dismiss'` no lo produce nadie». Lo produce el POPOVER —
`dismissWith('dismiss')` en su manejador de Escape—, no el picker, y por eso el
picker nunca se enteraba. Grepear solo el directorio del picker lo escondio.
El arreglo: la arista de cierre, no la tecla
---------------------------------------------
Interceptar Escape seria fragil y estaria en la capa equivocada: el `Content` es
el del Popover y su gancho de Escape es prop del consumidor, asi que el contrato
del VALOR acabaria viviendo en eidos.
Se vigila la arista de CIERRE: un cierre que no declara causa es un descarte, y
en `modal` un descarte revierte. Eso cubre ademas a un consumidor que baje `open`
a mano, que tampoco es un Save. En `inline` no revierte nada — alli la seleccion
se aplico segun se hacia y el snapshot solo sirve para `cancel()`.
Vive UNA vez, en `watchPickerDismiss` (`picker-shell-handle.svelte.ts`), y los
cinco lo consumen: eran cinco copias del mismo `watch` sobre `open`, con el mismo
`valueOnOpen`. El provider declara su causa desde `closeWith`, asi que `commit()`
y `cancel()` pasan intactos; los de rango pasan su snapshot compuesto tal y como
su propio `cancel()` lo restaura.
Medido, y dos tropiezos propios
--------------------------------
Navegador, date / time / color-picker en `modal`: se edita, Escape cierra el
popover Y el valor vuelve al de apertura.
⚠️ La primera medicion dijo «Escape BLOQUEADO». Era la sonda leyendo a 400 ms, en
plena animacion de salida; la traza temporal muestra el popover aun presente a
+200 ms y ya cerrado, con el valor revertido, a +600 ms. Si me quedo con la
primera lectura, reporto como exito justo la conducta que la doctrina prohibe.
⚠️ Los tres primeros tests pasaban EN VACIO hasta que les añadi `flushSync`:
`watch` no ve una transicion si las tres escrituras caen en el mismo tick, asi
que no observaba ninguna arista. Los cinco estan vistos fallar desactivando la
reversion.
`check` 70 errores (linea base), 2251 tests del uix — los 6 fallos de
`contracts.test.ts` siguen siendo de la otra sesion. `docs:check` 0/623.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| D5 | los 5 pickers | `ARREGLADO` | P1 | en `modal` , un cierre que no declara causa es un descarte, y un descarte no commitea |
feat(soma,morfo): Home y End en la familia de segmentos, con una sola accion declarada
APG `spinbutton` dice que Home salta a `aria-valuemin` y End a `aria-valuemax`.
Tres auditorias lo pidieron por separado —date-field F-1, time-field F-2,
color-field F-2— y las tres coinciden. El min/max ya existia por segmento; solo
faltaba la tecla.
Tercera afirmacion falsa de la fila D6: color-field YA LO TENIA
---------------------------------------------------------------
Su F-2 estaba desfasada. `ColorFieldChannelProvider.handleHomeEnd` existe desde
que se construyo. Asi que el pase no invento conducta: copio la referencia que ya
vivia en el arbol a date-field y time-field, incluidos sus `dayPeriod` — donde
`aria-valuemin` es AM y `aria-valuemax` es PM, luego Home/End son ABSOLUTOS
donde las flechas alternan (pulsar Home dos veces no vuelve a voltear).
Es un JUMP, no un ciclo: no envuelve y no lee el valor previo, asi que aterriza
tambien sobre un segmento vacio.
Una sola accion para los tres
-----------------------------
F-1 proponia `set-min`/`set-max`; color-field declaraba `first-item`/`last-item`.
El tipo obliga a elegir — «Semantic action identifier. Keep consistent across
components for the same intent» — y el catalogo tiene DOS vocabularios: el de
LISTA (`first-item`, 25 usos, y `menu-dial` lo consume por el mapa de acciones
del runtime) y el de VALOR (`set-min`, que usa `knob`). Un segmento es un control
de valor y no tiene items. Los tres declaran ahora `set-min`/`set-max`, y
color-field se alineo: sin riesgo, porque los segmentos despachan por tecla, no
por el mapa del runtime.
Medido
------
Teclado real en el navegador, y cada valor cae exactamente en el aria que su
segmento publica: date-field mes End→12 / Home→01 (min/max 1/12), time-field
hora End→23 / Home→00 (0/23), color-field hex End→ffffff / Home→000000
(0/16777215). Home dos veces no envuelve.
Seis tests nuevos y LOS SEIS VISTOS FALLAR contra la conducta vieja: cerrando el
gate compartido de `isAcceptableSegmentKey` y retirando cada rama por separado.
Uno de ellos es para color-field, que era la referencia del pase y no tenia
ninguno — el arbol copiaba de algo que nadie vigilaba.
⚠️ Un tropiezo propio: la primera version del test numerico llamaba a
`handleHomeEnd` directamente, asi que habria seguido verde si alguien borraba el
enrutado del `keydown`. Reescrito para entrar por `onkeydown`, que es lo que
prueba puerta + enrutado + conducta.
`check` 70 errores (linea base; una pasada intermedia dejo 73 por un acceso a
`dayPeriod` sobre el tipo union — estrechado con `DateAndTimeSegmentObj`, el
mismo que usa el provider). 217/217 en los tres campos + morfo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| D6 | date/time/color-field | `ARREGLADO` | P1 | `Home` /`End` en la familia de segmentos, con una sola acción declarada |
fix(morfo,soma): `defaultElement` era un contrato que no vigilaba nadie
D7 y D8 no eran dos defectos: eran dos instancias de la misma clase. Un censo
del catalogo encontro que `defaultElement` MIENTE en decenas de partes, y es un
contrato — `assertContract`, las recetas y quien lee el morfo lo toman como el
tag que aterriza en el DOM.
D7 · cinco Labels, no dos
-------------------------
El morfo declara `label` y se renderizaba `<div>` en date-field,
date-range-field, time-field, time-range-field y color-picker.
La otra mitad de la fila era FALSA: decia que la doc promete un par `for`/`id`
que nadie emite. No existe tal promesa — `date-field/types.ts:158` dice lo
contrario y bien («Prefer `aria-labelledby` with a `DateField.Label`»). La fila
habia mezclado el hallazgo del `Field` generico, que si emite `for` condicional.
El nombre accesible ya estaba cableado por `aria-labelledby` desde el
`role="group"` (que es el mecanismo correcto: `for=` no puede apuntar a un
grupo) y el clic-a-enfocar ya lo hacia el provider.
Riesgo comprobado antes de tocar: `<label>` es `inline` y `<div>` es `block`.
Dos reciben `display: inline-flex` de `field.css`; los otros tres son items de
flex o grid y el navegador los blockifica. Medido despues en los cinco demos:
ninguno queda `inline`, ninguno arrastra un `for` que no pueda honrar, y la
maquetacion no se mueve.
D8 · los siete arrow, no uno
----------------------------
La sospecha de deuda sistemica era cierta. Los SIETE declaraban `div` y ninguno
renderiza un `div`: cinco componen `internal/arrow.svelte`, cuyo elemento de
parte es un `<span>`, y dos rinden un `<svg>` propio. Cada morfo declara ahora
lo que su componente renderiza.
El guard, y el falso verde que casi cuela
-----------------------------------------
Sin guard esto vuelve a derivar, asi que hay uno en `contracts.test.ts` con las
24 partes restantes enumeradas en `DEFAULT_ELEMENT_DEBT` — visible y sin poder
crecer — mas un detector anti-podredumbre que falla si una entrada de la lista
deja de estar rota.
El primer borrador se fue en FALSO VERDE. Tomaba «el tag del ultimo `{:else}`»,
y el `<svg>` decorativo de `internal/arrow.svelte` no lleva spread: la busqueda
fallaba, el tag volvia `undefined` y una regresion inyectada en `popover.arrow`
PASABA. Se descubrio inyectandola antes de fiarse. La regla correcta es que el
elemento de la parte es EL QUE DIFUNDE LOS PROPS. Con ella el guard encontro 8
violaciones mas que el censo a mano.
Segunda correccion: hay partes polimorficas por diseño — `media-player.media`
rinde `audio` o `video`, `breadcrumb.link` `span` o `a`. El guard lee TODAS las
ramas y da el contrato por bueno si el declarado esta entre ellas; leer solo la
primera las marcaba como mentira. Eso saco a `chat-composer.input` de la lista
de deuda, donde yo lo habia metido por error — lo dijo el propio detector.
Las 24 que quedan (D11) se parten en dos y por eso no van en bloque: unas el
morfo va detras del componente (arreglo mecanico), otras el componente va detras
del morfo con peso de a11y — `tree-view.item` declara `li` y rinde `div`,
`stepper.list` declara `ol`, `tooltip.trigger` declara `button`. Eso es
semantica de lista y de control: son decisiones, no ediciones.
Queda abierto D12, tambien del censo: `internal/arrow.svelte` dibuja poligono
MAS un contorno trazado, y las dos flechas propias solo el poligono. Dos de
siete flechas del sistema no tienen contorno. El arreglo es que compongan la
primitiva compartida, pero es un cambio visual y no se improvisa.
Verificado: 2240 tests del uix en verde (los 6 fallos de `contracts.test.ts` que
se ven en el arbol son de la otra sesion — waveform, media-player, audio-player,
menubar, aura, radio-group, tabs — y el guard nuevo no esta entre ellos);
`check` 70 errores, linea base; `docs:check` 0/623.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| D7 | 5 componentes de campo | `ARREGLADO` | P1 | el Label renderizaba `<div>` y el morfo declara `label` |
| D8 | los 7 `arrow` | `ARREGLADO` | P2 | `defaultElement` falso en el `arrow` — sistémico, confirmado |
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| D9 | chronos | `ARREGLADO` | P2 | el acarreo habla: `handle-drag` y `handle-resize` , anclados y a la cadencia del gesto |
docs(process): la ronda de decisiones queda firmada — cinco disposiciones, dos corregidas al re-analizar
D10 SE RETIRA (lo ejecuta el eje de sonido, su handoff PRIMERO), y el
re-analisis añade un SEXTO sitio a adjudicar: sema.md §per-emit payload aun
describe pitch/gain/contour cuando soma adjunta hoy sound:'step' + curva
haptica (dragSignalOverrides del slider y del knob, con el trade-off del
2026-08-06 citado en su comentario).
fixedWeeks: alinear a false a secas era la opcion debil — las filas del mes
son de altura FIJA (grid-auto-rows, chronos.css:278) y un false pelado cambia
la semana fantasma por saltos de altura al navegar. Firmado: crecer las filas
(modelo Google), con false incluido; es arreglo de RECETA, no un flip de flag.
Chip bloqueado: via (b), y la letra pequeña va INCLUIDA — el morfo de
drag-drop YA declara data-disabled (declaracion sin emisor) y el cursor vive
en drag-drop.css; pero el chip fusiona tres morfos en un elemento clicable,
asi que la regla de archetype item se anula en su receta y aria-disabled NO
aterriza en el elemento fusionado.
mode/scope: SE RETIRAN, con el barrido de la regla 4 hecho de verdad: 0 hits
en docs/, 0 lectores del compilado, 4 ficheros de alcance. SemaCause queda
como pregunta hermana (mas muerto aun: ni atraviesa morfo).
present-rise: medir primero (lo esperable es la receta F4, pero decide la
medida). handle-drag-progress: revisar contra CANON, no renombrar — el matiz
es legal y puede ser deliberado.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| D10 | sema ↔ `$sound` | `CONFIRMADO` · decisión FIRMADA: retirar | P1 | los 3 resolvers de gesto — la retirada la firma el autor el 2026-08-12 y la EJECUTA la sesión del eje de sonido, empezando por su handoff |
fix(morfo,soma): las 4 ultimas de D11 — el guard se queda sin excepciones
`DEFAULT_ELEMENT_DEBT` esta vacio: las 28 partes que el censo encontro dicen ya
la verdad sobre el elemento que renderizan. Estas cuatro pedian un cambio con
consecuencias, y la leccion es que «que lado esta mal» solo se contesta mirando.
chronos.event-chip — el morfo tenia razon, faltaba el puente
------------------------------------------------------------
El motivo estaba escrito desde el 2026-08-10: el chip CONTIENE el tirador de
redimensionado y el modelo de contenido de un `<button>` no admite un control
anidado, asi que es `div` + `role='button'`. Lo que faltaba era el «tabindex
propiedad de soma» que ese mismo comentario promete y que nunca existio. El
provider emite ahora `tabindex: 0` y un `onkeydown` que convierte Enter/Espacio
en un clic — con `preventDefault` sobre el espacio, que si no desplaza la
pagina— y el componente pasa a ser el `div` que su contrato declara.
tooltip.trigger — probe el morfo, me equivoque, y lo corrigio la captura
------------------------------------------------------------------------
Declaraba `button`, asi que renderice un `<button>`. La captura mostro el
cromado nativo alrededor del disparador: un recuadro que antes no estaba.
La receta llama a esta parte «a focusable shell» y difiere el anillo de foco «to
the wrapped element». Es un ENVOLTORIO: el control real del consumidor va DENTRO,
y un `<button>` envolviendo un `<button>` es el mismo anidamiento invalido del
chip de chronos. El lado equivocado era el morfo. Declara `div`, y la a11y la dan
el `tabindex: 0` del provider y el `aria-describedby` del morfo, que es lo que el
patron APG de tooltip pide de verdad.
stepper.item — no era declaracion, era patron
----------------------------------------------
Un `div` SIN rol dentro de un `role='tablist'`. El patron real es
`list (tablist) > item > trigger (tab)`, y un elemento generico entre un tablist
y sus tabs rompe la relacion de posesion. Es `role='presentation'` ahora: el
envoltorio sale del arbol, igual que un `<li>` dentro de un `role='menu'`. El
idioma ya estaba en 8 componentes del catalogo, no lo invento.
color-picker.channel-input — una declaracion que nada podia satisfacer
-----------------------------------------------------------------------
Declaraba `input` mientras compone `ColorField.Input`, que es `div` +
`role='group'` — el contenedor de segmentos, la misma forma que el `input` de
date-field. Las piezas editables son las partes hermanas `channel-segment`.
Verificado
----------
Guard en verde CON LA LISTA VACIA. Navegador: el trigger de tooltip vuelve a ser
texto plano (sin cromado), enfocable, y abre al foco; consola limpia en tooltip y
chronos. 2246 tests del uix (los 6 fallos de `contracts.test.ts` siguen siendo de
la otra sesion), `check` 70 errores en linea base — una pasada intermedia dejo 71
por un `SomaKeyboardEvent` sin importar en chronos. `docs:check` 0/623.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| D11 | catálogo | `ARREGLADO` | P1 | `defaultElement` mentía en 28 partes; las 28 dicen ya la verdad y el guard no tiene excepciones |
fix(morfo,soma,eidos): una flecha, una forma — y `defaultElement` deja de mentir en 24 partes
D12 · las dos flechas sueltas
-----------------------------
`internal/arrow.svelte` dibuja poligono MAS un contorno trazado; context-menu y
link-preview rendian un `<svg>` propio con solo el poligono. Dos de las siete
flechas del sistema no tenian contorno — medido: link-preview no tenia `<path>`
ninguno mientras tooltip si.
Ahora componen la primitiva, asi que las siete son el mismo `<span>` con el mismo
`<svg>` y las siete declaran `span`. Las recetas pasan a direccionar las formas
por dentro (`polygon { fill }`, `path { stroke }` con `non-scaling-stroke`):
un `fill` sobre el envoltorio no puede pisar los atributos de presentacion que
poligono y path llevan encima.
⚠️ El arreglo destapo otro defecto. Al componer la primitiva la flecha
DESAPARECIO: `<span>` de 0x0, sin `<svg>` dentro. Los wrappers de eidos de estos
dos pasaban `{@render children?.()}` INCONDICIONALMENTE, y la primitiva lee
cualquier snippet de children como «el consumidor trae su propio glifo» y se
salta el suyo. popover y tooltip no pasan children en absoluto, por eso nunca les
paso. Los dos son condicionales ahora. Es la regla «eidos wrappers need
conditional children», reaprendida midiendo en vez de leyendo.
Medido despues: los dos dan `<span>` 10x5 con `<svg>` 10x5, poligono relleno y
`<path>` con trazo, identicos a tooltip (el control). Consola limpia.
D11 · 24 de 28
--------------
Eran 28, no 24 — mi cifra anterior estaba mal.
Dieciseis son el morfo yendo detras de un componente que ya renderiza lo mas
correcto (`header`, `p`, `span`, `button`): edicion de declaracion, el DOM no se
mueve.
Ocho parecian del grupo contrario Y NO LO ERAN. `tree-view.item` declara `li` y
rinde `div`, si — pero tambien declara `role='treeitem'`, y lo mismo
`file-upload` con `list`/`listitem`, `feed` con `article`, `stepper.list` con
`tablist`, `tree-view.branch-content` con `group`. La a11y NO esta rota: el rol
explicito carga la semantica que daria el elemento nativo. La declaracion era
aspiracional. Cambiar el DOM a listas nativas es una mejora deliberada aparte,
no algo que colar en un pase de verdad-del-contrato.
Las 4 que quedan piden un cambio con consecuencias, y cada una lo lleva escrito
en `DEFAULT_ELEMENT_DEBT`:
- `chronos.event-chip` — aqui el morfo es el que tiene razon, con el motivo
escrito desde el 2026-08-10: el chip CONTIENE el tirador de redimensionado y
el modelo de contenido de un `<button>` no admite un control anidado. El
componente rinde `<button>` igual. Pero el «tabindex propiedad de soma» que ese
mismo comentario promete NO EXISTE en la parte, asi que cambiar el elemento hoy
canjearia HTML invalido por un control sin foco.
- `tooltip.trigger` — `button` declarado, `div` con `tabindex: 0` y sin rol
rendido. Un boton nativo se trae `type=submit` dentro de formularios.
- `stepper.item` — `div` sin rol dentro de un `role='tablist'`. Problema de
patron, no de declaracion.
- `color-picker.channel-input` — compone `ColorFieldInput`, no renderiza un
elemento.
Verificado: guard de `defaultElement` en verde con las 4 de deuda; 2246 tests del
uix (los 6 fallos de `contracts.test.ts` siguen siendo de la otra sesion);
`check` 70 errores, linea base.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| D12 | context-menu · link-preview | `ARREGLADO` | P2 | sus flechas componen ya la primitiva compartida: una flecha, una forma |
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| D13 | 4 componentes | `CONFIRMADO` | P1 | 7 eventos declarados que nadie emite — enumerados y guardados |
| D14 | chronos | `CONFIRMADO` | P1 | `restoreChipFocus` pierde el foco: el movimiento por teclado muere al primer paso |
docs(process): los nueve defectos abiertos salen de mi memoria y entran en el repo
Los defectos que dejo el barrido docs-codigo del 2026-08-11 vivian solo en la
memoria de la sesion que los encontro. Eso es una superficie de recuerdo del
agente, no del proyecto: un handoff que no se carga los pierde, y son la unica
huella de nueve averias que se decidio NO tocar. Ahora tienen casa, con la forma
del ledger de blocks: escritura por `id`, un ARREGLADO lleva su sha, y una fila
de gap no se borra nunca.
D1 · D2 · D3 · D4 arreglados (`f4e414e2e`, `6f42eebfe`). D5…D9 confirmados y
abiertos. D10 es nuevo y nace de un error mio de metodo.
D10 — la migracion a medias
---------------------------
El 2026-08-06 `dragSignalOverrides` paso a nombrar `step` (el gesto suena por
REPETICION) y eso dejo a los tres resolvers de gesto sin un solo llamador. Yo
lei «cero llamadores» y propuse retirarlos. Cinco documentos dicen lo contrario,
y dos de ellos estaban en la salida de mi propio grep sin que los abriera:
`PLAN-sound-engine.md` §4 los pone en la columna «sema conserva» de la LINEA DE
CORTE con `$sound`, y `PLAN-audio-player.md` D-AP.7 los da por medidos con un
check verde. No es codigo muerto: es una migracion que no se adjudico.
De ahi la regla 4 del ledger. «No lo referencia nadie» es una observacion, nunca
un veredicto — la misma leccion que la fila de «Gaps» que dos agentes borraron.
Verificado antes de escribir cada fila, no copiado de la memoria: D2 esta
arreglado y mi registro lo daba por abierto; y la primera lectura de D9 decia
que los tres `commit-*` de chronos tampoco se disparan — falso, se despachan por
variable en `emitOnChip`, invisibles a un grep de `trigger('literal')`.
Y el handoff del plan
---------------------
`PLAN-event-name-normalization.md` no tenia. El eje esta cerrado (256/256 con
prefijo, guard visto fallar, barrido sobre los 172 morfos), pero quedan dos
decisiones tuyas bloqueando trabajo — D10 y el `present-rise` anclado al trigger
— mas tres cosas que el eje destapo sin cerrar: el `grid` repetido con
`numberOfMonths=2`, el nombre `handle-drag-progress`, y los cinco defectos.
`docs:check` 0 errores sobre 623 docs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
---
## Fichas
### D1 · AlertDialog mudo — `ARREGLADO` (`f4e414e2e`)
Action y Cancel llamaban `dialog.handleClose()` , que sólo voltea `open` : nunca
pasaban por `dismissWith` ni disparaban `emerge-close` . Medido: sólo sellaba
`contact-activate` . Escape sí funcionaba, así que **el teclado tenía firma y los
botones no**.
Arreglo: Action llama `dismissWith('save', { intent })` y Cancel
`dismissWith('cancel')` . `dismissWith` gana un `opts.intent` porque la causa es
vocabulario cerrado pero el PESO es por instancia — el mismo eje por el que
`emerge-open` liga con `fromProp` . Medido: Action → commit/risk/saved, Cancel →
emerge/cancelled.
### D2 · Regla CSS muerta del splitter — `ARREGLADO` (`6f42eebfe`)
`splitter.css` enganchaba `data-event='commit-resize'` , evento renombrado a
`commit-set` en `bd2e40366` (2026-05-22). No se arreglaba renombrando: el
`commit-set` de hoy apunta al `provider` , no al trigger.
Arreglo: la regla engancha por familia sobre el provider
(`[data-event-family='commit'][data-event-phase='active']`) y pinta el trigger
con **selector descendente** , más un opt-out del anillo global de commit. La
firma que pinta otro nodo es un selector descendente — no una razón para mover
el sello (doctrina en `docs/architecture/eidos.md` §«descendant-selector
corollary»).
### D3 · `commit-reset` mudo en 5 pickers — `ARREGLADO` (`f4e414e2e`)
Declarado en date / time / date-range / time-range / color y jamás disparado:
`clear()` sólo asignaba.
Al arreglarlo salió **una segunda avería debajo** : date-picker y
date-range-picker apuntaban `commit-reset` a la parte `calendar` , que nadie
registra en el runtime — destino inalcanzable, emit rechazado en silencio.
Retargeteados al `provider` .
⚠️ **Una parte declarada sin registro en runtime es un destino inalcanzable, y
no chilla.** Vale para todo el catálogo, no sólo para estos dos.
### D4 · ColorPicker commitea en silencio — `ARREGLADO` (`f4e414e2e`)
Swatch y eyedropper aplican el color sin disparar nada, pese a que el morfo **y**
el pack de sema declaran que disparan `commit-set` .
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### D5 · Escape en `modal` cierra sin revertir — `ARREGLADO` (2026-08-12)
docs(soma,process): D5, D6 y D9 medidos — y cuatro afirmaciones del ledger eran falsas
Al ir a arreglarlos, tres de las cinco filas resultaron decir cosas que no se
sostienen. Las corrijo con la evidencia delante, porque una fila que miente es
peor que una fila vacia.
D5 — la doc ya estaba adjudicada; no se propago
-----------------------------------------------
La fila decia dos cosas falsas. (1) «modal promete bloquear Escape»: esa promesa
ya se habia adjudicado AL REVES el 2026-08-11 en tres pickers, con razon escrita
en `time-picker/types.ts:42` — Escape descarta en AMBOS modos porque el morfo
declara el patron APG `combobox`, y el framework bloquea Escape en exactamente un
sitio, `alertdialog`; tragarselo dejaria a un usuario de teclado sin salida salvo
que el consumidor recordara componer un Cancel. La correccion no llego al handle
compartido ni a date-picker / date-range-picker. Propagada aqui. (2) «no hay
buffer»: si lo hay — `valueOnOpen` se captura en la arista de apertura y
`cancel()` lo restaura.
Lo que SI es defecto, medido en navegador: en `mode='modal'` el popover no
autocierra al elegir, pero Escape cierra Y SE QUEDA la edicion (05/20 → 05/10).
Es un tercer camino de salida que se comporta como Save, y el contrato del modo
solo tiene dos. La causa esta a la vista: `PickerCloseCause` es
`'save' | 'cancel' | 'dismiss'` y **`'dismiss'` no lo produce nadie** — misma
clase que D1/D3/D4. Escape cierra por la via del Popover sin pasar por
`closeWith`, asi que ni sella causa ni revierte; ningun picker cablea
`escapeKeydownBehavior`, luego los cinco se comportan igual.
Queda decision: que Escape produzca `dismiss` y que `dismiss` revierta en modal
(no en inline). Se deduce de los dos modos documentados, pero cambia el
comportamiento de cinco componentes, asi que no lo improviso.
D6 — no es una decision sin tomar, es una spec sin construir
-------------------------------------------------------------
La fila decia «Home/End/PageUp/PageDown documentados en 4 sitios» y «las tres
paginas se contradicen sobre que harian». Ninguna de las dos: PageUp/PageDown no
aparecen en ninguna parte, y las tres auditorias COINCIDEN — `Home` → `set-min`,
`End` → `set-max`, APG spinbutton, extensivo a date/time/color-field. F-1 llega a
escribir la declaracion del morfo literal.
El min/max ya existe por segmento (`aria-valuemin`/`aria-valuemax`); falta la
tecla en el plan de teclado de los tres morfos y el enrutado en los varios
`onkeydown` de cada provider. La auditoria lo dimensiona como pass de familia.
D9 — los dos documentos de chronos discrepaban
-----------------------------------------------
El README de soma decia que el pack «ships rules» para `handle-drag` y
`handle-resize`; el SPEC, que se retiraron el 2026-08-07 por codigo muerto. El
SPEC tenia razon — el pack solo lleva los tres `commit-*`. README al dia.
Lo que queda es la decision que el SPEC ya deja preparada: o el provider los
emite al traducir el drag-drop reutilizado a comandos —y entonces el gesto suena
por REPETICION, `step` por emision, como el resto de arrastres— o las dos
DECLARACIONES se retiran del morfo.
Verificado: `docs:check` 0/623, `check` 70 errores (linea base), 199/199 en
date-picker + picker-shell + morfo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️ **Dos afirmaciones de esta fila eran falsas y se corrigen aquí.**
1. *«`mode='modal'` promete bloquear Escape»* — la promesa existía sólo en
[`picker-shell-handle.svelte.ts:32` ](../../src/uix/soma/components/picker-shell/picker-shell-handle.svelte.ts )
y en un comentario de `date-picker.svelte` . **Era doc rancia** : el 2026-08-11
se adjudicó lo contrario en tres pickers, con razón escrita
([`time-picker/types.ts:42`](../../src/uix/soma/components/time-picker/types.ts)):
Escape descarta en AMBOS modos porque el morfo declara el patrón APG
`combobox` y el framework bloquea Escape en exactamente un sitio,
`alertdialog` ; tragárselo dejaría a un usuario de teclado sin salida salvo
que el consumidor recordara componer un Cancel. La adjudicación no se propagó
al handle compartido ni a date-picker / date-range-picker. **Propagada el
2026-08-12.**
2. *«No hay buffer»* — sí lo hay:
[`date-picker-provider.svelte.ts:153` ](../../src/uix/soma/components/date-picker/date-picker-provider.svelte.ts )
captura `valueOnOpen` en la arista de apertura y `cancel()` (:262) lo
restaura.
**Lo que sí es un defecto, medido en navegador el 2026-08-12** (date-picker en
`mode='modal'` ): el popover no autocierra al elegir ✓, pero Escape **cierra y se
queda la edición** (05/20 → 05/10). Es un tercer camino de salida que se comporta
como Save, y el contrato documentado del modo sólo tiene dos: Save confirma,
Cancel revierte.
La causa está a la vista: `PickerCloseCause` es `'save' | 'cancel' | 'dismiss'`
([`picker-shell-handle.svelte.ts:28`](../../src/uix/soma/components/picker-shell/picker-shell-handle.svelte.ts))
y ** `'dismiss'` no lo produce nadie** — misma clase que D1/D3/D4. Escape cierra
por la vía del Popover sin pasar por `closeWith` , así que ni sella causa ni
revierte. Ningún picker cablea `escapeKeydownBehavior` : los cinco se comportan
igual.
fix(soma): en `modal`, un cierre sin causa es un descarte — y un descarte no commitea
El contrato que los cinco pickers documentan tiene dos salidas: Save confirma,
Cancel revierte al valor con el que se abrio. Escape no es ninguna de las dos, y
tampoco esta bloqueado — descarta en ambos modos por diseño (APG `combobox`; el
framework bloquea Escape en exactamente un sitio, `alertdialog`).
Medido el 2026-08-12: en `modal` el popover no autocerraba al elegir, pero Escape
cerraba Y SE QUEDABA la edicion (05/20 → 05/10). Un tercer camino de salida que
se comportaba como Save, y que ningun documento describe.
Tercera afirmacion falsa de la fila D5
--------------------------------------
Escribi que «`'dismiss'` no lo produce nadie». Lo produce el POPOVER —
`dismissWith('dismiss')` en su manejador de Escape—, no el picker, y por eso el
picker nunca se enteraba. Grepear solo el directorio del picker lo escondio.
El arreglo: la arista de cierre, no la tecla
---------------------------------------------
Interceptar Escape seria fragil y estaria en la capa equivocada: el `Content` es
el del Popover y su gancho de Escape es prop del consumidor, asi que el contrato
del VALOR acabaria viviendo en eidos.
Se vigila la arista de CIERRE: un cierre que no declara causa es un descarte, y
en `modal` un descarte revierte. Eso cubre ademas a un consumidor que baje `open`
a mano, que tampoco es un Save. En `inline` no revierte nada — alli la seleccion
se aplico segun se hacia y el snapshot solo sirve para `cancel()`.
Vive UNA vez, en `watchPickerDismiss` (`picker-shell-handle.svelte.ts`), y los
cinco lo consumen: eran cinco copias del mismo `watch` sobre `open`, con el mismo
`valueOnOpen`. El provider declara su causa desde `closeWith`, asi que `commit()`
y `cancel()` pasan intactos; los de rango pasan su snapshot compuesto tal y como
su propio `cancel()` lo restaura.
Medido, y dos tropiezos propios
--------------------------------
Navegador, date / time / color-picker en `modal`: se edita, Escape cierra el
popover Y el valor vuelve al de apertura.
⚠️ La primera medicion dijo «Escape BLOQUEADO». Era la sonda leyendo a 400 ms, en
plena animacion de salida; la traza temporal muestra el popover aun presente a
+200 ms y ya cerrado, con el valor revertido, a +600 ms. Si me quedo con la
primera lectura, reporto como exito justo la conducta que la doctrina prohibe.
⚠️ Los tres primeros tests pasaban EN VACIO hasta que les añadi `flushSync`:
`watch` no ve una transicion si las tres escrituras caen en el mismo tick, asi
que no observaba ninguna arista. Los cinco estan vistos fallar desactivando la
reversion.
`check` 70 errores (linea base), 2251 tests del uix — los 6 fallos de
`contracts.test.ts` siguen siendo de la otra sesion. `docs:check` 0/623.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**ARREGLADO 2026-08-12** — y con una tercera corrección de la fila: *«`'dismiss'`
no lo produce nadie»* también era falso. Lo produce el **Popover**
(`dismissWith('dismiss')` en su manejador de Escape), no el picker; por eso el
picker nunca se enteraba. Grepear sólo el directorio del picker lo escondió.
El arreglo **no intercepta la tecla** , que sería frágil y estaría en la capa
equivocada (el `Content` es el del Popover, y su gancho de Escape es prop del
consumidor). Vigila la **arista de cierre** : un cierre que no declara causa es un
descarte, y en `modal` un descarte revierte al valor con el que se abrió. Eso
cubre además a un consumidor que baje `open` a mano, que tampoco es un Save. En
`inline` no revierte nada — allí la selección se aplicó según se hacía y el
snapshot sólo sirve para `cancel()` .
Vive una vez, en `watchPickerDismiss` (`picker-shell-handle.svelte.ts`), y los
cinco pickers lo consumen: eran cinco copias del mismo `watch` sobre `open` . El
provider declara su causa desde `closeWith` , así que `commit()` y `cancel()`
pasan intactos.
Medido en navegador (date / time / color-picker en `modal` ): se edita, Escape
cierra el popover Y el valor vuelve al de apertura. ⚠️ La primera medición dijo
«Escape BLOQUEADO» — era la sonda leyendo a 400 ms, en plena animación de salida;
la traza temporal muestra el popover aún presente a +200 ms y ya cerrado, con el
valor revertido, a +600 ms.
Cinco tests sobre el guard compartido (`picker-shell-handle.svelte.test.ts`),
**vistos fallar** desactivando la reversión. ⚠️ Los tres primeros pasaban *en
vacío* hasta que se les añadió `flushSync` : `watch` no ve una transición si las
tres escrituras caen en el mismo tick, así que no observaba ninguna arista.
docs(soma,process): D5, D6 y D9 medidos — y cuatro afirmaciones del ledger eran falsas
Al ir a arreglarlos, tres de las cinco filas resultaron decir cosas que no se
sostienen. Las corrijo con la evidencia delante, porque una fila que miente es
peor que una fila vacia.
D5 — la doc ya estaba adjudicada; no se propago
-----------------------------------------------
La fila decia dos cosas falsas. (1) «modal promete bloquear Escape»: esa promesa
ya se habia adjudicado AL REVES el 2026-08-11 en tres pickers, con razon escrita
en `time-picker/types.ts:42` — Escape descarta en AMBOS modos porque el morfo
declara el patron APG `combobox`, y el framework bloquea Escape en exactamente un
sitio, `alertdialog`; tragarselo dejaria a un usuario de teclado sin salida salvo
que el consumidor recordara componer un Cancel. La correccion no llego al handle
compartido ni a date-picker / date-range-picker. Propagada aqui. (2) «no hay
buffer»: si lo hay — `valueOnOpen` se captura en la arista de apertura y
`cancel()` lo restaura.
Lo que SI es defecto, medido en navegador: en `mode='modal'` el popover no
autocierra al elegir, pero Escape cierra Y SE QUEDA la edicion (05/20 → 05/10).
Es un tercer camino de salida que se comporta como Save, y el contrato del modo
solo tiene dos. La causa esta a la vista: `PickerCloseCause` es
`'save' | 'cancel' | 'dismiss'` y **`'dismiss'` no lo produce nadie** — misma
clase que D1/D3/D4. Escape cierra por la via del Popover sin pasar por
`closeWith`, asi que ni sella causa ni revierte; ningun picker cablea
`escapeKeydownBehavior`, luego los cinco se comportan igual.
Queda decision: que Escape produzca `dismiss` y que `dismiss` revierta en modal
(no en inline). Se deduce de los dos modos documentados, pero cambia el
comportamiento de cinco componentes, asi que no lo improviso.
D6 — no es una decision sin tomar, es una spec sin construir
-------------------------------------------------------------
La fila decia «Home/End/PageUp/PageDown documentados en 4 sitios» y «las tres
paginas se contradicen sobre que harian». Ninguna de las dos: PageUp/PageDown no
aparecen en ninguna parte, y las tres auditorias COINCIDEN — `Home` → `set-min`,
`End` → `set-max`, APG spinbutton, extensivo a date/time/color-field. F-1 llega a
escribir la declaracion del morfo literal.
El min/max ya existe por segmento (`aria-valuemin`/`aria-valuemax`); falta la
tecla en el plan de teclado de los tres morfos y el enrutado en los varios
`onkeydown` de cada provider. La auditoria lo dimensiona como pass de familia.
D9 — los dos documentos de chronos discrepaban
-----------------------------------------------
El README de soma decia que el pack «ships rules» para `handle-drag` y
`handle-resize`; el SPEC, que se retiraron el 2026-08-07 por codigo muerto. El
SPEC tenia razon — el pack solo lleva los tres `commit-*`. README al dia.
Lo que queda es la decision que el SPEC ya deja preparada: o el provider los
emite al traducir el drag-drop reutilizado a comandos —y entonces el gesto suena
por REPETICION, `step` por emision, como el resto de arrastres— o las dos
DECLARACIONES se retiran del morfo.
Verificado: `docs:check` 0/623, `check` 70 errores (linea base), 199/199 en
date-picker + picker-shell + morfo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### D6 · `Home` / `End` en la familia de segmentos — `CONFIRMADO` · P1
⚠️ **Otra fila con dos afirmaciones falsas.** Decía «`Home`/`End`/`PageUp`/
`PageDown` documentados en 4 sitios» y «las tres páginas se contradicen sobre qué
harían». `PageUp` /`PageDown` **no aparecen en ninguna parte** , y las tres
auditorías **coinciden** — no se contradicen:
| Documento | Qué especifica |
| --- | --- |
| [`audit/components/date-field.md` ](../audit/components/date-field.md ) F-1 | `{ key: 'Home', action: 'set-min' }` / `{ key: 'End', action: 'set-max' }` en el morfo + implementación en provider, «extensivo a time-field/color-field (misma familia de segmentos)» |
| [`audit/components/time-field.md` ](../audit/components/time-field.md ) F-2 | «Sin Home/End (APG spinbutton) — pass de familia de segmentos (con date/color)» |
| [`audit/components/color-field.md` ](../audit/components/color-field.md ) F-2 | «especialmente útil aquí: canales 0-255/0-360 — pass de familia» |
feat(soma,morfo): Home y End en la familia de segmentos, con una sola accion declarada
APG `spinbutton` dice que Home salta a `aria-valuemin` y End a `aria-valuemax`.
Tres auditorias lo pidieron por separado —date-field F-1, time-field F-2,
color-field F-2— y las tres coinciden. El min/max ya existia por segmento; solo
faltaba la tecla.
Tercera afirmacion falsa de la fila D6: color-field YA LO TENIA
---------------------------------------------------------------
Su F-2 estaba desfasada. `ColorFieldChannelProvider.handleHomeEnd` existe desde
que se construyo. Asi que el pase no invento conducta: copio la referencia que ya
vivia en el arbol a date-field y time-field, incluidos sus `dayPeriod` — donde
`aria-valuemin` es AM y `aria-valuemax` es PM, luego Home/End son ABSOLUTOS
donde las flechas alternan (pulsar Home dos veces no vuelve a voltear).
Es un JUMP, no un ciclo: no envuelve y no lee el valor previo, asi que aterriza
tambien sobre un segmento vacio.
Una sola accion para los tres
-----------------------------
F-1 proponia `set-min`/`set-max`; color-field declaraba `first-item`/`last-item`.
El tipo obliga a elegir — «Semantic action identifier. Keep consistent across
components for the same intent» — y el catalogo tiene DOS vocabularios: el de
LISTA (`first-item`, 25 usos, y `menu-dial` lo consume por el mapa de acciones
del runtime) y el de VALOR (`set-min`, que usa `knob`). Un segmento es un control
de valor y no tiene items. Los tres declaran ahora `set-min`/`set-max`, y
color-field se alineo: sin riesgo, porque los segmentos despachan por tecla, no
por el mapa del runtime.
Medido
------
Teclado real en el navegador, y cada valor cae exactamente en el aria que su
segmento publica: date-field mes End→12 / Home→01 (min/max 1/12), time-field
hora End→23 / Home→00 (0/23), color-field hex End→ffffff / Home→000000
(0/16777215). Home dos veces no envuelve.
Seis tests nuevos y LOS SEIS VISTOS FALLAR contra la conducta vieja: cerrando el
gate compartido de `isAcceptableSegmentKey` y retirando cada rama por separado.
Uno de ellos es para color-field, que era la referencia del pase y no tenia
ninguno — el arbol copiaba de algo que nadie vigilaba.
⚠️ Un tropiezo propio: la primera version del test numerico llamaba a
`handleHomeEnd` directamente, asi que habria seguido verde si alguien borraba el
enrutado del `keydown`. Reescrito para entrar por `onkeydown`, que es lo que
prueba puerta + enrutado + conducta.
`check` 70 errores (linea base; una pasada intermedia dejo 73 por un acceso a
`dayPeriod` sobre el tipo union — estrechado con `DateAndTimeSegmentObj`, el
mismo que usa el provider). 217/217 en los tres campos + morfo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
No era una decisión sin tomar: era una **especificación acordada sin construir** ,
con la declaración del morfo escrita literalmente en F-1.
**Hecho el 2026-08-12** — y con una tercera corrección de la fila: **color-field
YA lo tenía implementado** (`handleHomeEnd`, desde que se construyó). Su F-2
estaba desfasada. Así que el pase no inventó la conducta: copió la referencia que
ya vivía en el árbol, a date-field y time-field, incluidos sus segmentos
`dayPeriod` (donde `aria-valuemin` es AM y `aria-valuemax` es PM, así que Home /
End son absolutos donde las flechas ALTERNAN).
**Una sola acción declarada.** F-1 proponía `set-min` / `set-max` ; color-field
declaraba `first-item` / `last-item` . El tipo obliga a elegir —
*«Semantic action identifier. Keep consistent across components for the same
intent»*— y el catálogo tiene dos vocabularios: el de LISTA (`first-item`, 25
usos, y `menu-dial` lo consume por el mapa de acciones del runtime) y el de VALOR
(`set-min`, que usa `knob` ). Un segmento es un control de valor y no tiene ítems,
así que los tres declaran `set-min` / `set-max` y color-field se alineó. Sin
riesgo: los segmentos despachan por tecla, no por el mapa del runtime.
Medido con teclado real en el navegador, y los valores caen exactamente en el
aria que cada segmento publica: date-field mes `End→12 / Home→01` (min/max 1/12),
time-field hora `End→23 / Home→00` (0/23), color-field hex `End→ffffff /
Home→000000` (0/16777215). Home dos veces no envuelve.
Seis tests nuevos, **los seis vistos fallar** contra la conducta vieja
(inyectando el cierre del gate compartido y la retirada de cada rama). Incluido
uno para color-field, que era la referencia y **no tenía ninguno** .
docs(process): los nueve defectos abiertos salen de mi memoria y entran en el repo
Los defectos que dejo el barrido docs-codigo del 2026-08-11 vivian solo en la
memoria de la sesion que los encontro. Eso es una superficie de recuerdo del
agente, no del proyecto: un handoff que no se carga los pierde, y son la unica
huella de nueve averias que se decidio NO tocar. Ahora tienen casa, con la forma
del ledger de blocks: escritura por `id`, un ARREGLADO lleva su sha, y una fila
de gap no se borra nunca.
D1 · D2 · D3 · D4 arreglados (`f4e414e2e`, `6f42eebfe`). D5…D9 confirmados y
abiertos. D10 es nuevo y nace de un error mio de metodo.
D10 — la migracion a medias
---------------------------
El 2026-08-06 `dragSignalOverrides` paso a nombrar `step` (el gesto suena por
REPETICION) y eso dejo a los tres resolvers de gesto sin un solo llamador. Yo
lei «cero llamadores» y propuse retirarlos. Cinco documentos dicen lo contrario,
y dos de ellos estaban en la salida de mi propio grep sin que los abriera:
`PLAN-sound-engine.md` §4 los pone en la columna «sema conserva» de la LINEA DE
CORTE con `$sound`, y `PLAN-audio-player.md` D-AP.7 los da por medidos con un
check verde. No es codigo muerto: es una migracion que no se adjudico.
De ahi la regla 4 del ledger. «No lo referencia nadie» es una observacion, nunca
un veredicto — la misma leccion que la fila de «Gaps» que dos agentes borraron.
Verificado antes de escribir cada fila, no copiado de la memoria: D2 esta
arreglado y mi registro lo daba por abierto; y la primera lectura de D9 decia
que los tres `commit-*` de chronos tampoco se disparan — falso, se despachan por
variable en `emitOnChip`, invisibles a un grep de `trigger('literal')`.
Y el handoff del plan
---------------------
`PLAN-event-name-normalization.md` no tenia. El eje esta cerrado (256/256 con
prefijo, guard visto fallar, barrido sobre los 172 morfos), pero quedan dos
decisiones tuyas bloqueando trabajo — D10 y el `present-rise` anclado al trigger
— mas tres cosas que el eje destapo sin cerrar: el `grid` repetido con
`numberOfMonths=2`, el nombre `handle-drag-progress`, y los cinco defectos.
`docs:check` 0 errores sobre 623 docs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
fix(morfo,soma): `defaultElement` era un contrato que no vigilaba nadie
D7 y D8 no eran dos defectos: eran dos instancias de la misma clase. Un censo
del catalogo encontro que `defaultElement` MIENTE en decenas de partes, y es un
contrato — `assertContract`, las recetas y quien lee el morfo lo toman como el
tag que aterriza en el DOM.
D7 · cinco Labels, no dos
-------------------------
El morfo declara `label` y se renderizaba `<div>` en date-field,
date-range-field, time-field, time-range-field y color-picker.
La otra mitad de la fila era FALSA: decia que la doc promete un par `for`/`id`
que nadie emite. No existe tal promesa — `date-field/types.ts:158` dice lo
contrario y bien («Prefer `aria-labelledby` with a `DateField.Label`»). La fila
habia mezclado el hallazgo del `Field` generico, que si emite `for` condicional.
El nombre accesible ya estaba cableado por `aria-labelledby` desde el
`role="group"` (que es el mecanismo correcto: `for=` no puede apuntar a un
grupo) y el clic-a-enfocar ya lo hacia el provider.
Riesgo comprobado antes de tocar: `<label>` es `inline` y `<div>` es `block`.
Dos reciben `display: inline-flex` de `field.css`; los otros tres son items de
flex o grid y el navegador los blockifica. Medido despues en los cinco demos:
ninguno queda `inline`, ninguno arrastra un `for` que no pueda honrar, y la
maquetacion no se mueve.
D8 · los siete arrow, no uno
----------------------------
La sospecha de deuda sistemica era cierta. Los SIETE declaraban `div` y ninguno
renderiza un `div`: cinco componen `internal/arrow.svelte`, cuyo elemento de
parte es un `<span>`, y dos rinden un `<svg>` propio. Cada morfo declara ahora
lo que su componente renderiza.
El guard, y el falso verde que casi cuela
-----------------------------------------
Sin guard esto vuelve a derivar, asi que hay uno en `contracts.test.ts` con las
24 partes restantes enumeradas en `DEFAULT_ELEMENT_DEBT` — visible y sin poder
crecer — mas un detector anti-podredumbre que falla si una entrada de la lista
deja de estar rota.
El primer borrador se fue en FALSO VERDE. Tomaba «el tag del ultimo `{:else}`»,
y el `<svg>` decorativo de `internal/arrow.svelte` no lleva spread: la busqueda
fallaba, el tag volvia `undefined` y una regresion inyectada en `popover.arrow`
PASABA. Se descubrio inyectandola antes de fiarse. La regla correcta es que el
elemento de la parte es EL QUE DIFUNDE LOS PROPS. Con ella el guard encontro 8
violaciones mas que el censo a mano.
Segunda correccion: hay partes polimorficas por diseño — `media-player.media`
rinde `audio` o `video`, `breadcrumb.link` `span` o `a`. El guard lee TODAS las
ramas y da el contrato por bueno si el declarado esta entre ellas; leer solo la
primera las marcaba como mentira. Eso saco a `chat-composer.input` de la lista
de deuda, donde yo lo habia metido por error — lo dijo el propio detector.
Las 24 que quedan (D11) se parten en dos y por eso no van en bloque: unas el
morfo va detras del componente (arreglo mecanico), otras el componente va detras
del morfo con peso de a11y — `tree-view.item` declara `li` y rinde `div`,
`stepper.list` declara `ol`, `tooltip.trigger` declara `button`. Eso es
semantica de lista y de control: son decisiones, no ediciones.
Queda abierto D12, tambien del censo: `internal/arrow.svelte` dibuja poligono
MAS un contorno trazado, y las dos flechas propias solo el poligono. Dos de
siete flechas del sistema no tienen contorno. El arreglo es que compongan la
primitiva compartida, pero es un cambio visual y no se improvisa.
Verificado: 2240 tests del uix en verde (los 6 fallos de `contracts.test.ts` que
se ven en el arbol son de la otra sesion — waveform, media-player, audio-player,
menubar, aura, radio-group, tabs — y el guard nuevo no esta entre ellos);
`check` 70 errores, linea base; `docs:check` 0/623.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### D7 · El Label de los campos renderizaba `<div>` — `ARREGLADO` (2026-08-12)
El morfo declara `defaultElement: 'label'` y el componente renderizaba `<div>` .
No eran dos componentes sino **cinco** : date-field, date-range-field, time-field,
time-range-field y color-picker.
⚠️ **La otra mitad de esta fila era falsa.** Decía «la doc promete un par
`for` /`id` que nadie emite»; no existe tal promesa en date-field —
[`types.ts:158` ](../../src/uix/soma/components/date-field/types.ts ) dice lo
contrario y bien: *«Prefer `aria-labelledby` with a `DateField.Label`»* . La fila
había mezclado el hallazgo del ** `Field` genérico** (`field.md:19`, que sí emite
`for` condicional) con el date-field. El nombre accesible ya estaba cableado por
`aria-labelledby` desde el `role="group"` — que es el mecanismo correcto, porque
`for=` no puede apuntar a un grupo — y el clic-a-enfocar ya lo implementaba
`DateFieldLabelProvider.onclick` (enfoca el primer segmento).
Riesgo comprobado antes de tocar, no supuesto: `<label>` es `inline` por defecto
y `<div>` es `block` . Dos de los cinco reciben `display: inline-flex` de
`field.css` vía `fieldRole('label')` ; los otros tres son ítems de flex o grid, y
el navegador los blockifica. Medido después en los cinco demos: ninguno queda en
`inline` , ninguno arrastra un `for` que no pueda honrar, y la maquetación no se
mueve.
### D8 · `defaultElement` falso en los `arrow` — `ARREGLADO` (2026-08-12)
La sospecha de deuda sistémica era cierta y peor de lo escrito: **los siete
`arrow` del catálogo declaraban `div` y ninguno renderiza un `div` .** Cinco
(combobox, dropdown-menu, popover, select, tooltip) componen
[`components/internal/arrow.svelte` ](../../src/uix/soma/components/internal/arrow.svelte ),
cuyo elemento de parte es un `<span>` ; dos (context-menu, link-preview) rinden un
`<svg>` propio. Cada morfo declara ahora lo que su componente renderiza.
### D11 · `defaultElement` miente en 24 partes más — `CONFIRMADO` · P1
El censo que cerró D8 destapó la clase entera: **nada verificaba
`defaultElement` **, y es un contrato — `assertContract` , las recetas y quien lee
el morfo lo toman como el tag que aterriza en el DOM.
Hay un guard desde el 2026-08-12
([`contracts.test.ts`](../../src/uix/contracts.test.ts), «guards defaultElement
against the tag the soma part actually renders»), con las 24 restantes
enumeradas en `DEFAULT_ELEMENT_DEBT` para que la deuda sea visible y no crezca.
El guard lleva además un detector anti-podredumbre: si una entrada de la lista
deja de estar rota, falla pidiendo que se retire.
fix(morfo,soma,eidos): una flecha, una forma — y `defaultElement` deja de mentir en 24 partes
D12 · las dos flechas sueltas
-----------------------------
`internal/arrow.svelte` dibuja poligono MAS un contorno trazado; context-menu y
link-preview rendian un `<svg>` propio con solo el poligono. Dos de las siete
flechas del sistema no tenian contorno — medido: link-preview no tenia `<path>`
ninguno mientras tooltip si.
Ahora componen la primitiva, asi que las siete son el mismo `<span>` con el mismo
`<svg>` y las siete declaran `span`. Las recetas pasan a direccionar las formas
por dentro (`polygon { fill }`, `path { stroke }` con `non-scaling-stroke`):
un `fill` sobre el envoltorio no puede pisar los atributos de presentacion que
poligono y path llevan encima.
⚠️ El arreglo destapo otro defecto. Al componer la primitiva la flecha
DESAPARECIO: `<span>` de 0x0, sin `<svg>` dentro. Los wrappers de eidos de estos
dos pasaban `{@render children?.()}` INCONDICIONALMENTE, y la primitiva lee
cualquier snippet de children como «el consumidor trae su propio glifo» y se
salta el suyo. popover y tooltip no pasan children en absoluto, por eso nunca les
paso. Los dos son condicionales ahora. Es la regla «eidos wrappers need
conditional children», reaprendida midiendo en vez de leyendo.
Medido despues: los dos dan `<span>` 10x5 con `<svg>` 10x5, poligono relleno y
`<path>` con trazo, identicos a tooltip (el control). Consola limpia.
D11 · 24 de 28
--------------
Eran 28, no 24 — mi cifra anterior estaba mal.
Dieciseis son el morfo yendo detras de un componente que ya renderiza lo mas
correcto (`header`, `p`, `span`, `button`): edicion de declaracion, el DOM no se
mueve.
Ocho parecian del grupo contrario Y NO LO ERAN. `tree-view.item` declara `li` y
rinde `div`, si — pero tambien declara `role='treeitem'`, y lo mismo
`file-upload` con `list`/`listitem`, `feed` con `article`, `stepper.list` con
`tablist`, `tree-view.branch-content` con `group`. La a11y NO esta rota: el rol
explicito carga la semantica que daria el elemento nativo. La declaracion era
aspiracional. Cambiar el DOM a listas nativas es una mejora deliberada aparte,
no algo que colar en un pase de verdad-del-contrato.
Las 4 que quedan piden un cambio con consecuencias, y cada una lo lleva escrito
en `DEFAULT_ELEMENT_DEBT`:
- `chronos.event-chip` — aqui el morfo es el que tiene razon, con el motivo
escrito desde el 2026-08-10: el chip CONTIENE el tirador de redimensionado y
el modelo de contenido de un `<button>` no admite un control anidado. El
componente rinde `<button>` igual. Pero el «tabindex propiedad de soma» que ese
mismo comentario promete NO EXISTE en la parte, asi que cambiar el elemento hoy
canjearia HTML invalido por un control sin foco.
- `tooltip.trigger` — `button` declarado, `div` con `tabindex: 0` y sin rol
rendido. Un boton nativo se trae `type=submit` dentro de formularios.
- `stepper.item` — `div` sin rol dentro de un `role='tablist'`. Problema de
patron, no de declaracion.
- `color-picker.channel-input` — compone `ColorFieldInput`, no renderiza un
elemento.
Verificado: guard de `defaultElement` en verde con las 4 de deuda; 2246 tests del
uix (los 6 fallos de `contracts.test.ts` siguen siendo de la otra sesion);
`check` 70 errores, linea base.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Cerradas 24 de 28 el 2026-08-12** (eran 28, no 24: mi cifra anterior estaba
mal). Dieciséis eran el morfo yendo detrás de un componente que ya renderiza lo
más correcto — edición de declaración, el DOM no se mueve. Ocho más parecían del
grupo contrario y no lo eran: declaran un `role` explícito que carga la semántica
que daría el elemento nativo (`role='list'`, `listitem'` , `treeitem'` , `group'` ,
`article'` , `tablist'` ) o son decorativas (`aria-hidden`). Ahí la a11y **no está
rota** y la declaración era aspiracional; cambiar el DOM a listas nativas es una
mejora deliberada aparte, no algo que colar en un pase de verdad-del-contrato.
fix(morfo,soma): las 4 ultimas de D11 — el guard se queda sin excepciones
`DEFAULT_ELEMENT_DEBT` esta vacio: las 28 partes que el censo encontro dicen ya
la verdad sobre el elemento que renderizan. Estas cuatro pedian un cambio con
consecuencias, y la leccion es que «que lado esta mal» solo se contesta mirando.
chronos.event-chip — el morfo tenia razon, faltaba el puente
------------------------------------------------------------
El motivo estaba escrito desde el 2026-08-10: el chip CONTIENE el tirador de
redimensionado y el modelo de contenido de un `<button>` no admite un control
anidado, asi que es `div` + `role='button'`. Lo que faltaba era el «tabindex
propiedad de soma» que ese mismo comentario promete y que nunca existio. El
provider emite ahora `tabindex: 0` y un `onkeydown` que convierte Enter/Espacio
en un clic — con `preventDefault` sobre el espacio, que si no desplaza la
pagina— y el componente pasa a ser el `div` que su contrato declara.
tooltip.trigger — probe el morfo, me equivoque, y lo corrigio la captura
------------------------------------------------------------------------
Declaraba `button`, asi que renderice un `<button>`. La captura mostro el
cromado nativo alrededor del disparador: un recuadro que antes no estaba.
La receta llama a esta parte «a focusable shell» y difiere el anillo de foco «to
the wrapped element». Es un ENVOLTORIO: el control real del consumidor va DENTRO,
y un `<button>` envolviendo un `<button>` es el mismo anidamiento invalido del
chip de chronos. El lado equivocado era el morfo. Declara `div`, y la a11y la dan
el `tabindex: 0` del provider y el `aria-describedby` del morfo, que es lo que el
patron APG de tooltip pide de verdad.
stepper.item — no era declaracion, era patron
----------------------------------------------
Un `div` SIN rol dentro de un `role='tablist'`. El patron real es
`list (tablist) > item > trigger (tab)`, y un elemento generico entre un tablist
y sus tabs rompe la relacion de posesion. Es `role='presentation'` ahora: el
envoltorio sale del arbol, igual que un `<li>` dentro de un `role='menu'`. El
idioma ya estaba en 8 componentes del catalogo, no lo invento.
color-picker.channel-input — una declaracion que nada podia satisfacer
-----------------------------------------------------------------------
Declaraba `input` mientras compone `ColorField.Input`, que es `div` +
`role='group'` — el contenedor de segmentos, la misma forma que el `input` de
date-field. Las piezas editables son las partes hermanas `channel-segment`.
Verificado
----------
Guard en verde CON LA LISTA VACIA. Navegador: el trigger de tooltip vuelve a ser
texto plano (sin cromado), enfocable, y abre al foco; consola limpia en tooltip y
chronos. 2246 tests del uix (los 6 fallos de `contracts.test.ts` siguen siendo de
la otra sesion), `check` 70 errores en linea base — una pasada intermedia dejo 71
por un `SomaKeyboardEvent` sin importar en chronos. `docs:check` 0/623.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Las 4 últimas, cerradas el mismo día.** Cada una pedía un cambio con
consecuencias, y la lección es que la pregunta «¿qué lado está mal?» sólo se
contesta mirando:
- `chronos.event-chip` — **el morfo tenía razón** , con el motivo escrito desde el
2026-08-10: el chip CONTIENE el tirador de redimensionado y el modelo de
contenido de un `<button>` no admite un control anidado, así que es `div` +
`role='button'` . Lo que faltaba era el puente: el «`tabindex` propiedad de soma»
que ese comentario promete no existía. Ahora el provider emite `tabindex: 0` y
un `onkeydown` que convierte Enter / Espacio en un clic (con `preventDefault`
sobre el espacio, que si no desplaza la página), y el componente puede ser el
`div` que su contrato declara.
- `tooltip.trigger` — **probé el morfo y me equivoqué; la medición lo corrigió.**
Declaraba `button` , así que rendericé un `<button>` … y la captura mostró el
cromado nativo alrededor del disparador. La receta llama a esta parte *«a
focusable shell»* y difiere el anillo de foco *«to the wrapped element»* : es un
ENVOLTORIO, el control real del consumidor va dentro, y un `<button>` que
envuelve un `<button>` es el mismo anidamiento inválido del chip. El morfo era
el lado equivocado; declara `div` , y la a11y la dan el `tabindex: 0` del
provider y el `aria-describedby` del morfo, que es lo que el patrón APG pide.
- `stepper.item` — un `div` **sin rol** dentro de un `role='tablist'` . El patrón
es `list (tablist) > item > trigger (tab)` , y un elemento genérico entre un
tablist y sus tabs rompe la relación de posesión. Es `role='presentation'`
ahora — el envoltorio sale del árbol, igual que un `<li>` dentro de un
`role='menu'` ; el idioma ya estaba en 8 componentes del catálogo.
- `color-picker.channel-input` — declaraba `input` mientras compone
`ColorField.Input` , que es `div` + `role='group'` (el contenedor de segmentos,
la misma forma que el `input` de date-field). Ninguna composición podía
satisfacer esa declaración: las piezas editables son las partes hermanas
`channel-segment` .
`DEFAULT_ELEMENT_DEBT` está **vacío** , y su comentario explica que una entrada
nueva es la decisión de publicar un contrato que miente.
fix(morfo,soma,eidos): una flecha, una forma — y `defaultElement` deja de mentir en 24 partes
D12 · las dos flechas sueltas
-----------------------------
`internal/arrow.svelte` dibuja poligono MAS un contorno trazado; context-menu y
link-preview rendian un `<svg>` propio con solo el poligono. Dos de las siete
flechas del sistema no tenian contorno — medido: link-preview no tenia `<path>`
ninguno mientras tooltip si.
Ahora componen la primitiva, asi que las siete son el mismo `<span>` con el mismo
`<svg>` y las siete declaran `span`. Las recetas pasan a direccionar las formas
por dentro (`polygon { fill }`, `path { stroke }` con `non-scaling-stroke`):
un `fill` sobre el envoltorio no puede pisar los atributos de presentacion que
poligono y path llevan encima.
⚠️ El arreglo destapo otro defecto. Al componer la primitiva la flecha
DESAPARECIO: `<span>` de 0x0, sin `<svg>` dentro. Los wrappers de eidos de estos
dos pasaban `{@render children?.()}` INCONDICIONALMENTE, y la primitiva lee
cualquier snippet de children como «el consumidor trae su propio glifo» y se
salta el suyo. popover y tooltip no pasan children en absoluto, por eso nunca les
paso. Los dos son condicionales ahora. Es la regla «eidos wrappers need
conditional children», reaprendida midiendo en vez de leyendo.
Medido despues: los dos dan `<span>` 10x5 con `<svg>` 10x5, poligono relleno y
`<path>` con trazo, identicos a tooltip (el control). Consola limpia.
D11 · 24 de 28
--------------
Eran 28, no 24 — mi cifra anterior estaba mal.
Dieciseis son el morfo yendo detras de un componente que ya renderiza lo mas
correcto (`header`, `p`, `span`, `button`): edicion de declaracion, el DOM no se
mueve.
Ocho parecian del grupo contrario Y NO LO ERAN. `tree-view.item` declara `li` y
rinde `div`, si — pero tambien declara `role='treeitem'`, y lo mismo
`file-upload` con `list`/`listitem`, `feed` con `article`, `stepper.list` con
`tablist`, `tree-view.branch-content` con `group`. La a11y NO esta rota: el rol
explicito carga la semantica que daria el elemento nativo. La declaracion era
aspiracional. Cambiar el DOM a listas nativas es una mejora deliberada aparte,
no algo que colar en un pase de verdad-del-contrato.
Las 4 que quedan piden un cambio con consecuencias, y cada una lo lleva escrito
en `DEFAULT_ELEMENT_DEBT`:
- `chronos.event-chip` — aqui el morfo es el que tiene razon, con el motivo
escrito desde el 2026-08-10: el chip CONTIENE el tirador de redimensionado y
el modelo de contenido de un `<button>` no admite un control anidado. El
componente rinde `<button>` igual. Pero el «tabindex propiedad de soma» que ese
mismo comentario promete NO EXISTE en la parte, asi que cambiar el elemento hoy
canjearia HTML invalido por un control sin foco.
- `tooltip.trigger` — `button` declarado, `div` con `tabindex: 0` y sin rol
rendido. Un boton nativo se trae `type=submit` dentro de formularios.
- `stepper.item` — `div` sin rol dentro de un `role='tablist'`. Problema de
patron, no de declaracion.
- `color-picker.channel-input` — compone `ColorFieldInput`, no renderiza un
elemento.
Verificado: guard de `defaultElement` en verde con las 4 de deuda; 2246 tests del
uix (los 6 fallos de `contracts.test.ts` siguen siendo de la otra sesion);
`check` 70 errores, linea base.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Las 24 se partieron en dos, y por eso no se arreglaron en bloque:
fix(morfo,soma): `defaultElement` era un contrato que no vigilaba nadie
D7 y D8 no eran dos defectos: eran dos instancias de la misma clase. Un censo
del catalogo encontro que `defaultElement` MIENTE en decenas de partes, y es un
contrato — `assertContract`, las recetas y quien lee el morfo lo toman como el
tag que aterriza en el DOM.
D7 · cinco Labels, no dos
-------------------------
El morfo declara `label` y se renderizaba `<div>` en date-field,
date-range-field, time-field, time-range-field y color-picker.
La otra mitad de la fila era FALSA: decia que la doc promete un par `for`/`id`
que nadie emite. No existe tal promesa — `date-field/types.ts:158` dice lo
contrario y bien («Prefer `aria-labelledby` with a `DateField.Label`»). La fila
habia mezclado el hallazgo del `Field` generico, que si emite `for` condicional.
El nombre accesible ya estaba cableado por `aria-labelledby` desde el
`role="group"` (que es el mecanismo correcto: `for=` no puede apuntar a un
grupo) y el clic-a-enfocar ya lo hacia el provider.
Riesgo comprobado antes de tocar: `<label>` es `inline` y `<div>` es `block`.
Dos reciben `display: inline-flex` de `field.css`; los otros tres son items de
flex o grid y el navegador los blockifica. Medido despues en los cinco demos:
ninguno queda `inline`, ninguno arrastra un `for` que no pueda honrar, y la
maquetacion no se mueve.
D8 · los siete arrow, no uno
----------------------------
La sospecha de deuda sistemica era cierta. Los SIETE declaraban `div` y ninguno
renderiza un `div`: cinco componen `internal/arrow.svelte`, cuyo elemento de
parte es un `<span>`, y dos rinden un `<svg>` propio. Cada morfo declara ahora
lo que su componente renderiza.
El guard, y el falso verde que casi cuela
-----------------------------------------
Sin guard esto vuelve a derivar, asi que hay uno en `contracts.test.ts` con las
24 partes restantes enumeradas en `DEFAULT_ELEMENT_DEBT` — visible y sin poder
crecer — mas un detector anti-podredumbre que falla si una entrada de la lista
deja de estar rota.
El primer borrador se fue en FALSO VERDE. Tomaba «el tag del ultimo `{:else}`»,
y el `<svg>` decorativo de `internal/arrow.svelte` no lleva spread: la busqueda
fallaba, el tag volvia `undefined` y una regresion inyectada en `popover.arrow`
PASABA. Se descubrio inyectandola antes de fiarse. La regla correcta es que el
elemento de la parte es EL QUE DIFUNDE LOS PROPS. Con ella el guard encontro 8
violaciones mas que el censo a mano.
Segunda correccion: hay partes polimorficas por diseño — `media-player.media`
rinde `audio` o `video`, `breadcrumb.link` `span` o `a`. El guard lee TODAS las
ramas y da el contrato por bueno si el declarado esta entre ellas; leer solo la
primera las marcaba como mentira. Eso saco a `chat-composer.input` de la lista
de deuda, donde yo lo habia metido por error — lo dijo el propio detector.
Las 24 que quedan (D11) se parten en dos y por eso no van en bloque: unas el
morfo va detras del componente (arreglo mecanico), otras el componente va detras
del morfo con peso de a11y — `tree-view.item` declara `li` y rinde `div`,
`stepper.list` declara `ol`, `tooltip.trigger` declara `button`. Eso es
semantica de lista y de control: son decisiones, no ediciones.
Queda abierto D12, tambien del censo: `internal/arrow.svelte` dibuja poligono
MAS un contorno trazado, y las dos flechas propias solo el poligono. Dos de
siete flechas del sistema no tienen contorno. El arreglo es que compongan la
primitiva compartida, pero es un cambio visual y no se improvisa.
Verificado: 2240 tests del uix en verde (los 6 fallos de `contracts.test.ts` que
se ven en el arbol son de la otra sesion — waveform, media-player, audio-player,
menubar, aura, radio-group, tabs — y el guard nuevo no esta entre ellos);
`check` 70 errores, linea base; `docs:check` 0/623.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- **El componente renderiza lo más correcto y el morfo va detrás** —
`calendar.header` / `range-calendar.header` (`header`), `field.helper-text` /
`field.error-text` (`p`), los cuatro de `slider` (`span`), `chronos.event-chip`
(`button`)… Arreglo mecánico: poner al día el morfo.
- **El morfo declara lo más correcto y el componente va detrás, con peso de
a11y** — `tree-view.item` / `.branch` declaran `li` y rinden `div` ,
`tree-view.branch-content` declara `ul` , `stepper.list` declara `ol` ,
`file-upload.file-list` declara `ul` , `feed.article` declara `article` ,
`tooltip.trigger` declara `button` . Rendirlos como `div` pierde la semántica
de lista / landmark / control que APG espera. **Son decisiones, no ediciones.**
⚠️ Notas de método, por si alguien reescribe el guard: (1) el elemento de la
parte es **el que difunde los props** , no «el tag del último `{:else}` » — el
primer borrador usó lo segundo y se fue en FALSO VERDE, porque el `<svg>`
decorativo de `internal/arrow.svelte` no lleva spread; se descubrió inyectando
una regresión antes de fiarse. (2) Hay partes **polimórficas por diseño**
(`media-player.media` rinde `audio` o `video` , `breadcrumb.link` `span` o `a` ):
el guard lee TODAS las ramas y da el contrato por bueno si el declarado está
entre ellas.
### D12 · Dos flechas se dibujan distinto que las otras cinco — `CONFIRMADO` · P2
Salió al censar D8. `internal/arrow.svelte` dibuja `<polygon>` **más** un
`<path>` de contorno trazado; las flechas propias de
[`context-menu` ](../../src/uix/soma/components/context-menu/components/context-menu-arrow.svelte )
y [`link-preview` ](../../src/uix/soma/components/link-preview/components/link-preview-arrow.svelte )
dibujan sólo el polígono. Dos de siete flechas del sistema no tienen contorno.
fix(morfo,soma,eidos): una flecha, una forma — y `defaultElement` deja de mentir en 24 partes
D12 · las dos flechas sueltas
-----------------------------
`internal/arrow.svelte` dibuja poligono MAS un contorno trazado; context-menu y
link-preview rendian un `<svg>` propio con solo el poligono. Dos de las siete
flechas del sistema no tenian contorno — medido: link-preview no tenia `<path>`
ninguno mientras tooltip si.
Ahora componen la primitiva, asi que las siete son el mismo `<span>` con el mismo
`<svg>` y las siete declaran `span`. Las recetas pasan a direccionar las formas
por dentro (`polygon { fill }`, `path { stroke }` con `non-scaling-stroke`):
un `fill` sobre el envoltorio no puede pisar los atributos de presentacion que
poligono y path llevan encima.
⚠️ El arreglo destapo otro defecto. Al componer la primitiva la flecha
DESAPARECIO: `<span>` de 0x0, sin `<svg>` dentro. Los wrappers de eidos de estos
dos pasaban `{@render children?.()}` INCONDICIONALMENTE, y la primitiva lee
cualquier snippet de children como «el consumidor trae su propio glifo» y se
salta el suyo. popover y tooltip no pasan children en absoluto, por eso nunca les
paso. Los dos son condicionales ahora. Es la regla «eidos wrappers need
conditional children», reaprendida midiendo en vez de leyendo.
Medido despues: los dos dan `<span>` 10x5 con `<svg>` 10x5, poligono relleno y
`<path>` con trazo, identicos a tooltip (el control). Consola limpia.
D11 · 24 de 28
--------------
Eran 28, no 24 — mi cifra anterior estaba mal.
Dieciseis son el morfo yendo detras de un componente que ya renderiza lo mas
correcto (`header`, `p`, `span`, `button`): edicion de declaracion, el DOM no se
mueve.
Ocho parecian del grupo contrario Y NO LO ERAN. `tree-view.item` declara `li` y
rinde `div`, si — pero tambien declara `role='treeitem'`, y lo mismo
`file-upload` con `list`/`listitem`, `feed` con `article`, `stepper.list` con
`tablist`, `tree-view.branch-content` con `group`. La a11y NO esta rota: el rol
explicito carga la semantica que daria el elemento nativo. La declaracion era
aspiracional. Cambiar el DOM a listas nativas es una mejora deliberada aparte,
no algo que colar en un pase de verdad-del-contrato.
Las 4 que quedan piden un cambio con consecuencias, y cada una lo lleva escrito
en `DEFAULT_ELEMENT_DEBT`:
- `chronos.event-chip` — aqui el morfo es el que tiene razon, con el motivo
escrito desde el 2026-08-10: el chip CONTIENE el tirador de redimensionado y
el modelo de contenido de un `<button>` no admite un control anidado. El
componente rinde `<button>` igual. Pero el «tabindex propiedad de soma» que ese
mismo comentario promete NO EXISTE en la parte, asi que cambiar el elemento hoy
canjearia HTML invalido por un control sin foco.
- `tooltip.trigger` — `button` declarado, `div` con `tabindex: 0` y sin rol
rendido. Un boton nativo se trae `type=submit` dentro de formularios.
- `stepper.item` — `div` sin rol dentro de un `role='tablist'`. Problema de
patron, no de declaracion.
- `color-picker.channel-input` — compone `ColorFieldInput`, no renderiza un
elemento.
Verificado: guard de `defaultElement` en verde con las 4 de deuda; 2246 tests del
uix (los 6 fallos de `contracts.test.ts` siguen siendo de la otra sesion);
`check` 70 errores, linea base.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**ARREGLADO 2026-08-12**: las dos componen ya la primitiva compartida, así que
las siete flechas del sistema son el mismo `<span>` con el mismo `<svg>` , y las
siete declaran `span` . Las recetas pasan a direccionar las formas por dentro
(`polygon { fill }`, `path { stroke }` con `vector-effect: non-scaling-stroke` ),
porque un `fill` sobre el envoltorio no puede pisar los atributos de presentación
que polígono y path llevan encima.
⚠️ **Y el arreglo destapó otro defecto por el camino.** Al componer la primitiva,
la flecha desapareció: `<span>` de 0× 0 y sin `<svg>` dentro. Causa: los wrappers
de eidos de estos dos pasaban `{@render children?.()}` **incondicionalmente** , y
la primitiva lee CUALQUIER snippet de children como «el consumidor trae su propio
glifo» y se salta el suyo. popover y tooltip no pasan children en absoluto, por
eso nunca les pasó. Los dos wrappers son condicionales ahora — es la regla
«eidos wrappers need conditional children», reaprendida midiendo.
Medido tras el cambio: context-menu y link-preview dan `<span>` 10× 5 con `<svg>`
10× 5, polígono relleno y `<path>` con trazo — idénticos a tooltip, que es el
control. Antes link-preview no tenía `<path>` **ninguno** . Consola limpia.
docs(process): los nueve defectos abiertos salen de mi memoria y entran en el repo
Los defectos que dejo el barrido docs-codigo del 2026-08-11 vivian solo en la
memoria de la sesion que los encontro. Eso es una superficie de recuerdo del
agente, no del proyecto: un handoff que no se carga los pierde, y son la unica
huella de nueve averias que se decidio NO tocar. Ahora tienen casa, con la forma
del ledger de blocks: escritura por `id`, un ARREGLADO lleva su sha, y una fila
de gap no se borra nunca.
D1 · D2 · D3 · D4 arreglados (`f4e414e2e`, `6f42eebfe`). D5…D9 confirmados y
abiertos. D10 es nuevo y nace de un error mio de metodo.
D10 — la migracion a medias
---------------------------
El 2026-08-06 `dragSignalOverrides` paso a nombrar `step` (el gesto suena por
REPETICION) y eso dejo a los tres resolvers de gesto sin un solo llamador. Yo
lei «cero llamadores» y propuse retirarlos. Cinco documentos dicen lo contrario,
y dos de ellos estaban en la salida de mi propio grep sin que los abriera:
`PLAN-sound-engine.md` §4 los pone en la columna «sema conserva» de la LINEA DE
CORTE con `$sound`, y `PLAN-audio-player.md` D-AP.7 los da por medidos con un
check verde. No es codigo muerto: es una migracion que no se adjudico.
De ahi la regla 4 del ledger. «No lo referencia nadie» es una observacion, nunca
un veredicto — la misma leccion que la fila de «Gaps» que dos agentes borraron.
Verificado antes de escribir cada fila, no copiado de la memoria: D2 esta
arreglado y mi registro lo daba por abierto; y la primera lectura de D9 decia
que los tres `commit-*` de chronos tampoco se disparan — falso, se despachan por
variable en `emitOnChip`, invisibles a un grep de `trigger('literal')`.
Y el handoff del plan
---------------------
`PLAN-event-name-normalization.md` no tenia. El eje esta cerrado (256/256 con
prefijo, guard visto fallar, barrido sobre los 172 morfos), pero quedan dos
decisiones tuyas bloqueando trabajo — D10 y el `present-rise` anclado al trigger
— mas tres cosas que el eje destapo sin cerrar: el `grid` repetido con
`numberOfMonths=2`, el nombre `handle-drag-progress`, y los cinco defectos.
`docs:check` 0 errores sobre 623 docs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### D9 · Eventos de chronos sin emisor — `CONFIRMADO` · P2
El morfo de chronos declara `handle-drag`
([`chronos.ts:131`](../../src/uix/morfo/components/chronos.ts)) y `handle-resize`
(:141), y **ningún provider los dispara** : el barrido de `trigger(` en
`soma/components/chronos/` da `shift-navigate` , `commit-restore` , `commit-apply`
y el trío `commit-save` /`commit-move`/`commit-delete` de `emitOnChip` . El
arrastre y el redimensionado emiten su `commit-move` , nunca la familia `handle`
que declaran. Ya declarado como S-37 en el README de chronos.
⚠️ Corrección de método, 2026-08-12: la primera lectura de esta fila dio «los
tres `commit-*` tampoco se disparan». Era falsa — se despachan **por variable**
en `emitOnChip` (`chronos-provider.svelte.ts:1240`), invisible a un grep de
`trigger('literal')` .
docs(soma,process): D5, D6 y D9 medidos — y cuatro afirmaciones del ledger eran falsas
Al ir a arreglarlos, tres de las cinco filas resultaron decir cosas que no se
sostienen. Las corrijo con la evidencia delante, porque una fila que miente es
peor que una fila vacia.
D5 — la doc ya estaba adjudicada; no se propago
-----------------------------------------------
La fila decia dos cosas falsas. (1) «modal promete bloquear Escape»: esa promesa
ya se habia adjudicado AL REVES el 2026-08-11 en tres pickers, con razon escrita
en `time-picker/types.ts:42` — Escape descarta en AMBOS modos porque el morfo
declara el patron APG `combobox`, y el framework bloquea Escape en exactamente un
sitio, `alertdialog`; tragarselo dejaria a un usuario de teclado sin salida salvo
que el consumidor recordara componer un Cancel. La correccion no llego al handle
compartido ni a date-picker / date-range-picker. Propagada aqui. (2) «no hay
buffer»: si lo hay — `valueOnOpen` se captura en la arista de apertura y
`cancel()` lo restaura.
Lo que SI es defecto, medido en navegador: en `mode='modal'` el popover no
autocierra al elegir, pero Escape cierra Y SE QUEDA la edicion (05/20 → 05/10).
Es un tercer camino de salida que se comporta como Save, y el contrato del modo
solo tiene dos. La causa esta a la vista: `PickerCloseCause` es
`'save' | 'cancel' | 'dismiss'` y **`'dismiss'` no lo produce nadie** — misma
clase que D1/D3/D4. Escape cierra por la via del Popover sin pasar por
`closeWith`, asi que ni sella causa ni revierte; ningun picker cablea
`escapeKeydownBehavior`, luego los cinco se comportan igual.
Queda decision: que Escape produzca `dismiss` y que `dismiss` revierta en modal
(no en inline). Se deduce de los dos modos documentados, pero cambia el
comportamiento de cinco componentes, asi que no lo improviso.
D6 — no es una decision sin tomar, es una spec sin construir
-------------------------------------------------------------
La fila decia «Home/End/PageUp/PageDown documentados en 4 sitios» y «las tres
paginas se contradicen sobre que harian». Ninguna de las dos: PageUp/PageDown no
aparecen en ninguna parte, y las tres auditorias COINCIDEN — `Home` → `set-min`,
`End` → `set-max`, APG spinbutton, extensivo a date/time/color-field. F-1 llega a
escribir la declaracion del morfo literal.
El min/max ya existe por segmento (`aria-valuemin`/`aria-valuemax`); falta la
tecla en el plan de teclado de los tres morfos y el enrutado en los varios
`onkeydown` de cada provider. La auditoria lo dimensiona como pass de familia.
D9 — los dos documentos de chronos discrepaban
-----------------------------------------------
El README de soma decia que el pack «ships rules» para `handle-drag` y
`handle-resize`; el SPEC, que se retiraron el 2026-08-07 por codigo muerto. El
SPEC tenia razon — el pack solo lleva los tres `commit-*`. README al dia.
Lo que queda es la decision que el SPEC ya deja preparada: o el provider los
emite al traducir el drag-drop reutilizado a comandos —y entonces el gesto suena
por REPETICION, `step` por emision, como el resto de arrastres— o las dos
DECLARACIONES se retiran del morfo.
Verificado: `docs:check` 0/623, `check` 70 errores (linea base), 199/199 en
date-picker + picker-shell + morfo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️ Los dos documentos de chronos discrepaban: el README de soma decía que el pack
«ships rules» para ambos, y el SPEC que **se retiraron el 2026-08-07** por código
muerto. El SPEC tenía razón (el pack sólo lleva los tres `commit-*` ); el README
quedó al día el 2026-08-12.
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**ARREGLADO 2026-08-12 — se cablean.** `handle` pregunta *«¿estoy manipulando
directamente este objeto?»*, y una familia que no responde su propia pregunta ha
fallado en lo único para lo que existe ([CANON §2](../CANON.md)). Chronos es el
componente más manipulable del catálogo: hablaba el suelte (`commit-move`) y el
acarreo entero estaba mudo. El *handle invisible* .
No se autora nada: `handle` ya declara `sounds: { default: 'step' }` y los dos
canales en el mapa, así que el ritmo ES el sonido — un diente por emisión, a la
cadencia del gesto. Por eso las dos reglas del pack se retiraron el 2026-08-07
como código muerto: sobraba la regla, no el evento.
Estrangulado a ~14 Hz como slider y splitter, y **anclado** : los destinos son
`event-chip` y `event-resize-handle` , partes REPETIDAS, así que es una aplicación
directa de la ley de `e5811e422` (una ocurrencia con un sujeto entre muchos se
ancla). Chronos ya tenía el mecanismo en `emitOnChip` .
**Dónde el acarreo NO es de chronos.** Arrastrar un chip con el PUNTERO pasa por
el `DragDrop` compuesto, que posee ese bucle y lo expresa en `handle-pick` y
`handle-drop` — declara tres eventos y emite tres, sin acarreo continuo (CANON
regla 6: la evaluación se concentra en el drop). Añadir una tercera narración
encima serían dos componentes contando el mismo gesto. Así que `handle-drag` es
aquí el acarreo de TECLADO y `handle-resize` cubre las dos vías.
Medido: el arrastre del tirador con puntero da **6 `handle-resize` en 6 pasos** ,
todos sobre `event-resize-handle` . El `handle-drag` sella `event-chip` a la
primera flecha y no más — no por el cableado, sino por **D14** .
docs(soma,process): D5, D6 y D9 medidos — y cuatro afirmaciones del ledger eran falsas
Al ir a arreglarlos, tres de las cinco filas resultaron decir cosas que no se
sostienen. Las corrijo con la evidencia delante, porque una fila que miente es
peor que una fila vacia.
D5 — la doc ya estaba adjudicada; no se propago
-----------------------------------------------
La fila decia dos cosas falsas. (1) «modal promete bloquear Escape»: esa promesa
ya se habia adjudicado AL REVES el 2026-08-11 en tres pickers, con razon escrita
en `time-picker/types.ts:42` — Escape descarta en AMBOS modos porque el morfo
declara el patron APG `combobox`, y el framework bloquea Escape en exactamente un
sitio, `alertdialog`; tragarselo dejaria a un usuario de teclado sin salida salvo
que el consumidor recordara componer un Cancel. La correccion no llego al handle
compartido ni a date-picker / date-range-picker. Propagada aqui. (2) «no hay
buffer»: si lo hay — `valueOnOpen` se captura en la arista de apertura y
`cancel()` lo restaura.
Lo que SI es defecto, medido en navegador: en `mode='modal'` el popover no
autocierra al elegir, pero Escape cierra Y SE QUEDA la edicion (05/20 → 05/10).
Es un tercer camino de salida que se comporta como Save, y el contrato del modo
solo tiene dos. La causa esta a la vista: `PickerCloseCause` es
`'save' | 'cancel' | 'dismiss'` y **`'dismiss'` no lo produce nadie** — misma
clase que D1/D3/D4. Escape cierra por la via del Popover sin pasar por
`closeWith`, asi que ni sella causa ni revierte; ningun picker cablea
`escapeKeydownBehavior`, luego los cinco se comportan igual.
Queda decision: que Escape produzca `dismiss` y que `dismiss` revierta en modal
(no en inline). Se deduce de los dos modos documentados, pero cambia el
comportamiento de cinco componentes, asi que no lo improviso.
D6 — no es una decision sin tomar, es una spec sin construir
-------------------------------------------------------------
La fila decia «Home/End/PageUp/PageDown documentados en 4 sitios» y «las tres
paginas se contradicen sobre que harian». Ninguna de las dos: PageUp/PageDown no
aparecen en ninguna parte, y las tres auditorias COINCIDEN — `Home` → `set-min`,
`End` → `set-max`, APG spinbutton, extensivo a date/time/color-field. F-1 llega a
escribir la declaracion del morfo literal.
El min/max ya existe por segmento (`aria-valuemin`/`aria-valuemax`); falta la
tecla en el plan de teclado de los tres morfos y el enrutado en los varios
`onkeydown` de cada provider. La auditoria lo dimensiona como pass de familia.
D9 — los dos documentos de chronos discrepaban
-----------------------------------------------
El README de soma decia que el pack «ships rules» para `handle-drag` y
`handle-resize`; el SPEC, que se retiraron el 2026-08-07 por codigo muerto. El
SPEC tenia razon — el pack solo lleva los tres `commit-*`. README al dia.
Lo que queda es la decision que el SPEC ya deja preparada: o el provider los
emite al traducir el drag-drop reutilizado a comandos —y entonces el gesto suena
por REPETICION, `step` por emision, como el resto de arrastres— o las dos
DECLARACIONES se retiran del morfo.
Verificado: `docs:check` 0/623, `check` 70 errores (linea base), 199/199 en
date-picker + picker-shell + morfo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(process): los nueve defectos abiertos salen de mi memoria y entran en el repo
Los defectos que dejo el barrido docs-codigo del 2026-08-11 vivian solo en la
memoria de la sesion que los encontro. Eso es una superficie de recuerdo del
agente, no del proyecto: un handoff que no se carga los pierde, y son la unica
huella de nueve averias que se decidio NO tocar. Ahora tienen casa, con la forma
del ledger de blocks: escritura por `id`, un ARREGLADO lleva su sha, y una fila
de gap no se borra nunca.
D1 · D2 · D3 · D4 arreglados (`f4e414e2e`, `6f42eebfe`). D5…D9 confirmados y
abiertos. D10 es nuevo y nace de un error mio de metodo.
D10 — la migracion a medias
---------------------------
El 2026-08-06 `dragSignalOverrides` paso a nombrar `step` (el gesto suena por
REPETICION) y eso dejo a los tres resolvers de gesto sin un solo llamador. Yo
lei «cero llamadores» y propuse retirarlos. Cinco documentos dicen lo contrario,
y dos de ellos estaban en la salida de mi propio grep sin que los abriera:
`PLAN-sound-engine.md` §4 los pone en la columna «sema conserva» de la LINEA DE
CORTE con `$sound`, y `PLAN-audio-player.md` D-AP.7 los da por medidos con un
check verde. No es codigo muerto: es una migracion que no se adjudico.
De ahi la regla 4 del ledger. «No lo referencia nadie» es una observacion, nunca
un veredicto — la misma leccion que la fila de «Gaps» que dos agentes borraron.
Verificado antes de escribir cada fila, no copiado de la memoria: D2 esta
arreglado y mi registro lo daba por abierto; y la primera lectura de D9 decia
que los tres `commit-*` de chronos tampoco se disparan — falso, se despachan por
variable en `emitOnChip`, invisibles a un grep de `trigger('literal')`.
Y el handoff del plan
---------------------
`PLAN-event-name-normalization.md` no tenia. El eje esta cerrado (256/256 con
prefijo, guard visto fallar, barrido sobre los 172 morfos), pero quedan dos
decisiones tuyas bloqueando trabajo — D10 y el `present-rise` anclado al trigger
— mas tres cosas que el eje destapo sin cerrar: el `grid` repetido con
`numberOfMonths=2`, el nombre `handle-drag-progress`, y los cinco defectos.
`docs:check` 0 errores sobre 623 docs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### D10 · Los 3 resolvers de gesto: migración a medias — `CONFIRMADO` · P1
El 2026-08-06 se reescribió `dragSignalOverrides` (slider y splitter) a
`sound: 'step'` — el gesto pasa a sonar por REPETICIÓN — y eso dejó
`resolveHandleDragSound` / `resolveSliderDragSound` / `resolveSplitterDragSound`
sin un solo llamador. **No se adjudicó ninguno de los cinco sitios que los
describen como vigentes:**
| Sitio | Qué afirma |
| --- | --- |
| [`splitter-provider.svelte.ts:435` ](../../src/uix/soma/components/splitter/splitter-provider.svelte.ts ) | «Pitch/centroid/gain come from… `resolveSplitterDragSound` » — y `dragSignalOverrides` , 30 líneas más abajo **en el mismo fichero** , dice que eso se sustituyó |
| [`sema/components/splitter.ts:15` ](../../src/uix/sema/components/splitter.ts ) | medio cierto: soma **sí** calcula overrides por emisión, pero no por ese resolver, y «la curva dinámica sobrevive» ya sólo vale para el háptico |
| [`PLAN-sound-engine.md:95` ](./PLAN-sound-engine.md ) | §4, los tres en la columna ** «sema conserva»** de la LÍNEA DE CORTE |
| [`PLAN-audio-player.md:367` ](./PLAN-audio-player.md ) | D-AP.7, ** ✅ CONFIRMADO**: el slider adjunta el resolver en cada `handle-drag` |
| [`AUDIT-sema-2026-08-05.md` ](./AUDIT-sema-2026-08-05.md ) hallazgo 7 | la regla del pack del slider está muda **a propósito** porque las primitivas vienen del resolver — razón hoy sin base |
El slider **no** arrastra el comentario rancio: el suyo describe bien la
sustitución. La contradicción interna es sólo del splitter.
**Decisión abierta del autor:** ¿se retiran los resolvers de gesto, o se
recablean? La tabla de corte de `PLAN-sound-engine.md` §4 hay que actualizarla
en los dos casos. Nada se toca hasta entonces: reescribir los comentarios para
decir «se sustituyó» contesta la pregunta y borra la huella (regla 3).
revert(sema): la libreria de sonido vuelve byte a byte — la retirada no era de esta sesion
Revierte la mitad D10 de `5571f3bf7` por orden del autor. La sesion era
normalizar nombres de evento; la retirada de los 3 resolvers de gesto nacio de
perseguir un homonimo que cree yo mismo al renombrar `SoundDirection` →
`SoundContour` sin mirar el namespace de destino, y se ejecuto sin leer primero
el handoff vivo del eje (`CONTINUE-sound-engine.md` — la memoria del proyecto lo
marca PRIMERO) ni `PLAN-audio-player-v2.md` (gate firmado), que ni siquiera
sabia que existia. La verificacion posterior salio limpia — ninguno de los seis
documentos no leidos nombra los resolvers — pero limpia por suerte no es limpia
por metodo.
Restaurados byte a byte a su estado anterior al borrado (diff contra
`5571f3bf7^` = 0 lineas):
- `sema/sounds.ts` (160 lineas otra vez: resolvers, `DragSoundParams`,
`SoundContour`, `clamp`, `lerp`) · `sounds.test.ts` (los 2 tests de arrastre)
· `exports.ts` (los 5 re-exports)
- las 4 prosas que se habian reescrito describiendo el borrado:
`sema/types.ts`, `sema/components/splitter.ts`,
`soma/splitter-provider.svelte.ts`, `arts/motion/types.ts`
- `scripts/docs-vocabularies.ts` + `docs/canon/vocabularies.md` regenerado
- la nota fechada que se añadio al §4 de `PLAN-sound-engine.md`
Lo que NO se revierte, porque no depende de la libreria: D9 (el acarreo de
chronos) y el guard de eventos inertes — verificados en verde tras el revert.
El ledger deja constancia: D10 pasa a CONFIRMADO (retirada REVERTIDA), con el
analisis conservado como evidencia PARA la sesion propia del eje de sonido —
`git log -S` (un solo commit en la vida de los resolvers),
`book-deviations.md` dandolos por borrados el 2026-08-06, los dos planes
cerrado/rechazado — y la regla explicita: sounds.ts no se toca sin una sesion
que empiece por su handoff.
Verificado: sema 300/300 (con los tests restaurados dentro), guard de eventos
inertes en verde, `check` 70 errores (linea base), `docs:check` 0/623.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**RETIRADA EJECUTADA Y REVERTIDA el mismo día (2026-08-12).** El borrado se hizo
en `5571f3bf7` y el autor lo revirtió en el acto, con razón: **la sesión era de
normalizar nombres de evento, no de modificar la librería de sonido**, y la
retirada se ejecutó sin leer primero el handoff vivo del eje
([`CONTINUE-sound-engine.md`](./CONTINUE-sound-engine.md) — la memoria del
proyecto lo marca «PRIMERO») ni `PLAN-audio-player-v2.md` (gate firmado), que ni
siquiera se sabía que existía. La verificación posterior salió limpia — ninguno
de los seis documentos no leídos nombra los resolvers — pero salió limpia por
suerte, no por método. `sounds.ts` está restaurado byte a byte; **no se toca sin
una sesión propia del eje de sonido, que empiece por su handoff.**
docs(process): la ronda de decisiones queda firmada — cinco disposiciones, dos corregidas al re-analizar
D10 SE RETIRA (lo ejecuta el eje de sonido, su handoff PRIMERO), y el
re-analisis añade un SEXTO sitio a adjudicar: sema.md §per-emit payload aun
describe pitch/gain/contour cuando soma adjunta hoy sound:'step' + curva
haptica (dragSignalOverrides del slider y del knob, con el trade-off del
2026-08-06 citado en su comentario).
fixedWeeks: alinear a false a secas era la opcion debil — las filas del mes
son de altura FIJA (grid-auto-rows, chronos.css:278) y un false pelado cambia
la semana fantasma por saltos de altura al navegar. Firmado: crecer las filas
(modelo Google), con false incluido; es arreglo de RECETA, no un flip de flag.
Chip bloqueado: via (b), y la letra pequeña va INCLUIDA — el morfo de
drag-drop YA declara data-disabled (declaracion sin emisor) y el cursor vive
en drag-drop.css; pero el chip fusiona tres morfos en un elemento clicable,
asi que la regla de archetype item se anula en su receta y aria-disabled NO
aterriza en el elemento fusionado.
mode/scope: SE RETIRAN, con el barrido de la regla 4 hecho de verdad: 0 hits
en docs/, 0 lectores del compilado, 4 ficheros de alcance. SemaCause queda
como pregunta hermana (mas muerto aun: ni atraviesa morfo).
present-rise: medir primero (lo esperable es la receta F4, pero decide la
medida). handle-drag-progress: revisar contra CANON, no renombrar — el matiz
es legal y puede ser deliberado.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**DECISIÓN FIRMADA (2026-08-12): SE RETIRAN.** La ejecuta la sesión del eje de
sonido — la condición procedimental de arriba queda intacta (su handoff
PRIMERO). Con la retirada: actualizar la tabla de corte de
`PLAN-sound-engine.md` §4, adjudicar los cinco sitios de la tabla, y un
**SEXTO** que el re-análisis del 2026-08-12 destapó:
`docs/architecture/sema.md` §«The per-emit payload owns the primitives» aún
describe el payload sonoro de la era resolver («pitch / gain / contour derived
from pointer position and velocity»), cuando lo que soma adjunta hoy es
`sound: 'step'` + curva háptica (`dragSignalOverrides` en
`slider-provider.svelte.ts:233` y `knob-provider.svelte.ts:242` , con el
trade-off del 2026-08-06 citado en el propio comentario). El homónimo
`SoundContour` se disuelve con ellos — nada que renombrar.
revert(sema): la libreria de sonido vuelve byte a byte — la retirada no era de esta sesion
Revierte la mitad D10 de `5571f3bf7` por orden del autor. La sesion era
normalizar nombres de evento; la retirada de los 3 resolvers de gesto nacio de
perseguir un homonimo que cree yo mismo al renombrar `SoundDirection` →
`SoundContour` sin mirar el namespace de destino, y se ejecuto sin leer primero
el handoff vivo del eje (`CONTINUE-sound-engine.md` — la memoria del proyecto lo
marca PRIMERO) ni `PLAN-audio-player-v2.md` (gate firmado), que ni siquiera
sabia que existia. La verificacion posterior salio limpia — ninguno de los seis
documentos no leidos nombra los resolvers — pero limpia por suerte no es limpia
por metodo.
Restaurados byte a byte a su estado anterior al borrado (diff contra
`5571f3bf7^` = 0 lineas):
- `sema/sounds.ts` (160 lineas otra vez: resolvers, `DragSoundParams`,
`SoundContour`, `clamp`, `lerp`) · `sounds.test.ts` (los 2 tests de arrastre)
· `exports.ts` (los 5 re-exports)
- las 4 prosas que se habian reescrito describiendo el borrado:
`sema/types.ts`, `sema/components/splitter.ts`,
`soma/splitter-provider.svelte.ts`, `arts/motion/types.ts`
- `scripts/docs-vocabularies.ts` + `docs/canon/vocabularies.md` regenerado
- la nota fechada que se añadio al §4 de `PLAN-sound-engine.md`
Lo que NO se revierte, porque no depende de la libreria: D9 (el acarreo de
chronos) y el guard de eventos inertes — verificados en verde tras el revert.
El ledger deja constancia: D10 pasa a CONFIRMADO (retirada REVERTIDA), con el
analisis conservado como evidencia PARA la sesion propia del eje de sonido —
`git log -S` (un solo commit en la vida de los resolvers),
`book-deviations.md` dandolos por borrados el 2026-08-06, los dos planes
cerrado/rechazado — y la regla explicita: sounds.ts no se toca sin una sesion
que empiece por su handoff.
Verificado: sema 300/300 (con los tests restaurados dentro), guard de eventos
inertes en verde, `check` 70 errores (linea base), `docs:check` 0/623.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
El análisis de abajo se conserva porque es evidencia válida PARA esa sesión:
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
- [`PLAN-sound-engine.md` ](./PLAN-sound-engine.md ) está **CERRADO** (2026-07-30) y
su columna «sema conserva» miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe,
`SOUND_TUNINGS` se retiró el 2026-08-06 (con guard que lo mantiene retirado),
el sonido salió de la cascada y «qué firma para qué familia × intent» lo
sustituyó la ley del nombre. Es un inventario, no un mandato.
- [`PLAN-audio-player.md` ](./PLAN-audio-player.md ) está ** ⛔ GATE RECHAZADO —
SUSPENDIDO**, y su cabecera dice *«nada de lo de abajo se implementa»* . Su ✅
CONFIRMADO es una medición del terreno del 2026-07-31, cierta entonces.
- La fuente que gobierna no es un plan de proceso sino
[`book-deviations.md` ](../decisions/book-deviations.md ), de **decisiones** , que
el 2026-08-06 escribió en pasado: *«un gesto continuo suena por REPETICIÓN … y
**los tres resolvers se borraron con él** »*. `git log -S` sobre `sounds.ts`
devuelve **un solo commit en toda su vida** (mayo): nunca se borraron. El
registro dio por ejecutado lo que no se ejecutó.
revert(sema): la libreria de sonido vuelve byte a byte — la retirada no era de esta sesion
Revierte la mitad D10 de `5571f3bf7` por orden del autor. La sesion era
normalizar nombres de evento; la retirada de los 3 resolvers de gesto nacio de
perseguir un homonimo que cree yo mismo al renombrar `SoundDirection` →
`SoundContour` sin mirar el namespace de destino, y se ejecuto sin leer primero
el handoff vivo del eje (`CONTINUE-sound-engine.md` — la memoria del proyecto lo
marca PRIMERO) ni `PLAN-audio-player-v2.md` (gate firmado), que ni siquiera
sabia que existia. La verificacion posterior salio limpia — ninguno de los seis
documentos no leidos nombra los resolvers — pero limpia por suerte no es limpia
por metodo.
Restaurados byte a byte a su estado anterior al borrado (diff contra
`5571f3bf7^` = 0 lineas):
- `sema/sounds.ts` (160 lineas otra vez: resolvers, `DragSoundParams`,
`SoundContour`, `clamp`, `lerp`) · `sounds.test.ts` (los 2 tests de arrastre)
· `exports.ts` (los 5 re-exports)
- las 4 prosas que se habian reescrito describiendo el borrado:
`sema/types.ts`, `sema/components/splitter.ts`,
`soma/splitter-provider.svelte.ts`, `arts/motion/types.ts`
- `scripts/docs-vocabularies.ts` + `docs/canon/vocabularies.md` regenerado
- la nota fechada que se añadio al §4 de `PLAN-sound-engine.md`
Lo que NO se revierte, porque no depende de la libreria: D9 (el acarreo de
chronos) y el guard de eventos inertes — verificados en verde tras el revert.
El ledger deja constancia: D10 pasa a CONFIRMADO (retirada REVERTIDA), con el
analisis conservado como evidencia PARA la sesion propia del eje de sonido —
`git log -S` (un solo commit en la vida de los resolvers),
`book-deviations.md` dandolos por borrados el 2026-08-06, los dos planes
cerrado/rechazado — y la regla explicita: sounds.ts no se toca sin una sesion
que empiece por su handoff.
Verificado: sema 300/300 (con los tests restaurados dentro), guard de eventos
inertes en verde, `check` 70 errores (linea base), `docs:check` 0/623.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
Alcance medido de la retirada (por si esa sesión la retoma): los tres resolvers,
`DragSoundParams` , el `SoundContour` de sema, sus 5 re-exports, 2 tests que sólo
se probaban a sí mismos y los helpers `clamp` /`lerp` huérfanos — 81 líneas, 7
símbolos; el registro (`SEMA_SOUND_VOICE`, `sample` , `resolveSoundDefinition` …)
no se toca. La nota fechada que se añadió al §4 del plan cerrado también se
revirtió con el resto.
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
**Cae con ellos** el homónimo `SoundContour` : el 2026-08-11 se renombró
docs(process): los nueve defectos abiertos salen de mi memoria y entran en el repo
Los defectos que dejo el barrido docs-codigo del 2026-08-11 vivian solo en la
memoria de la sesion que los encontro. Eso es una superficie de recuerdo del
agente, no del proyecto: un handoff que no se carga los pierde, y son la unica
huella de nueve averias que se decidio NO tocar. Ahora tienen casa, con la forma
del ledger de blocks: escritura por `id`, un ARREGLADO lleva su sha, y una fila
de gap no se borra nunca.
D1 · D2 · D3 · D4 arreglados (`f4e414e2e`, `6f42eebfe`). D5…D9 confirmados y
abiertos. D10 es nuevo y nace de un error mio de metodo.
D10 — la migracion a medias
---------------------------
El 2026-08-06 `dragSignalOverrides` paso a nombrar `step` (el gesto suena por
REPETICION) y eso dejo a los tres resolvers de gesto sin un solo llamador. Yo
lei «cero llamadores» y propuse retirarlos. Cinco documentos dicen lo contrario,
y dos de ellos estaban en la salida de mi propio grep sin que los abriera:
`PLAN-sound-engine.md` §4 los pone en la columna «sema conserva» de la LINEA DE
CORTE con `$sound`, y `PLAN-audio-player.md` D-AP.7 los da por medidos con un
check verde. No es codigo muerto: es una migracion que no se adjudico.
De ahi la regla 4 del ledger. «No lo referencia nadie» es una observacion, nunca
un veredicto — la misma leccion que la fila de «Gaps» que dos agentes borraron.
Verificado antes de escribir cada fila, no copiado de la memoria: D2 esta
arreglado y mi registro lo daba por abierto; y la primera lectura de D9 decia
que los tres `commit-*` de chronos tampoco se disparan — falso, se despachan por
variable en `emitOnChip`, invisibles a un grep de `trigger('literal')`.
Y el handoff del plan
---------------------
`PLAN-event-name-normalization.md` no tenia. El eje esta cerrado (256/256 con
prefijo, guard visto fallar, barrido sobre los 172 morfos), pero quedan dos
decisiones tuyas bloqueando trabajo — D10 y el `present-rise` anclado al trigger
— mas tres cosas que el eje destapo sin cerrar: el `grid` repetido con
`numberOfMonths=2`, el nombre `handle-drag-progress`, y los cinco defectos.
`docs:check` 0 errores sobre 623 docs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
`SoundDirection` → `SoundContour` en
[`sema/sounds.ts:34` ](../../src/uix/sema/sounds.ts ) sin mirar que
[`arts/sound/types.ts:44` ](../../src/arts/sound/types.ts ) ya exportaba ese nombre
con cinco valores en vez de dos. Cinco sitios a tocar; el nombre no puede volver
a `SoundDirection` (el rename se hizo porque tres cosas distintas se llamaban
`direction` ). Propuesto: `GestureContour` , que es la palabra que usa la propia
tabla de corte («los 3 resolvedores de **gesto** »). Si los resolvers se retiran,
el tipo se va con ellos y no hay nada que renombrar.
⚠️ Esta fila nació de un error de método: se propuso **retirar** los tres
resolvers por «cero llamadores», con dos de esos cinco sitios en la salida del
propio grep y sin abrirlos. «No lo referencia nadie» es una observación, nunca
un veredicto (regla 4).
---
## Cola menor · comentarios fósiles
~11 comentarios en código que citan nombres muertos, sin defecto de
comportamiento detrás: color-picker, combobox, nav-tree («stays sema-free» con
dos eventos `emerge` declarados) y aura, que cita el patrón
`close-save` /`close-cancel` que Dialog ya no usa. Sin `id` propio: se limpian
cuando se toque el fichero por otra razón.
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
### D13 · Siete eventos declarados que nadie emite — `CONFIRMADO` · P1
Salió al cerrar D9: es la CLASE, y la clase ya produjo D1 (AlertDialog mudo), D3
(`commit-reset` en cinco pickers), D4 (ColorPicker) y el propio D9.
`book-deviations.md` tipifica el defecto hermano —declarar una firma de canal que
la activación no incluye— como *«mecánicamente comprobable y merece guard»* . Esto
es la misma forma un piso más arriba.
Hay guard desde el 2026-08-12 (`contracts.test.ts`, «guards declared events
docs(process): dos correcciones de registro — mi censo repetia uno que ya existia, y peor
D13 mezclaba tres clases en un saco
------------------------------------
`CONTINUE-sema-audit.md` §3.1 YA habia medido esto — «eventos huerfanos: 14 de
249 en 104 morfos con soma» — y, sobre todo, ya los habia CLASIFICADO. Verificado
componente a componente, su clasificacion es la correcta y la mia era gruesa:
- **contrato muerto** — `tooltip` ×3. El unico defecto de la clase D1/D3/D4, y el
unico accionable. Cero `trigger(` en todo su directorio soma.
- **punto de extension documentado** — `virtual-list` / `virtual-grid`
`handle-scroll*`. Los emite la APP; el README los diseca en prosa con su
doctrina. Lo que falta no es cableado: es que el morfo no tiene forma de
DECLARARLO (la auditoria propone `emission: 'app'`).
- **verbo delegado** — `gradient-picker.commit-reset` (S-14, 1 de 6 identicos).
NO se arregla como D3: `GradientPickerProvider` no tiene `clear()` — su
docblock dice que open/commit/cancel/clear viven en el `PickerProvider`
generico compuesto y que esta clase «solo posee el runtime del morfo». No hay
donde enganchar.
Lo que el guard añade sobre aquel censo no es el hallazgo: es que deja de ser una
medicion de una vez y bloquea la regresion. Eso lo demostro D9 al deshacerlo.
`CONTINUE-perceptual-surface.md` afirmaba algo falso sobre chronos
-------------------------------------------------------------------
Su fila de la migracion de `targetOverride` dice «sus chips tampoco REGISTRAN —
plain trigger fallaria igual». No se sostiene, y lo se porque acabo de medirlo
cableando el acarreo (D9): `partInstance('event-chip', el)` RESUELVE, el sello de
`handle-drag` aterriza en el `event-chip`, y el arrastre del tirador da 6
`handle-resize` sobre `event-resize-handle`. Los chips registran.
La otra mitad de la fila (los botones del editor no son partes) queda, y se le
añade lo que dice la auditoria de sema: la exclusion de escritura de chronos se
levanto el 2026-08-10.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
against the ones a provider actually emits»), con los siete en `INERT_EVENT_DEBT` .
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
docs(process): dos correcciones de registro — mi censo repetia uno que ya existia, y peor
D13 mezclaba tres clases en un saco
------------------------------------
`CONTINUE-sema-audit.md` §3.1 YA habia medido esto — «eventos huerfanos: 14 de
249 en 104 morfos con soma» — y, sobre todo, ya los habia CLASIFICADO. Verificado
componente a componente, su clasificacion es la correcta y la mia era gruesa:
- **contrato muerto** — `tooltip` ×3. El unico defecto de la clase D1/D3/D4, y el
unico accionable. Cero `trigger(` en todo su directorio soma.
- **punto de extension documentado** — `virtual-list` / `virtual-grid`
`handle-scroll*`. Los emite la APP; el README los diseca en prosa con su
doctrina. Lo que falta no es cableado: es que el morfo no tiene forma de
DECLARARLO (la auditoria propone `emission: 'app'`).
- **verbo delegado** — `gradient-picker.commit-reset` (S-14, 1 de 6 identicos).
NO se arregla como D3: `GradientPickerProvider` no tiene `clear()` — su
docblock dice que open/commit/cancel/clear viven en el `PickerProvider`
generico compuesto y que esta clase «solo posee el runtime del morfo». No hay
donde enganchar.
Lo que el guard añade sobre aquel censo no es el hallazgo: es que deja de ser una
medicion de una vez y bloquea la regresion. Eso lo demostro D9 al deshacerlo.
`CONTINUE-perceptual-surface.md` afirmaba algo falso sobre chronos
-------------------------------------------------------------------
Su fila de la migracion de `targetOverride` dice «sus chips tampoco REGISTRAN —
plain trigger fallaria igual». No se sostiene, y lo se porque acabo de medirlo
cableando el acarreo (D9): `partInstance('event-chip', el)` RESUELVE, el sello de
`handle-drag` aterriza en el `event-chip`, y el arrastre del tirador da 6
`handle-resize` sobre `event-resize-handle`. Los chips registran.
La otra mitad de la fila (los botones del editor no son partes) queda, y se le
añade lo que dice la auditoria de sema: la exclusion de escritura de chronos se
levanto el 2026-08-10.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️ **Corrección 2026-08-12 (misma jornada): esto NO es «la cola», y el censo no
es nuevo.** [`CONTINUE-sema-audit.md` ](./CONTINUE-sema-audit.md ) §3.1 ya lo había
medido — *«eventos huérfanos: 14 de 249 en 104 morfos con soma»* — y, sobre todo,
ya los había **clasificado en tres clases que yo metí en un saco** . Verificado
componente a componente, la clasificación de aquella auditoría es la correcta:
| Clase | Cuáles | Quién la cierra |
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| --- | --- | --- |
docs(process): dos correcciones de registro — mi censo repetia uno que ya existia, y peor
D13 mezclaba tres clases en un saco
------------------------------------
`CONTINUE-sema-audit.md` §3.1 YA habia medido esto — «eventos huerfanos: 14 de
249 en 104 morfos con soma» — y, sobre todo, ya los habia CLASIFICADO. Verificado
componente a componente, su clasificacion es la correcta y la mia era gruesa:
- **contrato muerto** — `tooltip` ×3. El unico defecto de la clase D1/D3/D4, y el
unico accionable. Cero `trigger(` en todo su directorio soma.
- **punto de extension documentado** — `virtual-list` / `virtual-grid`
`handle-scroll*`. Los emite la APP; el README los diseca en prosa con su
doctrina. Lo que falta no es cableado: es que el morfo no tiene forma de
DECLARARLO (la auditoria propone `emission: 'app'`).
- **verbo delegado** — `gradient-picker.commit-reset` (S-14, 1 de 6 identicos).
NO se arregla como D3: `GradientPickerProvider` no tiene `clear()` — su
docblock dice que open/commit/cancel/clear viven en el `PickerProvider`
generico compuesto y que esta clase «solo posee el runtime del morfo». No hay
donde enganchar.
Lo que el guard añade sobre aquel censo no es el hallazgo: es que deja de ser una
medicion de una vez y bloquea la regresion. Eso lo demostro D9 al deshacerlo.
`CONTINUE-perceptual-surface.md` afirmaba algo falso sobre chronos
-------------------------------------------------------------------
Su fila de la migracion de `targetOverride` dice «sus chips tampoco REGISTRAN —
plain trigger fallaria igual». No se sostiene, y lo se porque acabo de medirlo
cableando el acarreo (D9): `partInstance('event-chip', el)` RESUELVE, el sello de
`handle-drag` aterriza en el `event-chip`, y el arrastre del tirador da 6
`handle-resize` sobre `event-resize-handle`. Los chips registran.
La otra mitad de la fila (los botones del editor no son partes) queda, y se le
añade lo que dice la auditoria de sema: la exclusion de escritura de chronos se
levanto el 2026-08-10.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
| **Contrato muerto** — el único defecto de la clase D1/D3/D4 | `tooltip` × 3 | libre; es el que queda accionable aquí |
| **Punto de extensión documentado** — lo emite la APP, no el componente | `virtual-list.handle-scroll` · `virtual-grid.handle-scroll-row/column` | el morfo **no tiene forma de declararlo** : la auditoría propone un `emission: 'app'` . Es vocabulario de morfo, no cableado |
| **Verbo delegado** — la transacción vive en un componente compuesto | `gradient-picker.commit-reset` (S-14, **1 de 6 casos idénticos** ) | `CONTINUE-sema-audit.md` . No se arregla como D3: `GradientPickerProvider` **no tiene `clear()`** — su docblock dice que open/commit/cancel/clear viven en el `PickerProvider` genérico compuesto, y esta clase «sólo posee el runtime del morfo». No hay dónde enganchar; o se retira la declaración, o el externo re-emite |
Lo que este guard añade sobre aquel censo no es el hallazgo, es que **deja de ser
una medición de una vez**: bloquea la regresión. Eso lo demostró D9 al deshacerlo.
**El accionable: `tooltip` , 3 de 3.** Cero llamadas a `trigger(` en todo
`soma/components/tooltip` — abre y cierra **sin firma alguna** , en uno de los
componentes más ubicuos del catálogo. `CONTINUE-sema-audit.md` lo marca como
«HALLAZGO NUEVO, no está entre los 44» y lo tipifica como *contrato muerto* : o el
provider emite los tres, o las tres declaraciones se retiran. La pregunta previa
es cuál de las dos, porque el tooltip **compone Popover** y podría ser otro
`expression: 'delegated'` como los pickers — eso hay que medirlo antes de tocar,
no suponerlo.
feat(soma,sema): el acarreo de chronos habla, los 3 resolvers se van, y un guard cierra la clase
D10 · no era una decision abierta: era una firmada sin ejecutar
---------------------------------------------------------------
Mi correccion de mi propia propuesta estaba sobre-corregida: lei la linea 95 de
un plan y la 367 de otro, no los documentos.
- `PLAN-sound-engine.md` esta CERRADO (2026-07-30) y su columna «sema conserva»
miente en 4 de 5 celdas: `SOUND_LIBRARY` no existe, `SOUND_TUNINGS` se retiro
el 2026-08-06 (con guard que lo mantiene retirado), el sonido salio de la
cascada, y «que firma para que familia × intent» lo sustituyo la ley del
nombre. Es un inventario del 30 de julio, no un mandato.
- `PLAN-audio-player.md` esta ⛔ GATE RECHAZADO — SUSPENDIDO, y su cabecera dice
«nada de lo de abajo se implementa».
- La fuente que gobierna es `docs/decisions/book-deviations.md`, de DECISIONES,
que el 2026-08-06 escribio en pasado: «un gesto continuo suena por REPETICION …
y los tres resolvers se borraron con el». `git log -S` sobre `sounds.ts`
devuelve UN SOLO COMMIT en toda su vida (mayo): nunca se borraron. El registro
dio por ejecutado lo que no se ejecuto.
Retirados los tres, `DragSoundParams`, el `SoundContour` de sema, sus exports,
los dos tests que solo se probaban a si mismos y los helpers `clamp`/`lerp` que
quedaron huerfanos: `sounds.ts` pasa de 160 a 79 lineas. Con ellos cae el
homonimo `SoundContour` — el nombre queda para el art, sin renombrar nada. El
plan cerrado no se reescribe, pero su §4 lleva ya una nota fechada porque me
engaño a mi.
D9 · el acarreo habla
---------------------
`handle` pregunta «¿estoy manipulando directamente este objeto?», y una familia
que no responde su propia pregunta ha fallado en lo unico para lo que existe
(CANON §2). Chronos es el componente mas manipulable del catalogo y hablaba solo
el suelte: el acarreo entero estaba mudo. El *handle invisible*.
No se autora nada — `handle` ya declara `sounds: { default: 'step' }` y los dos
canales, asi que el RITMO es el sonido. Estrangulado a ~14 Hz como slider y
splitter, y ANCLADO: los destinos son partes repetidas, asi que es aplicacion
directa de la ley de `e5811e422`.
Donde el acarreo NO es de chronos: arrastrar un chip con puntero pasa por el
`DragDrop` compuesto, que declara tres eventos y emite tres, sin acarreo continuo
(CANON regla 6). Dos componentes narrando un gesto seria peor. Asi que
`handle-drag` es el acarreo de TECLADO y `handle-resize` cubre las dos vias.
Medido: el arrastre del tirador con puntero da 6 `handle-resize` en 6 pasos,
todos sobre `event-resize-handle`.
El guard, y dos hallazgos que salieron de medirlo
--------------------------------------------------
`book-deviations.md` tipifica el defecto hermano como «mecanicamente comprobable
y merece guard». Este es la misma forma un piso arriba, y es la clase que produjo
D1, D3, D4 y D9. La prueba NO es `trigger('literal')` — chronos despacha por
variable y eso me dio dos falsos negativos durante la auditoria; se comprueba que
el nombre aparezca como literal donde el provider alcance: su directorio soma mas
las librerias compartidas (sin `$libs/selection` en el ambito, combobox y select
se leen como inertes y no lo son).
D13 — quedan 7 eventos inertes en 4 componentes, enumerados en
`INERT_EVENT_DEBT`, que no son exenciones sino la cola. El peor: `tooltip` 3 de
3, cero `trigger(` en todo su directorio, abriendo y cerrando sin firma alguna.
D14 — midiendo D9 salio un defecto anterior: `restoreChipFocus` reenfoca en un
`queueMicrotask` que corre ANTES de que Svelte reponga el nodo, asi que enfoca la
nada y el foco cae al `<body>`. La segunda flecha ya no llega al manejador y el
Escape tampoco: la interaccion que el propio componente anuncia («Grabbed. Arrow
keys move, Enter drops, Escape cancels») muere al primer paso. No lo toco aqui —
es de foco, no de firma, y merece su propia medicion en navegador real.
Verificado: guard visto fallar deshaciendo D9 (caza los dos eventos); `check` 70
errores en linea base; 2250 tests del uix — los 6 fallos de `contracts.test.ts`
siguen siendo de la otra sesion; `docs:check` 0/623 tras regenerar
`vocabularies.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
⚠️ Nota de método: la prueba **no es** `trigger('literal')` . Chronos despacha por
variable (`emitOnChip`) y un grep literal dio dos falsos negativos durante la
auditoría. Lo que se comprueba es más débil y robusto: que el nombre aparezca
como literal en algún sitio que el provider alcance — su directorio soma **más
las librerías compartidas**. Sin `$libs/selection` en el ámbito, combobox y
select se leen como inertes y no lo son.
### D14 · El movimiento por teclado de chronos pierde el foco — `CONFIRMADO` · P1
Salió midiendo D9, y es anterior a él.
[`restoreChipFocus` ](../../src/uix/soma/components/chronos/chronos-provider.svelte.ts )
reenfoca el chip en un `queueMicrotask` , que corre **antes** de que Svelte reponga
el nodo: consulta un elemento que ya no está, `dom.focus(null)` , y el foco cae al
`<body>` .
Medido: se enfoca un chip, se pulsa flecha → el agarre se activa (`data-dragging`)
y el foco pasa a `BODY` ; la segunda y la tercera flecha **no llegan al
manejador**, y el Escape tampoco, así que el agarre queda colgado. La interacción
que el propio componente anuncia —*«Grabbed. Arrow keys move, Enter drops, Escape
cancels»*— muere al primer paso.
No se toca aquí: es un defecto de foco, no de firma, y merece su propia medición
(un `raf` o el `tick` de Svelte en lugar del microtask, verificado en navegador
real y no sólo headless).