feat(morfo,soma): M1(ii) virtual-list/grid — el scroll declara su emisor: el host

Los tres `handle-scroll*` de virtual-list/grid estaban en la deuda del D9 como
«declarados y nunca sonados». Mal clasificados: la resolucion YA estaba escrita
en los dos providers como decision con su porque — el listener de scroll
dispara por pixel y la familia handle es ['sound','haptic'] (trinquete `step` +
tick), asi que una emision por defecto seria un clic-clic continuo bajo
scroll con inercia; «apps that want scroll-driven sema feedback should wire it
themselves with their own throttle / debounce policy». Lo que faltaba no era
el emisor: era un sitio DECLARABLE para esa decision. Es exactamente el caso
de diseño del valor `host` de D.2, estrenado aqui: el contrato declara la
superficie, el emisor es la aplicacion anfitriona.

- `emission: 'host'` en los tres eventos, con el porque en el docblock.
- Los dos comentarios de provider apuntan al flag y corrigen la cita
  desfasada (`activeChannels=['haptic']` — hoy son dos canales, lo que hace la
  conclusion MAS cierta, no menos).
- La promesa del host es viable, verificado: `provider.runtime` es campo
  publico — un app puede emitir con su propia politica.
- Deuda D9: -3 ids. Queda UNA entrada en INERT_EVENT_DEBT: gradient-picker
  commit-reset (S-14), la ultima resolucion de la parte (ii).

Sin cambio de conducta: cero emisiones nuevas, cero navegador que medir.

Verificado: guards 309 ✓ / 6 ajenos · check 69 = base aislada, diff VACIO ·
prettier: virtual-list.ts limpio en HEAD queda limpio; los otros 3 ya fallaban.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
alpha-0.1-dir-prefs
dev 2 months ago
parent daa6461d62
commit c73cae0227

@ -245,9 +245,16 @@ por los dos caminos.
[]; leave→dismiss en CONTENT via Presence con la salida autorizada
(scale-out+fade-out, dismiss-fade no); Escape→dismiss-escape. El SILENT del
pack por fin CASA y la puerta de temas funciona. Deudas limpiadas: 3 ids
del D9 + 3 excepciones del censo. QUEDAN 4: virtual-list/grid ×3 ·
gradient-picker commit-reset = S-14. NADIE mas estrena el flag hasta esas
decisiones. La
del D9 + 3 excepciones del censo. ~~virtual-list/grid ×3~~ **RESUELTOS
2026-08-13 con `emission: 'host'`** — la resolucion YA estaba escrita en los
dos providers como decision con su porque («apps wire it themselves with
their own throttle policy»; per-pixel + familia handle = trinquete continuo
bajo inercia) y solo le faltaba un sitio DECLARABLE: es el caso de diseño
del valor `host` de D.2. La cita desfasada del comentario
(`activeChannels=['haptic']` — hoy es ['sound','haptic']) corregida al
tocarlo; la promesa del host es viable (`provider.runtime` es publico).
QUEDA 1: gradient-picker commit-reset = S-14 (retirar el evento o
emitirlo). NADIE mas estrena el flag hasta esa decision. La
instancia original de la ficha (5 pickers con close inerte) esta MUERTA
desde la normalizacion de nombres · ~~`M4`~~ **EJECUTADO 2026-08-13, con
el DIAGNOSTICO CORREGIDO dos veces**: la premisa de la ficha era falsa (hay

@ -324,11 +324,6 @@ const INERT_EVENT_DEBT = new Set<string>([
// Each is a real, unfixed instance of the class — measured 2026-08-12, ledger
// D13. They are NOT exemptions: they are the queue.
//
// The scroll of a virtualised surface is `handle`, declared and never voiced;
// the only event these providers emit is `commit-set-resize`.
'virtual-list.handle-scroll',
'virtual-grid.handle-scroll-row',
'virtual-grid.handle-scroll-column',
// Same shape as D3: a reset declared, no `clear()` to fire it.
'gradient-picker.commit-reset'
]);

@ -19,6 +19,9 @@ export const virtualGridMorfo = {
// scrolling the viewport rows fits. `scroll` extends book canon
// per Cap 8 §1. Was misclassified as shift.navigate.
name: 'handle-scroll-row',
// Host-emitted — see virtual-list `handle-scroll`: the provider
// declines per-pixel emission; the app wires its own policy.
emission: 'host',
semantic: {
family: 'handle',
verb: 'scroll',
@ -30,6 +33,7 @@ export const virtualGridMorfo = {
// User-initiated viewport scroll on the column axis. Same as
// above, axis split for sema cascade differentiation.
name: 'handle-scroll-column',
emission: 'host',
semantic: {
family: 'handle',
verb: 'scroll',

@ -21,6 +21,11 @@ export const virtualListMorfo = {
// Cap 8 §1 ("Algunas diferencias pertenecen al verbo"), fitting
// handle's spirit. Was misclassified as shift.navigate.
name: 'handle-scroll',
// The provider deliberately does NOT emit this (its scroll listener
// fires per pixel; a ratchet on every frame is fatigue): the surface
// is declared for the HOST app, which wires its own throttle policy
// through `provider.runtime` (D.2 / M1(ii), 2026-08-13).
emission: 'host',
semantic: {
family: 'handle',
verb: 'scroll',

@ -263,10 +263,10 @@ export class VirtualGridViewportProvider {
}
};
// NOTE: `handle-scroll-row` / `handle-scroll-column` declared in
// the morfo but NOT emitted here. See virtual-list note —
// pixel-frequency scroll with haptic-only family = device buzz.
// Apps that want scroll-driven sema should wire their own
// throttled emit.
// the morfo as `emission: 'host'` — never emitted here. See the
// virtual-list note: per-pixel scroll on the ['sound','haptic']
// handle family = nonstop ratchet. Apps wire their own throttled
// emit through `provider.runtime`.
const updateScroll = () => {
this.provider.scrollTop = el.scrollTop;
this.provider.scrollLeft = el.scrollLeft;

@ -550,11 +550,12 @@ export class VirtualListViewportProvider {
void this.provider.runtime.trigger('commit-set-resize');
}
};
// NOTE: `handle-scroll` is declared in the morfo but NOT emitted
// here by default. The scroll listener below fires on every
// pixel; family.handle.activeChannels=['haptic'] so emitting on
// each event would buzz nonstop on mobile. Apps that want
// scroll-driven sema feedback should wire it themselves with
// NOTE: `handle-scroll` is `emission: 'host'` in the morfo — this
// provider deliberately never emits it. The scroll listener below
// fires on every pixel, and family `handle` is ['sound','haptic']
// (the ratchet `step` + tick), so a default emission would click and
// buzz nonstop under inertia scrolling. Apps that want scroll-driven
// sema feedback wire it themselves through `provider.runtime` with
// their own throttle / debounce policy.
const updateScroll = () => {
this.provider.scrollOffset = horizontal ? el.scrollLeft : el.scrollTop;

Loading…
Cancel
Save

Powered by TurnKey Linux.