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
1. **Se escribe por `id`.** `D1` …`D10` no se renumeran nunca. Un defecto que
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 |
| D5 | picker-shell | `CONFIRMADO` | P1 | `mode='modal'` promete bloquear Escape y no lo bloquea |
| D6 | date/time-field | `CONFIRMADO` | P1 | `Home` /`End`/`PageUp`/`PageDown` documentados en 4 sitios, nunca construidos |
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 |
| D11 | catálogo | `CONFIRMADO` | P1 | `defaultElement` miente en 24 partes más — enumeradas y guardadas |
| D12 | context-menu · link-preview | `CONFIRMADO` | P2 | sus flechas se dibujan SIN el trazo de contorno que llevan las otras cinco |
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 | chronos | `CONFIRMADO` | P2 | el morfo declara `handle-drag` y `handle-resize` ; nadie los dispara |
| D10 | sema ↔ `$sound` | `CONFIRMADO` | P1 | los 3 resolvers de gesto: migración a medias del 2026-08-06 |
---
## 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` .
### D5 · `mode='modal'` no bloquea Escape — `CONFIRMADO` · P1
Dos sitios lo prometen:
[`picker-shell-handle.svelte.ts:32` ](../../src/uix/soma/components/picker-shell/picker-shell-handle.svelte.ts )
(*«`modal` blocks outside-click + Escape»*) y el comentario de
[`date-picker.svelte:164` ](../../src/uix/soma/components/date-picker/components/date-picker.svelte ).
El Popover resuelve `escapeKeydownBehavior` a `'close'` por defecto
([`popover-provider.svelte.ts:555`](../../src/uix/soma/components/popover/popover-provider.svelte.ts))
y ** `modal` no lo alimenta**: sólo gobierna outside-click, hover y
trapFocus/preventScroll.
**Y hay un defecto más hondo debajo.**
[`date-picker/types.ts:73` ](../../src/uix/soma/components/date-picker/types.ts )
promete que en `modal` *«selection edits a buffer… Cancel reverts to the value
the popover opened with»*. **No hay buffer.** Así que Escape no sólo cierra: se
lleva la edición puesta mientras sella una dismissal. Arreglar sólo el Escape
dejaría la promesa del buffer igual de rota.
### D6 · Teclas de página en date/time-field — `CONFIRMADO` · P1
`Home` / `End` / `PageUp` / `PageDown` están documentados en cuatro sitios y no
existen en el código. Peor: **las tres páginas se contradicen** sobre qué harían
(saltar de segmento, saltar al extremo del rango, o paginar el valor). No es
sólo una funcionalidad que falta: es una decisión que nadie tomó.
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.
Las 24 se parten en dos, y por eso no se arreglan en bloque:
- **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.
El arreglo de referencia es que compongan la primitiva compartida — una flecha,
una forma — y entonces las siete declararían `span` . **Es un cambio visual en dos
componentes**, así que no se toca sin decisión: no se improvisa lo visual.
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')` .
### 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).
**Cuelga de esta decisión** el homónimo `SoundContour` : el 2026-08-11 se renombró
`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.