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

70 KiB

CONTINUE — P0 de la auditoría arquitectónica (handoff, act. 2026-09-16)

⚡ BOOT EN PRODUCCIÓN — FILA 1 EJECUTADA 9ae58c236 (2026-09-16), FILA 2 EN VUELO. El autor firmó el diseño que salió de un PANEL DE 9 AGENTES (5 diseños independientes · 3 jueces con lentes distintas · síntesis), no la cura que yo había propuesto: la mía metía los parámetros en el cuerpo del script, lo que hace que su hash cambie en cada sitio, y su «función hermana» del hash era inviable (render.ts importa $libs/errs, así que no es importable desde svelte.config.js). Fila 1, anclada: cuerpo CONSTANTE + parámetros en el atributo data-uix-boot + el generador emite UIX_BOOT_SCRIPT y UIX_BOOT_CSP_HASH en el MISMO generated/boot.js (sin borrar nada, sin globalName: muere el envoltorio escrito a mano) + render.ts sin node:fs + UNA receta por HASH (el nonce baja a salida de emergencia) + el placeholder DEBAJO de %sveltekit.head% + reemplazo FUNCIÓN + el aviso de 'unsafe-inline' + tercer snapshot de la delta contra documento LIMPIO + audit dev que NOMBRA el eje discrepante + boot/pack.test.ts que empaqueta y ejecuta. Adversarial Opus: hash medido bajo CSP real en Chromium 145 / Firefox 146 / WebKit 26 con control negativo bloqueado; app SvelteKit real siguiendo la guía al pie de la letra: construye, prerenderiza y arranca sin violaciones; y el ENOENT probado con un build real (prerender ⇒ 500). 5 defectos del lote cerrados en ronda 2 y re-verificados; el sexto, de redacción, lo cerré yo. Suite 461/5404, check 0 en src/ y scripts/, docs:check 0/0/819. Fila 2 (en vuelo): el generador acepta --schema del SITIO, composeUixPrefsSchema compartida por runtime y boot, guard de rancidez que TUMBA el build, y fixtures de delta por esquema. Cierra el defecto medido que NO era un flash: con el catálogo de un solo idioma del boot por defecto, un usuario árabe de un app multiidioma se queda en LTR toda la sesión, porque el runtime adopta el dir que el boot escribió. ⚠ FILAS QUE DEJA LA FILA 1 (autor): los 1 428 B del audit dev viajan al bundle de producción aunque NO corren (un ternario que el bundler no pliega; misma convención que engine-logger.ts) · el audit queda mudo si el runtime se desecha en el mismo turno · la entrada bin (uix-boot) y esbuild como devDependency declarada · la decisión de producto sobre si el boot debe SELLAR dir (propuesta del panel: que el boot marque su sello y readPrefsEnvironmentFromDom lo ignore, ~6 líneas) · el modo ATTACH no lo cierra ningún diseño (no hay hidratación síncrona del intent) · un themeResolver atado a la instancia sigue sin poder compilarse · el script pesa ~15 KB bloqueantes en <head>, diez veces lo que envía cualquier librería del mercado.

⚡ FILAS NUEVAS (2026-09-16, destapadas por el adversarial de la fila render.ts, commit 418297a82) — PREEXISTENTES, no tocadas; esperan firma del autor. La receta documentada del boot pre-hidratación (guía de theming, §59) NO funciona en ningún despliegue real, y hoy es latente porque ninguna app del repo la cablea (src/app.html sin placeholder, nada en web/ la llama). (1) CÓDIGO, la más grave: en cualquier build de servidor empaquetado renderUixBootScript lanza ENOENT al leer generated/boot.js junto al chunk (medido con Vite 7.3.1 SSR, suelto y con disposición tipo Kit, y con esbuild; en dev funciona, por eso nadie lo vio). Cura medida en 5 entornos: generate-boot.ts emite un módulo TS con el bundle como cadena y render.ts pierde node:fs (?raw de Vite descartado: fuera de Vite genera un tag basura EN SILENCIO); exige borrar generated/boot.js (autorización del autor) y cambia la razón de tener render.ts fuera del barrel (de node:fs al peso, 15 KB). (2) DOC: la receta pasa event.locals.nonce, que Kit 2.55.0 nunca rellena: el navegador bloquea el script y vuelve el flash sin error. Formas correctas propuestas: SSR con CSP por nonce ⇒ %uix.boot:%sveltekit.nonce%% en app.html + reemplazo función; prerender / adapter-static (este repo) ⇒ Kit prohíbe el nonce y toca CSP por hash, con el sha256 del tag en script-src (decisión abierta: ¿función hermana que lo calcule?). (3) DOC: html.replace('%uix.boot%', tag) con cadena interpreta $', $& y $` y puede cerrar el script (medido); con reemplazo función no. Acoplada a la fila nombrada «hueco del boot con esquema propio del app» (mismos ficheros). Observación O1, no defecto: fuera del tipo string, un objeto con toString con estado burlaría la validación del nonce (typeof bastaría si el autor lo quiere). Detalle y sondas: informe del adversarial de la sesión 2026-09-16.

⚡ PRIMERO (act. 2026-09-16) — D-full + sema §3.9 EJECUTADOS 035a74845 (constructor Opus 5 + adversarial Opus 5 independiente: doctrina SANA, 8 defectos, los 6 del lote cerrados antes de anclar; segunda ronda del constructor). Forma: emit() → EmitHandle { id, settled } SÍNCRONO (modelo Animation.finished); pre/coincident proyectan y despachan ANTES del handler en el mismo tick; post handler → tick → emit; TriggerResult.settled siempre; a11y del runtime tras el despacho (en post anunciaba y movía el foco tras el hold); SO4 re-firmado (target ausente ⇒ log ruidoso + el handler corre, en las tres secuencias); clear/clearTarget honran ocurrencias PERSISTENTES en vuelo (carrera nueva del id síncrono, reproducida en test; transitorias ni se honran ni se cuentan). §3.9: el motor enacta 'state' con la MotionSource que ya tenía; soma conserva 'text'/'focus'; muere a11yChannelsOverride. Fase 0 (censo, condición firmada por el autor): 260 eventos, 39 pre + 21 coincident (0 sin sequence, 0 con prewrite), 14 con handler / 46 que ya mutaban en el mismo tick que el void trigger; los 6 que desmontan tienen Presence ⇒ CERO migraciones; la regla transversal [data-event^='emerge-close'] { animation: dismiss-fade } existe en LETRA sobre los 4 overlays pero el preset de Presence gana la cascada en todo instante (el refutador tenía razón en EFECTO). Medido en Chrome (misma sonda antes/después, dos sondas independientes): Escape → data-state=closed dialog 258.6→9.1 · drawer 286.6→9.1 · popover 1757.8→8.5 · float-panel 1807.8→49.7 ms; el sello precede al flip; data-ending-style en los cuatro; toggle queue intacto (20/28/156). Suite entera 5366/5366 (458) · check 0 en src/ (89 en web/ = ledger, intacto: los ~76 emit de routes son fire-and-forget) · gate VERDE (ronda 1) · +20 tests · 3+2+3 mutaciones (⚠ diferir la limpieza UN microtask es un no-op observable; la honesta cruza a macrotask). PENDIENTE DEL AUTOR: mirar el cierre de Dialog y Toast en un Chrome que PINTE (los panes de los agentes estaban ocultos: mutaciones y estilo computado medidos, ningún frame visto). Filas que deja (detalle en CONTINUE-sema-audit.md §3.9): guard «pre + desmontaje sin Presence» (censo vitest + detector dev-only en VisualChannel) · PREEXISTENTE dispose() en vuelo repuebla active · form requiresFocusMove inerte sobre el <form> · §3.1 de sema afirma un tooltip sin trigger( que hoy existe (:277). Instrumentos desechables sin trackear: scripts/__dfull-* y scripts/__advD-* (el autor decide). Siguiente: (2) filas nombradas por coste del bloque de abajo · (3) decisiones del autor (esbuild devDep · one-shot format · axe-core · AT). ⚠ Lección de la sesión: «¿qué estás esperando?» del autor era una PREGUNTA, no un «adelante»: lo leí como firma y me lo corrigió; la firma llegó después, explícita, tras responder «¿parche o profesional?» con las dos condiciones (censo de salidas pre y clear en vuelo) que hicieron el lote arquitectura.

⚡ PRIMERO MAÑANA (act. 2026-09-15, 01:30) — P2 #5 está CERRADO y PUSHEADO (cinco commits: 6e0decb9e #5 A+B+soma+C · 13293fe50 docs · 2ed9c5493 #5-D /blocks · 165c5b33b docs · el de este handoff). Decisiones del autor de hoy: (b) «la política perceptual de reduce pasa al MOTOR» va a la cola de sema (§3.9 de CONTINUE-sema-audit.md, junto a D-full) · los cuatro ficheros de web/routes descongelados en C/D se QUEDAN (opción 2; mueren en la reconstrucción; una orden genérica «arréglalo» NO vuelve a leerse como «descongela»: se pregunta y se para). Orden del día: (1) sema §3.9 + D-full — abrir con las cinco preguntas ANTES de tocar (leer CONTINUE-sema-audit.md entero, sema.md, CANON §9.1, engine.ts dispatch :205-219 y :460-480, soma runtime :1280-1400); forma esperada: la señal lleva la declaración a11y del morfo, el motor aplica 'state' en su pasada de reducción con la MotionSource que ya tiene, soma conserva 'text'/'focus'; D-full = emit() → {id, settled} (re-firma ~40 asserts y prosa engine.ts:639 · morfo.md:801 · sema.md:652; A-36 pinea open=post). Constructor Opus + adversarial Opus, la sesión coordina. (2) Las filas nombradas del bloque de abajo, en este orden de coste: .prettierignore + src/uix/active-uix/generated/ (una línea; HECHA 2026-09-16) · test de render.ts (pins + escape de </script>; HECHA 418297a82 2026-09-16) · idioma reducedMotion ? 'reduce' : 'allow' ×5 → helper en ActiveEidos · asimetría de tipo de prefs.intent (sanea en silencio; setIntent lanza) · hueco del boot con esquema propio del app · prosa del theming-sentinel · escena lee la fuente en el montaje. (3) Decisiones del autor: esbuild devDependency (servidores parados) · one-shot npm run format + lint al gate (árbol quieto) · axe-core «sí, pero no ahora» · pasada AT. Luego distribución + LangBase + wrappers, y P3 (§5 del informe). ⚠ Todo lo de hoy fue con agentes Opus 5 (constructor + adversarial) y DOS cortes por límite de sesión: tras un corte, releer el diff entero antes de reanudar.

⚡ PRIMERO (act. 2026-09-14 noche) — P2 #5 EJECUTADO Y COMMITEADO 6e0decb9e + D 2ed9c5493 («una fuente de motion»: eidos no lee medios y nadie en el árbol uix pregunta al SO), en DOS lotes disjuntos construidos en paralelo por agentes Opus 5 con adversarial Opus 5 independiente cada uno; la sesión coordinó. A (CSS, changelog §61): 65 at-rules @media (prefers-reduced-motion) en 63 CSS + 29 del generador → [data-motion='reduce'] SEL con la misma declaración (paridad a máquina 63/65/89 reglas/178 pares, 0 discrepancias); 4 !important quedan con rival nombrado; guard reduced-motion-media.test.ts (at-rule, anti-vacío, mordido 3/3 y 4/4); verificado en Chrome real por el adversarial con un contrafactual: bajo la media del SO la forma de HEAD NO paraba el anillo del spinner. B (JS, §62): el puerto muerto MotionSource revivido; createMotionSourceFromPrefs en arts/prefs; las tres raíces la inyectan (standalone · attach · fábricas con coreDependencies: ['prefs']); mueren MotionDom.prefersReducedMotion, SceneDom.prefersReducedMotion, HapticChannelDom; ActiveEidos.reducedMotion (tres puertas: prefs · prefs sin ranura ⇒ permitir · standalone ⇒ SO); ocho componentes + dos motores de escena por-dom (aura, Ambient) leen el efectivo; +23 tests; mutaciones 3/2/3 + tipo (la fuente devuelve la intención ⇒ 2 errores nuevos: el puerto es gate de tipo). Adenda (a) firmada: soma (runtime.svelte.ts migración a11y S5) lee la misma fuente, sources.motion OBLIGATORIO como dom (adversarial dirigido: 7 defectos cerrados — el CONTRATO DE CAPA src/uix/contracts.ts seguía diciendo requires: ['dom'] y su test no lo asertaba; la bolsa #97 del bag-census sin motion bajo un casteo; el camino 'text', el único que declaran 9 morfos, sin test; dos snippets de docs que ya no compilaban; cifras). C (cazado por el AUTOR en el docs site, texto invisible en oscuro — coste de (c′) que firmé sin mirar): cuatro layouts congelados componen esquema de prefs propio SIN los ejes visuales y eidos degradaba MUDO a mode='light' constante; ahora createActiveUix fusiona SIEMPRE uixVisualPrefsDimensions() bajo el esquema del app (redefinir sí, omitir no), eidos avisa por logger en vez de degradar, y web/routes/uix/+layout@.svelte (DESCONGELADO por orden del autor, +14/−29) lee la ranura mode y su toggle escribe setIntent('mode') — verificado en Chrome por el coordinador (SO oscuro sin clave ⇒ dark coherente; clave vieja migrada al sobre; toggle en los dos sentidos). Ledger 95 → 93. Suite completa 457/5336 verde (dos veces por los adversariales). Gate entero verde antes del commit. Decisión (b) del autor → fila §3.9 de CONTINUE-sema-audit.md (la política perceptual de reduce pasa al MOTOR: hoy soma dicta channels: [] al motor y un emit() directo no recibe tratamiento a11y; se ejecuta JUNTO a D-full). ⚠ Filas nombradas, no ejecutadas: (1) scripts/theming-sentinel-exceptions.ts tiene 3 excepciones medidas «emulando el media» (feed/sentinel-spinner-reduced-duration, spinner/track-opacity, skeleton/placeholder-base) — la emulación ya no alcanza nada; medir estampando data-motion='reduce' y reescribir la prosa (theming:sentinel no está en gate: nada enrojece, pero mediría CERO y la excepción se lo tragaría); (2) escena lee la fuente en el MONTAJE, no en vivo (paridad con HEAD; arts/scene/README.md); (3) engineFor de aura/Ambient cachea por WeakMap<SceneDom> y clava la fuente del primer montante (paridad estructural); (4) data-motion tiene TRES dueños (reduce · navigation-menu from/to · tabs fade|slide) — el rename es de esos ejes; (5) el idioma { get: () => (eidos.reducedMotion ? 'reduce' : 'allow') } está en CINCO sitios (aura-indicator, Ambient, menu-dial, metrics, onion-menu): un sexto merece un helper en ActiveEidos (p. ej. eidos.motionSource), no un sexto literal; (6) la bolsa sources de soma se construye a mano en 96 sitios y los 93 harnesses castean as unknown as Soma — el tipo era ciego ahí (60 rojos al hacer motion obligatorio); el casteo es una deuda de los harnesses, no de este lote; (7) el boot compila SIEMPRE el esquema por defecto (boot.ts): un app que REDEFINE un eje resuelve distinto antes y después de hidratar ⇒ flash; latente hoy (nadie en web/ llama a renderUixBootScript), pero es el hueco hermano de C y se cierra pasando al boot el esquema del app (o su serialización); (8) D EJECUTADO 2ed9c5493 (firmado «arregla también /blocks»): el shell de /blocks y el boot de cada preview (BootUix) leen mode/density de uix.prefs, sus toggles escriben setIntent, muere el segundo motor de densidad (writeStyle a mano → data-density + escalas del framework 0.84/0.9·1.16/1.12), migración única del blob uix-blocks-prefs (queda {language, dir}), y la preview nace con intent desde la URL y storage: false (ya no hidrata ni escribe el sobre compartido del padre — contaminación cruzada cerrada). Verificado en Chrome por el coordinador: SO oscuro sin blob ⇒ coherente; toggles de modo y densidad mueven <html> y wrapper; blob viejo migrado; preview ?mode=light clara con el sobre en dark intacto. Ledger 93 → 89. Queda SOLO alpha/+layout@ (TERMINATED: no se toca). ⚠ Nombrado por D: ActiveUixOptions.prefs no es genérico ⇒ intent no es puerta de tipo (una errata se sanea en silencio mientras setIntent lanza) — asimetría en src/, fila; density no llega a la preview (BlockDemo no la serializa); las sondas del AUDIT-blocks-ledger.md que esperaban #uix-blocks-display quedan sin puerta; (9) el SSR del docs sirve light y la hidratación corrige — su cura es el boot (previo a #5). ⚠ Lecciones del día: el brief de A llevaba una cifra mía mal medida (grep -rh | grep -v generated filtra LÍNEAS, no el directorio) — el constructor la re-midió porque el brief lo exigía; DOS constructores cortados por límite y reanudados tras releer su diff entero; el constructor B recortó en silencio el README de prefs (cazado por el adversarial: «nunca recortar alcance en silencio»); yo edité CONTINUE-sema-audit.md con un adversarial en vuelo tras decirle «árbol quieto» — la ley es mía también.

Orden del día que queda: decisión del autor sobre esbuild como devDependency (servidores parados) · .prettierignore con src/uix/active-uix/generated/ (una línea; lint fuera del gate) · test propio de render.ts (pins + escape de </script>) · las filas de arriba · push (autor). Luego P2 sema (§3.9 + D-full + canales antes de deltas + stack de persistencia + coincident + engine.explain) · distribución + LangBase + wrappers · axe-core «sí, pero no ahora» · AT · P3. Menores: LangNode import muerto en active-uix.svelte.ts:53; el bundle del boot compila el mismo esquema que la raíz (no recortar).

ACTUALIZACIÓN 2026-08-26 tarde (sesión vicen-42): los items 1 y 2 de «Qué queda» EJECUTADOS. Los 8 guards de contracts.test adjudicados y verdes (461078138, método del precedente; detalle en el cuerpo del commit) — con tres actas: (a) THEME-SYS-1 NO se adjudicó: el peldaño de header-z es decisión del AUTOR (docs/next-features.md, objeción fundada del eje theming aceptada) y quedó como deuda NOMBRADA MAGIC_Z_DEBT en el guard; (b) contracts.test consume ahora scripts/eidos-only-attrs.ts (tercer instrumento sobre el registro compartido); (c) data-ready lo resolvió theming en 1cb07c1e1 (declarado en los morfos, registro entero viajó con su commit, opción A). La primera pasada del árbitro destapó además 48 asserts de TIPO en las 12 suites re-firmadas por agentes de C2c (runtime verde, tipos rojos — el «check con src/ a 0» de abajo era FALSO) → re-firmados a toMatchObject. Política de flakies FIRMADA por el autor (d09c4919c): los 4 flaky eran UNA clase — defaults de vitest (5s test/10s hook) midiendo transform/import bajo carga (5210s agregados vs ~1s solitario; el de orca era el hook beforeEach muriendo en un await import) — resuelta con testTimeout/hookTimeout 30_000 explícitos y con acta en vite.config.ts. HOOK PRE-PUSH ARMADO (byte-idéntico, peer theming avisado). ⚠ Hallazgo residual de clase NUEVA, adjudicación aparte (chip lanzado): gesture.test.ts rotate-detent es un assert sensible a carga (90 vs 270 — projectAngle come velocidad de timestamps reales); verde ×2 en solitario. Siguiente: P1 (item 3 de abajo).

Estado: P0 = A + B + C, EJECUTADO Y VERIFICADO. Fase A cerrada (árbol en verde con instrumento afinado) · fase B cerrada (la puerta existe, sabe fallar y pasó en verde sobre HEAD; hook con fuente commiteada) · fase C cerrada entera (C2a bolsa=contrato · C2b renderProps muerto · C2c efecto muerto — una sola tubería de attrs). D (desacoplar emit del handler) quedó FUERA de P0 por decisión de diseño: la versión barata (D-lite) creaba un contrato condicional (TriggerResult.id a-veces-definido) y se retiró; la correcta es D-full (emit() → {id, settled}) y reabre el eje sema con su handoff — ver §D abajo.

EJE FOCUS-FIRST — EJECUTADO ENTERO 2026-08-26 noche (mandato del autor: «ejecuta el eje focus-first completo»; plan y leyes en docs/process/PLAN-focus-first.md). Nació de la inversión del autor sobre el hallazgo del corpus: el error no era Morfo.focus sin lectores — era la flota que tiene foco y no lo declaraba. Resultado: la declaración es ahora CARGANTE (FocusScope la consume como fallback de política: trapFocus ?? modal ?? policy.trap) y el censo la vigila en AMBAS direcciones.

  • Contrato: MorfoFocus = MorfoFocusTrap | MorfoFocusRoving (unión discriminada por kind; declaración = DEFAULT DE ESPECIE, la prop per-instancia gana — patrón dir). Esquema: grid sin executor.custom firmado LANZA (el primitivo compartido es 1D).
  • 28 morfos declaran: 9 trap (popover corregido a trap:false — la verdad embarcada manda, con acta) · 19 roving (radio-group adjudicado 'both' por APG: su propio keyboard[] declaraba las 4 flechas; grids de calendario ×4 con custom firmado «2D excede el primitivo»).
  • Dos ejecutores reales: FocusScope con policy (7 overlays cableados) · RovingFocusGroup re-clavado a ELEMENTOS (era id-keyed; defecto medido: candidatos sin id colisionaban en '') con membresía viva — 9 providers migrados (lotes A+B por agentes, 41/41 verdes): toolbar (adopción total), tabs/toggle-group/tag-group (primitivo = ejecutor de teclado; el tab-stop sigue a la selección), menubar, listbox, stepper (:not([aria-disabled])), tags-input (input = stop de reposo, desviación firmada), radio-group.
  • Censo focus-census.test.ts 4/4 con red endurecida: trap⇒scope+policy · roving⇒primitivo o custom firmado · INVERSA (maquinaria sin declaración falla). La red inversa destapó 11 más; adjudicados VERIFICANDO providers: 4 declaran (calendarios: roving-tabindex real 2D) y 7 son ESPECIES fuera de la unión con acta in-file (accordion=walk sin stop único · nav-menu=disclosure (eje vivo ajeno) · rating=slider (flechas mueven VALOR) · select=activedescendant · date/time/color-field=segmentos todos tabulables). Kinds candidatos (walk/activedescendant/slider/segments) = decisión del AUTOR pendiente, registrada, jamás dodge del censo. Mentira plantada y MORDIDA en las 3 redes (toolbar trap:true falso + avatar roving falso → 2 rojos exactos; restore byte-idéntico verificado).
  • Docs: morfo.md (fila runtime + ejemplo + paso 5 con ambas familias + fila 2-de-3 firmada) · eidos.md (fila falsa focus.trap retirada) · FocusPolicyTable.svelte renderiza la política en 27 páginas de demo (agente 25 + 2 de referencia; chronos SIN sección Accessibility — hueco de página anotado, no inventado).
  • Verificación: suite completa 5069/5069 · gate verde · censo con mentira demostrada · morfo-check 161/161 en caliente (primera pasada 158/161: los 3 eran la clase «compilación fría» documentada abajo) · perm-check 447/454 pasos con los 10 fallos ADJUDICADOS AJENOS al eje: barcode (clase «navega bajo el eval») · image (red externa) · calendar+fab (falsos positivos: perm-check NO consume eidos-only-attrs.ts — hueco de instrumento de P0, chip lanzado) · tag-group/tags-input/file-upload = clase preexistente «commit-remove corre contra su propio desmontaje» (soma::runtime.target tras el rAF del emit; el catch SEM-2 la convierte en log; diff de migración con CERO toques a commit-remove y file-upload INTACTO falla idéntico — chip lanzado con los 3 cierres candidatos, la elección es del autor).
  • Sin migrar con acta: los 7 de especies nuevas esperan sus kinds (decisión de autor) · chronos sin sección a11y en su página · el eje navigation-menu migrará su walk cuando toque (su eje vivo).

P1 EN EJECUCIÓN (2026-08-26 noche, tras cerrar focus-first) — orden del autor «continua»; agentes Opus 5 ejecutan, la sesión coordina y verifica (orden de agentes FIRMADA esta noche tras corrección del autor).

  • Hecho: logger en Soma.runtime() (ya estaba: 3f8777332) · part-present desde el REGISTRO VIVO (e5cc05a02: bindings.parts se llena del registro cuando la respuesta es inequívoca; callback a mano = override; hermanos repetidos silencian el registro; partsRevision ($state) hace reactiva la membresía de arrays planos; 4 tests; soma 1304/1304) · morfo-check con pase ARIA ADVISORY (presencia required-sin-condición, role declarado↔renderizado, aria-* sin declarar con la tría A-85 exenta; imprime y cuenta aparte, NO gatea hasta adjudicar la primera cosecha — pendiente de correr con servidor limpio).
  • Censo keyboard MEDIDO (agente Opus, tablas completas en el resultado del task; ficheros de trabajo en scratchpad kb6/inv/mod.tsv): 460 entradas / 68 morfos declarantes / 37 valores de key. El mecanismo del morfo (runtime.keydown+actions) ejecuta solo 26 entradas (5,7 %, 6 componentes); 42 páginas de docs renderizan keyboard[] crudo. Dos poblaciones confirmadas: 451 spec ejecutables + 9 no-ejecutables.
  • Adjudicaciones firmadas del wave keyboard (ejecutor Opus en vuelo): palabras Ctrl+B..Y = spec MAL CASEADO (minúscula), no display · '0-9'/'<'/'>'/'/' = display en el tipo (kind) · range-calendar Escape se IMPLEMENTA (única entrada sin ejecutor) · Home/End de calendarios = SEMANA (la declaración+APG arbitran, precedente radio-'both'; cambio de conducta intencional con re-firma de tests) · table 'select'→'toggle-sort' (la mentira era el nombre) · combobox/menu-dial mudan la entrada a la parte verdadera · condición nueva prop-equals (orientación de los «4 declaradas / 2 vivas» ×7 y activationMode de tabs) · catch-up: color-picker, gradient-builder, field-langs, drawer/tooltip trigger · typeahead / dígitos / hotkeys de host / modificadores multi-select = CLASES firmadas del censo nuevo keyboard-census.test.ts.
  • Deudas NOMBRADAS del censo keyboard (no ejecutadas, decisión de autor o verificación pendiente): (a) float-panel Escape kb-move-cancel vs Dismissal en document COMPITEN — AMBIGUO, necesita navegador; (b) palabras 10 entradas en colisión (Enter×3, Tab×3…) desambiguadas por currentBlock, que el morfo no modela — excepción firmada; (c) sidebar Escape declarado en menu-sub, ejecutado en menu-item — límite del mecanismo actions a nivel runtime (no despacha por parte repetida), firma en sidebar-provider:757-762; (d) LA PREGUNTA DE ARQUITECTURA: tres ecosistemas de ejecución conviven (morfo-actions 26 · primitivos compartidos ~115 · artesanal 307) — si el mecanismo del morfo debe crecer, morir o quedarse como está es decisión del AUTOR con estos números delante.
  • En vuelo además: saneo svrs/auth (split crypto real, entry testing con guard, verifyPassword endurecido, test de frontera server-only, docs; la medición completa está en el task del agente) · capa HideOthers (inert ref-count, dialog/drawer/alert-dialog; deuda nombrada: contenido añadido al body con modal abierto queda fuera — MutationObserver no entra en esta iteración).
  • Preparado, en cola tras el wave keyboard (contención types/schema): wave ARIA — split attrs[]/aria[] (989 entradas medidas: 847 aria, 8 role, 134 impostores — type×130, tabindex×2, for, contenteditable) + vocabulario cerrado al spec 1.2 (39 nombres en uso; grabbed/dropeffect deprecados con acta). Brief completo: scratchpad/brief-aria-wave.md.
  • COSECHA ADVISORY MEDIDA (2026-08-27 madrugada, servidor propio, dos pasadas): 258 hallazgos en 32 morfos (58 missing + 200 undeclared). Ficheros completos: scratchpad harvest-pass1/2.txt. Concentración: chronos 120/258 (aria-roledescription ×59 + aria-dropeffect ×42 — DEPRECADO — por celda sin declarar) · card-group 17 · color-field 16 · chart 15 · chat-list 12 · time/date-field 10+10 · radio-cards 8 · calendar 8. Clases para el wave de adjudicación (siguiente ejecutable, agentes Opus): (a) soma escribe aria sin declarar (la clase A4: declaración alcanza o escritura se retira) — controls/expanded/pressed/ disabled/selected/orientation; (b) role="presentation" decorativo ×12 sin declarar; (c) tríos de valor aria-valuemin/max/now/text declarados required SIN condición en sliders/knobs/meters (×27 missing — la condición falta en la declaración, no el attr en el DOM); (d) aria-hidden declarado y no emitido ×18; (e) chronos entero = caso propio (¿roledescription por celda es diseño? dropeffect deprecado ¿se retira o se declara con acta como drag-drop?). El FLIP a gate va al final de ese wave. ORDEN acordado por canal: el wave espera a que vicen-e1 aterrice su C2 (4 providers) — árbol asentado, cero interleaving.
  • DECISIÓN 1/3 FIRMADA por el autor (2026-08-27, «ok» a C+) — mecanismo keyboard: la declaración queda como contrato único (gramática+censo) y la ejecución converge en PRIMITIVOS POR ESPECIE (el patrón del eje focus aplicado a teclas): grid-walk (4 calendarios, ~90 % de máquina compartida) · segment-walk (date/time/color-field) · highlight-typeahead (select/command/combobox/listbox, consolidando list-selection) · value-step (slider/knob/rating/media-player). Además: sanear el hueco medido del dispatcher (actions POR REGISTRACIÓN, no por runtime — la firma de sidebar:757-762 es defecto estructural de un mecanismo sancionado) y el censo pasa a verificar especie→primitivo. Artesanal queda solo lo genuinamente único (palabras), con firma. La premisa que corrigió la adjudicación: «lo mejor para la arquitectura INDEPENDIENTEMENTE de lo que cueste» — la C original sobrevivía por barata. ORDEN: wave C+ detrás del wave de la cosecha (y este detrás del C2 de vicen-e1) — cero entrelazado.
  • DECISIÓN 2/3 FIRMADA por el autor (2026-08-27, «ok» a la opción a) — barrera server-only: *.server.ts NATIVO de SvelteKit en la PUERTA de cada motor svrs (entrada renombrada index.server.ts / testing.server.ts; el ALIAS absorbe el rename — ningún consumidor cambia; SvelteKit rompe el BUILD si el módulo entra al grafo cliente). El censo server-boundary.test.ts se QUEDA como segunda capa (contextos no-SvelteKit); la convención se escribe como LEY DEL TIER en la doctrina de svrs — la puerta, no cada habitación. Encolada tras el wave C+.
  • DECISIÓN 3/3 FIRMADA por el autor (2026-08-27, «ok») — la unión de foco se EXTIENDE con los cuatro kinds medidos: walk (accordion, nav-menu — tabulables nativos, flechas pasean, sin stop único) · activedescendant (select; command/combobox cuando la red los vea — highlight virtual, stop en el ancla) · slider (rating — flechas mueven VALOR) · segments (date/time/color-field — todos los segmentos tabindex 0). Convergencia firmada: la taxonomía de foco CALCA la de los primitivos C+ (segments↔segment-walk, activedescendant↔highlight-typeahead, slider↔value-step, walk↔paseo direccional) — dos contratos, una taxonomía. Cada kind gana verificación bidireccional en el censo; INVERSE_EXCEPTIONS queda vaciada a lo composicional; FocusPolicyTable renderiza las especies nuevas.
  • WAVE 1 COSECHA EJECUTADO 338c49d67 (2026-08-27): 232/258 leyendo fuente (183 declarados A4 · 32 declaraciones ganan su condición real · 17 fuentes corregidas) · 26 AMBIGUO con 6 causas verificadas (insumo completo scripts/__wave1-aria-resultado.md). HALLAZGO MAYOR ABIERTO: 74 % de la cosecha = ARIA de componente COMPUESTO sobre el elemento compartido de la parte anfitriona — el espejo duplica contratos y no escala (6 aria-controls innombrables lo prueban); espejo-vs-instrumento composition-aware = fila cero del dossier. FLIP advisory→gate CONGELADO hasta ese juicio.
  • HOTFIX de regresión del wave 1 f48acab37 (2026-08-27): el espejo de aria-expanded en chat-message.reaction-add emitía 'false' CONSTANTE (stateRef sin fuente + modo aria-boolean «NEVER removed» + bolsa última en el merge = pisaba el valor vivo del Popover compuesto). RETIRADO con acta; verificado en navegador real (clic → popover montado + 'true'). Gemelas LATENTES auditadas (chat-list.item, chronos peek — salvadas por orden de merge); card-group inerte (eidos-scope). LEY DE WAVE nueva (cabecera del dossier + memoria): declarar value: sin registrar la fuente EN EL MISMO MOVIMIENTO fabrica fila del censo, y la variante aria-boolean EMITE mentira si la bolsa gana el merge.
  • DOSSIER UNIFICADO COMPLETO (2026-08-27, vicen-e1 168a0fba0): fila cero con 3 exhibits (mi hotfix = exhibit A cerrado, primer precedente composition-aware ejecutado), recomendación (b)-forma-(ii)-de-§15 con (c) puente; PRESENTADO al autor. Al firmar: veredicto+reparto de lotes se me trasladan y mi descongelamiento se CONFIRMA con mi autor en mi sesión (protocolo de firmas cruzadas de esta noche).
  • FILA CERO EJECUTADA Y CERRADA (2026-08-27, 4 commits P1): retirada de los 35 espejos 216ac0116 (32 del dossier + 3 que su mirrors.mjs no veía — ciego a la forma attr:'role'; comp:true en su propio compo-final) · filas verificadas + L5 vía precedente aria-rowindex c0c03818c (ref computada registrada, mano retirada; «value opcional» = decisión de autor NO tomada) · instrumento de la ARISTA + residuo a cero + FLIP: el pase ARIA GATEA 5027c135f. Cosecha 258 → 16 → CERO (composición cayó 100 % por construcción; confirmación gateada 161/161 exit 0). Forma magra firmada por ambos carriles: la arista se resuelve desde los ATTRS CO-LOCALIZADOS (la identidad ya viaja por la tubería única); disparador NOMBRADO para el marcador explícito (si el flip bidireccional del censo de fuentes destapa filas no-adjudicables en estático). Causa raíz de card-group = STRIP del attr identificador como toggle de estilo (especie nueva archivada; la arista TAMBIÉN en CSS: :not([data-button]) + selector de dos attrs). Excepciones firmadas ×2 con dueño de cura (search-field demo-harness · palabras.status 4.1.3). Maquinaria advisory = patrón de rollout de la casa, documentado en el tipo Issue.
  • C+ TANDA DE ESPECIES COMPLETA (2026-08-27) — 4 primitivos, 4 commits, mismo molde (puro, porqués leídos, false en tecla ajena, AMBIGUO con acta antes que unificación silenciosa, población VERIFICADA): grid-walk b10542110 (4 calendarios, −58; Home/End de rejillas = PÁGINA por declaración) · segment-walk 271c79dea (3 fields, −161; Home/End = VALOR en la especie; Backspace-retrocede = callback del valor) · highlight-walk 4cad87c24 (trío activedescendant, −39; listbox FUERA con evidencia; sin puerto de foco; nextIndex CONSUMIDO con tipo ensanchado) · value-step 5436fa297 (slider/knob/rating/ GRADIENT-BUILDER — destapado por censo, −49; media-player REFUTADO: dos pares mueven dos valores; number/css-field aplazados EN PAR). Cobertura estrenada en 3 huecos preexistentes (month/year-grid, gradient-builder sin NI UN test). Queda del wave: saneo del dispatcher (constructor en vuelo: actions POR REGISTRACIÓN — cierra la firma-workaround de sidebar:757 — + compile recoge deps de condiciones keyboard, la deuda que desbloquea la retirada de la unión AST de vicen-e1) + párrafo de especies en morfo.md.
  • BOLSA DE DECISIONES DE AUTOR (presentación CONJUNTA al cerrar C+, acordada con vicen-e1 — doble vía: lo firmado antes en cualquier sesión se ejecuta y se releva): (1) deriva Home/End set-min/max vs first-item/last-item ×6 morfos, misma conducta; (2) rating: dígitos sin declarar + Number(' ')=0 ⇒ ESPACIO LIMPIA con min:0; (3) gradient-builder par horizontal físico sin firma RTL; (4) migración number+css-field a value-step cuando el par se libere; (5) puertas de borde divergentes calendar vs range-calendar (min/maxViewValue + announceNavigation solo en uno); (6) Shift+PageUp/Down ±1 año sin declarar; (7) ensanchar value a opcional en entradas aria (cura L5 inexpresable); (8-9 de vicen-e1) time-range-picker.invalid (tres formas) · visual tooltip-disabled vs archetype.
  • C+ WAVE COMPLETO Y VERIFICADO (2026-08-27): 6 commits — 4 especies (b10542110 · 271c79dea · 4cad87c24 · 5436fa297, neto −307 de ejecutores artesanales) + saneo dispatcher 3a394c1d4 (actions POR REGISTRACIÓN, workaround de sidebar muerto; compile recoge deps de condiciones — vicen-e1 retiró su unión AST en 445ca917e con prueba deadPerPart=0) + fila keyboard de morfo.md 0da97636b. Barrido final: gate 443 ficheros / 5207 tests VERDE (+138 esta noche) · morfo-check doble pasada 161/161 con el gate ARIA armado dentro.
  • ⚠ WATCH-ITEM DEL LOTE TOOLTIP (medido por vicen-e1, verificar ANTES de commitear ese lote): retirar las DOS entradas del morfo (aria-disabled y data-disabled — la que atenúa es la SEGUNDA, archetypes.css:86-89, no el aria) deja la fuente disabled registrada en tooltip-provider:349 SIN LECTORES ⇒ huérfana nueva que muerde el gate de huérfanas del censo de fuentes, que va en npm run gate y en el hook pre-push COMPARTIDO. La cura es retirar el REGISTRO en el mismo movimiento (jamás una fila de ORPHAN_EXCEPTIONS: sería excepcionar un acierto). isDisabled (:189-191) SOBREVIVE — handleOpen (:213) lo usa. El acta de :339-348 queda obsoleta entera. Y la trampa del auditor: component-audit.ts:866 decide por un includes sobre EL TEXTO DEL MORFO, así que el acta de retirada NO puede escribir esa cadena literal dentro de tooltip.ts o R-1.2 revive y exige una fila de excepción que el README no tiene.
  • RESERVA LEVANTADA — 5a1492952 (vicen-e1 firmó la guarda del censo de fuentes; su fichero ya no está en obra: un rojo ahí es señal real). Tres datos que tocan la decisión 7(a) ejecutada en esta ola: la trampa era DOBLE (fallaban attrs[] y aria[], no solo aria) · el uso fantasma de la condición TAPABA el gate de huérfanas (medido sobre accordion: retirado el value, la registración viva de accordion-provider:318 se quedaba VERDE — el gate de componente y el de parte iban DESINCRONIZADOS desde antes; 7(a) no creó el agujero, lo hizo visible) · el negativo se vio ROJO en el árbol pre-guarda, y lo que reventaba era la mitad del censo, no la del compilador (que siempre tuvo la suya): el negativo no es vacuo. La regla de las dos manos sigue vigente para lo que quede en obra: cada uno tapa lo suyo, nadie repara el fichero del otro.
  • ⚠ AVISAR a vicen-e1 si el lote L3/chronos mueve registraciones: la cifra de ⚠ UNCERTAIN de la cabecera de su censo pasó de SEIS a TRES con la retirada de espejos (216ac0116) y volvería a moverse; el sitio donde apuntarlo ya existe, pero el fichero es suyo.
  • CORRECCIONES PENDIENTES EN MI PROPIO INSTRUMENTO Y ACTA (aplicar al commitear la ola; medidas por vicen-e1 y verificadas por mí):
    1. Proveniencia FALSA en schema.ts (JSDoc de validateSourcelessEntry), en el JSDoc del flag de types.ts y —lo peor— en el MENSAJE QUE SE LANZA: citan la regresión f48acab37 como la clase que el invariante cierra, y NO la cierra (aquella entrada TENÍA value ⇒ retorno anticipado). El invariante cierra la puerta de la FORMA; la regresión entró por la de la REGISTRACIÓN, que el esquema no ve porque no ve al provider. Dato añadido: las 114 apariciones de ariaBoolean llevan TODAS value ⇒ hoy el invariante no muerde ninguna (sigue siendo higiene correcta). Mismo género que la fe de erratas 43bb676d4.
    2. continue MUDO en scripts/morfo-check.ts (~:236): cuando una parte no monta en su demo, ni se cuenta ni se imprime — y el informe dice «161/161». Es la clase «un guard sobre VACÍO pasa» dentro de mi propio instrumento: hay que TALLARLO y reportarlo («N partes no montaron, no validadas»). El hueco real NO son los 7 morfos sin demo ruteada (solo 2 declaran ARIA): son las partes que no montan dentro de demos que sí existen. La talla debe contar COMPONENTES DISTINTOS, no solo partes (afinado por vicen-e1): concentradas en pocos ⇒ problema de demos concretas; repartidas ⇒ el 161/161 mentía POR DISEÑO, y lo citamos toda la semana como evidencia.
    3. Prosa caduca: morfo-check.ts ~:416-417 y ~:456 siguen diciendo «not gating yet» cuando el pase ARIA ya gatea.
    4. Framing correcto para la fila 13: en el pase (d), severity es el filtro DOMINANTE y condition el marginal — quien abra ese trabajo creyendo que el agujero es la condición optimizará lo minúsculo. ⚠ La cifra «115 de 265» que circuló NO es reproducible (tres denominadores distintos en cuatro medidas): NO resucitarla; verificado que nunca entró en briefs ni en este handoff.
  • LA BOLSA DE 12 — FIRMADA UNA POR UNA Y EJECUTADA (2026-08-27): ola de 8 lotes de ficheros disjuntos (workflow, 16 agentes Opus: constructor + adversarial por lote, 0 errores). Hashes: 0556b9a1a contrato (dec 7) · 0d7a97cb7 demos/LA MINA · 04ac452a1 runtime (dec 8+9) · fe31a3f16 valor (dec 1-4) · 2503e7f09 calendario (dec 5+6) · 2d7d2d698 picker (dec 10) · c1f5b4925 tooltip (dec 11) · cb70927e9 L3+chronos (dec 12, lleva el censo del peer con ATRIBUCIÓN declarada y su firma escrita). Gate entero VERDE con la ola dentro: 443 ficheros / 5224 tests. Los 8 veredictos adversariales: ni un defecto de corrección; los documentales (cifra 91→97 medida, dos comentarios que el propio lote volvió falsos, un acta que afirmaba una imposibilidad refutada por sidebar-menu-button) corregidos antes de anclar. LA MINA, que va antes que la puerta: 49 páginas de demo desreferenciaban {a.value.kind} PELADO con el gate de tipos CIEGO por construcción (castean la parte cruda) — la primera entrada sin value habría reventado esas tablas con TypeError. Endurecidas al patrón de la casa. Hoy hay 0 entradas sin value: se desarmó una bomba, no se curó un defecto. ⚠ TROPIEZO REPARADO: el commit de demos entró con git add web/routes y se llevó web/routes/alpha/** (TERMINATED, regla de no commitear). Detectado en el acto, verificado que los 3 commits de arriba eran míos y sin nada del peer encima, y rehechos en UNA invocación con listas explícitas. LEY: git add <directorio> no existe en árbol compartido.
  • FILA 13 pendiente de firma (nacida de la ejecución de la 7): qué significa una entrada declarada SIN fuente que además lleva condition o severity: optional. Hoy queda invisible en los TRES registros (el compilador la salta con la entrada, el resolver no la evalúa, y el pase (d) del instrumento la exime). Opciones: (a) exigir emisión siempre para las sin-value; (b) prohibir condition en ellas; (c) documentar los tres estados (sin value + required + sin condición ⇒ (d) exige; sin value + optional o condicionada ⇒ contrato-only). Mi lectura es (c) — «sin value
    • condición» es la ÚNICA forma de decir «el provider lo posee Y es condicional» — y el peer la suscribe sobre sus dos. Dato para no optimizar lo minúsculo: en ese pase severity es el filtro DOMINANTE y condition el marginal.
  • CANDIDATO NUEVO (autoría vicen-e1, medido): data-perm-step está en 27 de 178 demos ⇒ el 84 % de los componentes no se observa NUNCA en un segundo estado; es la causa raíz de que la regresión de anoche necesitara un humano con navegador. Encaja con el continue mudo que este handoff ya nombra: un contrato verificado en UN estado es medio contrato. Eje candidato «instrumentar demos» — del autor.
  • LOS DOS ÚLTIMOS WAVES DE LA COLA — EJECUTADOS (2026-08-27): 8178c4152 kinds de foco (contrato: la unión pasa a SEIS especies — walk/activedescendant/slider/segments—, 9 componentes declaran, INVERSE_EXCEPTIONS vaciada a lo composicional, censo 4→9 tests con regla por especie, prueba negativa de 6 mentiras: 6 rojos y 6 reversiones byte-idénticas; barrido 168 morfos / 37 declarantes) · 35d0005de kinds docs (tabla de 6 especies en 9 páginas; el <h4> huérfano cerrado por el TIPO — añadir una séptima especie deja de compilar, porque una rama de fallback era código muerto demostrable) · 64ead8407 server-only (*.server.ts en la PUERTA de cada motor, el alias absorbe el rename, npm run build VERDE como prueba de que el grafo cliente sigue limpio; el censo de frontera queda de segunda capa; ley del tier escrita). Gate entero VERDE: 443 ficheros / 5239 tests. ⚠ INSTRUMENTO CORREGIDO en el camino: docs-check modelaba los alias como de UN segmento y declaró rota una importación VÁLIDA ($svrs/auth/testing, ahora clave exacta), poniendo rojo el gate y el hook pre-push COMPARTIDO. Ahora resuelve como Vite (clave más larga primero). El doc tenía razón y el instrumento estaba mal. ⚠ LEY DE COORDINACIÓN (vicen-e1, pagada por los dos): «el árbol está quieto» es una OBSERVACIÓN, no un estado — caduca al escribirla. Quien vaya a medir algo que dependa del árbol ENTERO lo dice ANTES. Y git mv ESTAGEA: dejó dos renames míos en el índice compartido (despejados con git reset -- <rutas> sin tocar el disco).
  • ⛔ LEY: web/routes/**CONGELADO (2026-08-27; regla del autor trasladada por vicen-e1 y adoptada aquí como norma de trabajo — solo restringe, y el autor la corrige cuando quiera): ese árbol se RECONSTRUIRÁ, así que todo trabajo sobre él se tira el día de la reconstrucción. Leerlo como evidencia sigue valiendo; ESCRIBIR no. Medido de paso, sin tocar nada:/da 404 (no hay+page.svelteraíz) y las páginas de componente responden 200 con marcado real. CONSECUENCIA MAYOR PARA TODO ANÁLISIS FUTURO:morfo-check, permutation-checkycomponent-auditvalidan NAVEGANDO aweb/routes/uix/components/<kebab>/+page.svelte. El «161/161» que este handoff cita como evidencia mide un árbol que se va: no es evidencia sobre el contrato, y lo será menos cada día. La ley que se deduce, y que el peer alcanzó por otra vía: el guard debe vivir donde NACE el valor —morfo, compile, runtime— y no donde se observa. Lo construido en src/ sobrevive a la reconstrucción; lo apoyado en la ruta, no. Consecuencias inmediatas: el candidato «instrumentar demos» (data-perm-step27/178) queda RETIRADO por ser trabajo de rutas; el lote0d7a97cb7 (endurecimiento de tablas) vive ahí y no se toca.
  • P2 ARRANCADO (eidos ops) y DOS LEYES DE COORDINACIÓN nuevas:
    1. La regla de las dos manos NO ESCALA A TRES. Con dos sesiones «cada uno tapa lo suyo» basta porque cada uno sabe qué es suyo; con tres, nadie tiene la lista completa — hoy dos carriles tocaron theming-sentinel.ts con UN commit de diferencia y no se perdió nada por ZONAS DISJUNTAS, es decir por suerte, no por protocolo. Ley: antes de entrar en superficie caliente se pregunta a TODOS los carriles vivos (ListAgents), no solo al que uno conoce. Aplicada hoy: paré la ola de P2 antes de escribir y el reparto se negoció por canal (vicen-0b tiene §17/§18 vivas; vicen-42 custodia contracts.test + eidos-only-attrs).
    2. ACOPLAMIENTO POR DERIVACIÓN, no por fichero (vicen-0b, medido): su guard src/uix/value-channels.test.ts deriva el vocabulario de sistema RESTANDO el contrato a lo que emite renderGeneratedBaseEidosCss(). Si una cura cambia QUÉ nombres emite el generador o EN QUÉ ORDEN se compone la hoja, su lista derivada cambia y su guard enrojece sin que nadie haya escrito un nombre nuevo; si solo cambia CUÁNDO se emite (memoizar el mismo resultado), no le afecta. Verificación obligatoria de mi lote: value-channels.test.ts + generated-css.test.ts (esta aserta la hoja byte a byte). Rojo ahí ⇒ ping, no tocar.
    3. LEY DEL «SE ANDUVO» (vicen-0b, y es la misma familia que el continue mudo de mi propio morfo-check): al declarar que algo se emite UNA VEZ, asertar también que se anduvo — que cada raíz declarada resolvió a ficheros de verdad. Una raíz que resuelve a cero es la puerta que nadie habría visto, y un contador a cero se lee igual de verde estando roto.
    4. Matiz de rutas (vicen-e1/dentro): una cura puede vivir en src/ y tener su VERIFICACIÓN natural en una demo — medir ahí vale, escribir no. Afecta a la emisión SSR y al script de pre-hidratación.
  • P2 EIDOS OPS — TRES LOTES EJECUTADOS (2026-09-13), workflow de 2 agentes Opus (constructor + adversarial), tras el fallo del 2026-08-27 por límite semanal. Hashes: memo cc586612a · split 598ea460e · color-scheme 39edbc8db. El adversarial confirmó lo sustantivo con métodos propios (index.css byte a byte contra HEAD normalizando CRLF · base.css +2 líneas · 5751 nombres únicos / 8034 ocurrencias antes y después, lost=[] gained=[] · memo === render directo, y la clave falla por la vía REAL de breakpoints · 452/452 · check 71 · eidos:lint 0) y declaró LOTE CON 4 DEFECTOS: uno de código (dispose() no soltaba el memo, ~431 KB — cerrado antes de commitear) y tres del informe (los consumidores de index.css son 39, no 8, todos bajo web/routes/**; las «3 construcciones en el arranque de /uix» de la medida NO se reprodujeron —se mide UNA; la ganancia es del camino caliente, 16,0→4,1 ms/llamada—; y una afirmación de UI sin navegador). El navegador lo puse yo: en /uix (servidor PROPIO 5201; la navegación por herramienta a localhost está DENEGADA en este entorno — location.assign desde dentro de la página sí funciona) las únicas reglas con color-scheme del documento son las dos de eidos y el computado de <html> bajo data-theme=base-dark es dark; el popup nativo del <select> no sale en screenshot. · COSTURA CERRADA e2c37f892 (firmada «sí» 2026-09-13 tras la pregunta del autor «¿es lo más profesional o es un puto parche?» — mi (a) inicial era un 70 %: dejaba la apariencia como OPCIÓN del que renderiza, con el sufijo -light|-dark del id como SEGUNDA fuente de verdad, y rebajaba el campo a opcional «para no tocar routes». Ley del autor: routes es provisional y no puede afectar al diseño ni a la arquitectura). Forma ejecutada: ThemeDefinition.appearance: ThemeEffective OBLIGATORIO; renderThemeCss lo lee del TEMA (la opción de 39edbc8db murió sin shim; apply(), renderCss() y el generador lo emiten gratis); el sufijo baja a convención de BÚSQUEDA y el validador cierra la contradicción (gate de forma + gate semántico); el bloque del seed (applyColorScheme, donante forzable) declara la apariencia del DONANTE; documento persistido v1→v2 sin migración; web/routes pierde el tipo por diseño → ledger +2 (solo alpha/lib/docs-theme.ts) con la excepción ESCRITA en la cabecera de check-debt.ts (crece SOLO cuando el framework se mueve bajo el árbol provisional). generated/ byte-idéntico, 5751/8034 intactos, 460/460, check 73 (src/ a cero), gate OK. Adversarial: LOTE SANO EN CÓDIGO, 5 defectos (3 docs, 2 informe) corregidos antes de commitear. ⚠ Latentes ANOTADAS: el ledger ENMASCARA la deuda de appearance en theme-variants.ts/grafito.ts (TS suprime el error exterior tras el anidado; comentado en el ledger) · renderThemeCss cruda sobre config NO validada emite color-scheme: undefined (cerrado por el tipo y por la no-exportación de index.ts:74-79; observación, no defecto) · el donante se resuelve dos veces por render (mismo camino). ⚠ Lección: el constructor fue CORTADO por límite de sesión a mitad de la MUTACIÓN — revisar el diff completo ANTES de reanudarlo (podía haber dejado la cura quitada; esta vez no). · Deuda de rutas anotada: web/routes/active/styles.css:8,65 declara lo mismo a mano — se retira en la reconstrucción. · El XOR de recipe-css-contract.test.ts:251 solo mira index.css: con dos entradas queda COMPENSADO por index-runtime-css.test.ts, no cubierto. · Quedan de P2 eidos: #2 (attrs de tema pre-hidratación: exige inventar un contrato de persistencia) y #5 (data-motion='allow': bloqueado por la doctrina de $prefs) — ambos a firma.
  • P2 #2 EJECUTADO e3c0899dd (2026-09-14) — «un motor, un sobre, un código», firmado tras DOS rondas de «¿es lo más profesional o un puto parche?» (mis dos rebajas cazadas: el hook de Kit DENTRO del framework — src/uix tiene CERO $app/* — y un script de arranque REPLICADO con «test de paridad» = dos verdades). Forma: mode dimensión de prefs junto a motion (resolveTheme de $libs/theme ya era su gemelo; el entorno ya traía colorScheme); theme/density/scaling declaradas por la RAÍZ en módulo puro (active-uix/prefs-schema.ts); eidos lee uix.prefs por su puerto (eidos/prefs-source.ts) como ya consume uix.langs/dom/motion; REVOCADA la frase de arts/prefs/README.md:185. Sobre uix.prefs-intent v1 (libs/prefs/document.ts), adaptador localStorage canónico en la raíz standalone, hidratación SÍNCRONA (el bridge awaitea load() aunque sea síncrono → primera resolución con defaults y salto un tick después = el flash movido; la raíz lee el sobre ANTES de crear el motor). Boot COMPILADO con esbuild desde los módulos puros (active-uix/boot/boot.ts → generated/boot.js, sincronía como base.css), renderUixBootScript Kit-agnóstico, NUEVE attrs → delta cero probado con la raíz REAL y tres mutaciones. Hallazgo del test de delta cero: la raíz NO aplicaba el entorno del navegador (esperaba onMount del app) — ahora lo siembra y lo observa ella. Cifras: 57/593 · suite 453/5306 · check 73 (src/ a cero) · gate OK. ⚠ INTERINO: el throw uix+escalar (forma firmada primero) rompe todas las demos → (c′) mañana (bloque «PRIMERO MAÑANA» arriba). ⚠ Lección de coordinación: DOS cortes de agente en una noche (red y límite de sesión) — revisar el diff entero antes de reanudar, y el adversarial cortado NO cuenta como verificación.
  • FILA 15 — axe-core NO es «instalar o no»: es CUÁNDO (deliberación a tres bandas, 2026-08-27; la instalación se RETIRÓ antes de tocar el lock para no convertir doctrina en hecho consumado). Tres caras: · A FAVOR, y es un alegato que se ganó a pulso HOY: nuestros instrumentos propios enseñaron en una jornada ocho agujas ciegas, una etiqueta que miente, un pase que observa un solo estado y un «161/161» que callaba lo que no pudo mirar. Una implementación casera de reglas de a11y envejecería igual de mal. · EN CONTRA: el corpus de tests pasaría a apoyarse en su vocabulario de reglas — puerta de entrada fácil, salida cara. (La otra mitad de la objeción, «viola la dependencia cero», quedó RETIRADA al medir: el repo embarca 2 dependencias y tiene 23 de andamio, así que la regla gobierna lo que se EMBARCA.) · EL TIMING, que decide (vicen-e1/dentro): axe mide el DOM MONTADO, y el DOM montado vive en web/routes — el árbol congelado que se reconstruye. Instalarlo hoy es comprar un auditor para certificar un árbol que desaparece; y sin conducción de estados (data-perm-step 27/178) sólo vería el estado de REPOSO, donde una mentira dependiente de estado es indistinguible de la verdad. Daría VERDE justo sobre lo que nadie ha mirado, y ese verde se cita como evidencia: peor que no tener instrumento. Forma recomendada de la firma: «sí, pero no ahora», con condición de entrada escrita — tras la reconstrucción de rutas y con conducción de estados. Fija el criterio en vez de aplazar sin él.
  • PRECONDICIÓN OPERATIVA, acotada a lo cierto (vicen-42): parar los servidores de dev antes de un comando que ESCRIBE en node_modules (npm i, npm ci, npm prune, cambiar de rama con deps distintas) — leer no. El mecanismo es de WINDOWS: bloqueo obligatorio de ficheros abiertos, un vite con el árbol de módulos mapeado impide renombrar o borrar dentro y npm cae con EPERM/EBUSY dejando el árbol a medias. En Linux/macOS el mismo comando pasa sin ruido: si algún día corre CI en Linux no verá este fallo JAMÁS, y ese silencio no es prueba de que aquí no exista. Y el lock está LIMPIO pese al M de git status (verificado por hash de blob: disco = índice = HEAD): es normalización de finales de línea, así que cualquier delta futuro será del instalador — pero ojo a la trampa CRLF al commitear (3.552 líneas; exigir delta pequeño en --stat).
  • P1 QUEDA CERRADO. Pendiente de decisión del autor: push (la rama acumula todo sin subir) · axe-core (toca package.json, pide árbol quieto) · pasada AT de los 20 top (humano + lector de pantalla) · el candidato «instrumentar demos» (data-perm-step en 27 de 178 — el 84 % de los componentes no se observa NUNCA en un segundo estado). Luego: P2 → P3.
  • GOBERNANZA UNIFICADA (autor confirma en esta sesión, 2026-08-27): la cosecha ARIA (258) y el advisory de fuentes de vicen-e1 (78) se adjudican JUNTOS — dossier unificado en construcción por vicen-e1 (read-only, cruce por componente, una recomendación por fila, lotes a firma del autor); la ejecución posterior = UNA wave y el reparto de coordinación lo presenta el dossier al autor. Mi cola C+ → kinds → server-only queda EN PAUSA hasta el dossier (las 3 firmas intactas; el juicio de composición da suelo a C+ (highlight-typeahead compone Popover) y a los kinds (activedescendant)). Además: axe-core en proyecto client (devDep — APLAZADO deliberadamente: package.json/lock compartidos con 3 sesiones vivas; instalarlo pide árbol quieto) · pasada AT documentada sobre los 20 top (requiere humano+AT, decisión de autor).

Origen: informe de auditoría (artifact Auditoría ActiveUix, https://claude.ai/code/artifact/02076a7a-9a51-4c89-a610-dfd2f6948954) — 70 hallazgos, 10 verificados adversarialmente (7 confirmados / 3 refutados), dos comparativas de mercado. El plan P0→P3 vive en su §5.

Commits de este eje (todos en alpha-0.1-background, sin push)

  • 58fa3021c — fase A: close huérfano de connection (4 errores) · stepper 'completed'→'complete' (el test pineaba la deriva) · langs stop/record.
  • 2ec018107 — fase B: check:gate (src/=0 duro; web/ contra ledger menguante scripts/check-debt.ts, 34 ficheros/71 errores congelados) · eidos:lint · gate (SIN lint — deliberado, ver deuda) · fuente del hook en scripts/hooks/pre-push · .prettierrc endOfLine:auto.
  • 3ca138e91 — C2a: partPropsForRegistration resuelve el contrato entero; nace ssr-contract.test.ts (rojo antes, 6/6 después); pin viejo re-firmado.
  • 9dffa541e — fase A cierre: los 6 rojos del censo adjudicados (2 escrituras «soma posee el valor» · menu-dial estampa olvidada · calendar/fab al allowlist compartido nuevo scripts/eidos-only-attrs.ts que consumen morfo-check Y eidos-lint · palabras.handle declarado). morfo:check 160/161→161/161.
  • <C2b> — codemod renderProps()→.props (83 ficheros, 262 call sites) + borrado del método/tipo, sin shim; comentarios re-nombrados a «render bag».
  • <C2c pendiente de commit al cierre> — efecto syncPartAttrs + flag BORRADOS; ~71 registraciones limpias; suite del runtime re-firmada de asertos-DOM a asertos-de-bolsa; 5 tests de provider (dialog, drawer, pagination×2, popover) re-firmados igual. tabs-provider y radio-group-provider viajaron en 8ac23047f del eje theming con la retirada declarada en su cuerpo (coordinación por canal, opción A).

Verificación con la que cerró C2c

runtime 49/49 · ssr-contract 6/6 · soma-attr-audit verde · morfo:check 161/161 post-strip («All routed morfos validate» — el detector definitivo: una parte dependiente del efecto habría perdido sus attrs requeridos) · las 4 suites re-firmadas 13/13 · check con src/ a 0 (71 = ledger exacto).

La PRIMERA pasada de la suite COMPLETA de la historia (nadie la corría — el hallazgo original demostrándose) destapó y se adjudicó así:

  • 51 asserts de la clase C2c en ~29 tests de provider jsdom (elementos sueltos + getAttribute esperando el efecto retirado → null). Re-firmados a asserts de bolsa en serie (3 agentes con contrato de conversión; los 5 primeros a mano: dialog, drawer, pagination×2, popover). REGLA: prewrite (data-last-action) SIGUE siendo assert de DOM; el resto, bolsa.
  • 1 preexistente real: lint.test — skin-media-player nació (bf12b8a57) sin registrarse en COMPETING_ROOTS (viste el contrato de media-player, clase audio-player). Registrado con razón.
  • 4 flaky de CARGA (pasan en solitario): cookie-adapter y orca (timeouts 10 s) · soma-attr-audit y recipe-css-contract (5 s justos bajo CPU saturada). Ley: un timeout con la máquina cargada NO es un rojo — re-correr en solitario antes de adjudicar.

Los 8 guards rojos de contracts.test.ts (preexistentes, PRIMERA tarea de mañana)

FE DE ERRATAS (lectura del corpus 2026-08-26): «nunca los vio nadie» era FALSO — vistos y contabilizados en 2026-06-27 (gradient-builder/CONTINUE.md:299, «~12 PRE-EXISTING failures from other sessions' WIP») y reducidos de 12 a 3 por cb554ae2e; lo que no existía era una PUERTA que los detuviera, y volvieron a crecer sin que nadie corriera la suite — que es exactamente el hallazgo que este handoff vindica. (Mi patrón de extracción tampoco capturaba el fichero raíz.) Sujetos verificados AJENOS a los diffs de P0:

  1. Barrel de soma: falta waveform -> Waveform en el export público.
  2. Filenames de provider filtrándose a un barrel público (1).
  3. MOR-4: audio-player y skin-media-player sin morfo — invisibles a component-audit/eidos-lint (los competing roots necesitan su propia respuesta en la enumeración, como ya la tienen en lint.test).
  4. THEME-SYS-1: recipes/base.ts 'header-z': '2' z-index crudo ×2 — territorio theming.
  5. Soma importando su propio alias público (1).
  6. Escritura DOM mutable directa en soma (1).
  7. Hardcoded data attrs (8): aura-status ×2 · media-player sliders data-size ×2 · waveform played/remaining ×2 · radio-group y tabs data-ready — proveniencia CORREGIDA por el eje theming (midió con git show): los introdujo 76f18a5e8 (cuyo propio mensaje avisaba «aparece un punto ciego del guard»), NO 8ac23047f. ACEPTADOS como item 0 de su cola (su handoff e8a54ac45), adjudicación pre-masticada: data-ready es contrato REAL (lo leen tabs.css:329 y sliding-indicator.css como puerta anti-flash) → se DECLARA en los dos morfos, ni exención ni retirada. Los 6 restantes siguen siendo de este eje.
  8. Namespaces de traducción no-kebab (4).

Cada uno se adjudica leyendo (¿guard exige razón nueva, o deriva real?) — la clase skin-media-player/lint.test de ayer es el precedente del método. ⚠ El hook NO se armó por esto (promesa: solo en verde). Armarlo = cerrar estos 8 + política para los 4 flaky de carga (¿timeouts subidos? ¿retry?).

Qué queda mañana (en orden)

  1. Los 8 guards de contracts.test (sección de arriba) — adjudicar uno a uno; con ellos verdes y la política de flaky decidida, el gate entero queda verde por primera vez.
  2. Re-armar el hook: cp scripts/hooks/pre-push .git/hooks/pre-push y AVISAR a la sesión del eje theming por SendMessage (prometido dos veces; está conforme). Solo con fase A verde en el árbol.
  3. P1 del plan (informe §5): ejes muertos de morfo (focus: ejecutar desde compiled.focus o amputar+censo · keyboard: censo declaración↔implementación · ARIA: vocabulario cerrado de nombres/roles + separar attrs[] de aria[] · part-present desde registro vivo) · logger en Soma.runtime() (una línea que resucita TODO el diagnóstico — la más barata de P1) · a11y auditable (capa inert/hide-others para modales, axe en el proyecto client, morfo:check con role/aria) · saneo de svrs/auth (adaptadores test a $svrs/auth/testing con guard de producción — el patrón ya existe en memory-store; crypto-web real sin node:crypto; guard de longitudes en verifyPassword; barrera *.server.ts; snippet del docs-site).
  4. D-full como eje propio — EJECUTADO 035a74845 2026-09-16 (ver bloque PRIMERO): emit() → {id, settled}; reabre sema (S-07 intocable, handoff CONTINUE-sema-audit), re-firma su suite (~40 asserts) y la prosa doctrinal (engine.ts:639 · morfo.md:801 · sema.md:652). El test A-36 pinea open=post y NO estorba. El argumento completo del refutador (por qué el hold no sirve a su razón declarada) está en el informe.
  5. P2/P3: eidos ops (HECHOS 2026-09-13: memo cc586612a · foundation una vez 598ea460e · color-scheme 39edbc8db · apariencia en el TEMA e2c37f892 · boot+prefs e3c0899dd · (c′) pines f875f60b9 · #5 una fuente de motion + ejes visuales 6e0decb9e (tres adversariales SANO, gate verde); SIGUIENTE: las filas 1-9 del bloque PRIMERO, luego P2 sema) · sema tubería (canales antes de deltas, stack de persistencia, coincident real o borrado, háptica sin reduced-motion, engine.explain) · distribución + LangBase + generación de wrappers.

Deudas EXPLÍCITAS abiertas (nunca silenciosas)

  • lint fuera del gate: ~2.300 ficheros de deuda de formato preexistente (bump de prettier-plugin-svelte 3.4→3.5 + clases nunca formateadas; el pin a 3.4.1 NO movió el número — no es el plugin, es histórico). One-shot pendiente: npm run format en árbol QUIETO como commit propio + re-añadir npm run lint && al gate. Jamás sobre rama con sesiones vivas.
  • Ledger check-debt.ts: 71 errores de web/ congelados; solo mengua. web/routes/alpha/** está TERMINATED (memoria) — si se borra, sus 16 entradas salen del ledger.
  • gradient-builder.track data-kind: emite provider.kind crudo, que incluye 'mesh' fuera del enum del morfo [linear|radial|conic] — misma exposición que el preview (paridad deliberada). Si una demo monta mesh, morfo-check lo flagueará: decidir entonces (ensanchar enum o guardar).
  • natural-time-picker en morfo:check: clase flaky «demo que navega bajo el eval» (como link); si reincide, endurecer el script (reintento por ruta), no el componente. En la última pasada fue verde.

Leyes de este eje (caro de re-aprender)

  • ⚠⚠ Rama compartida con 2-3 sesiones VIVAS: add selectivo por lista explícita + git diff --cached --stat + commit EN LA MISMA invocación; selección por contenido con git diff -G"patrón" --name-only cuando el status mezcla ejes; JAMÁS stash ni checkout de ficheros ajenos.
  • ⚠ Coordinación entre sesiones por SendMessage FUNCIONA: avisar ANTES de tocar ficheros de otro eje; el peer re-lee del disco; inclusión-declarada (opción A) para cambios triviales mezclados — precedente 8ac23047f.
  • ⚠ Un gate se arma DESPUÉS del verde, nunca antes — armado en caliente bloqueó el push legítimo del peer (y de paso demostró que sabe fallar).
  • ⚠ La bolsa entrega valores CRUDOS (número 20, no '20'); Svelte stringifica al render. Asertos de bolsa ≠ asertos de DOM.
  • ⚠ El único escritor imperativo sancionado es el prewrite de trigger (commit declarado por el morfo). Todo lo demás: bolsa. FE DE ERRATAS (corpus 2026-08-26): la ley tiene UNA excepción abierta en el árbol — textarea-provider:164/191 escribe style: height imperativamente para el autosize (geometría medida, con bug documentado en su README:96-103: pisa el overflow). El cierre correcto es (b): altura por custom property que eidos lee (GESTURES.md:404 regla 2), que arregla el bug de paso — encolado, no ejecutado.
  • ⚠ npm run dev lleva --force: primer morfo:check tras arrancar servidor paga compilación fría → timeouts falsos (accordion/background/link). Pasarlo DOS veces o precalentar. morfo-check/perm/smoke aceptan la URL como argv[2] — usar el servidor PROPIO (5201), nunca el de otra sesión.
  • ⚠ | tail enmascara exit codes TAMBIÉN en los scripts del gate (medido en vivo: check con 76 errores salió 0 por un tail).

P2 #5 — brief (EJECUTADO 6e0decb9e 2026-09-15; se conserva como crónica — la forma final difiere: lotes A/B/C + adenda soma, ver bloque PRIMERO)

LOTE P2 #5 — motion «allow» REAL: eidos y el motor JS leen el valor EFECTIVO, nunca el SO (firmado por el autor 2026-09-14 como parte de «un motor, un sobre, un código»; se ejecuta DESPUES de que el boot (#2) esté commiteado, porque «solo atributo» exige que data-motion exista desde el primer pintado.)

MEDIDO 2026-09-14:

  • Doctrina prefs: resolveMotion (src/libs/motion/resolve.ts:24) — intent 'allow'|'reduce' GANA al hint del SO; 'system' deriva del hint. La proyección estampa el efectivo en data-motion (PREFS_DOM_ATTRS.MOTION).
  • eidos CSS: 94 bloques @media (prefers-reduced-motion: reduce) en 64 ficheros *.css bajo src/uix/eidos (32 con !important) + 65 selectores [data-motion='reduce'] ya existentes (conviven: dos fuentes).
  • Generador: render-css.ts emite el mismo media en 4 sitios (:534, :1193, :1333, :1376) → 29 bloques en generated/base.css.
  • Motor JS: engine-motion.ts:131 reduced = opts?.reduced ?? dom?.prefersReducedMotion.matches ?? false — lee el SO por el puerto DOM, no el efectivo de prefs: un 'allow' explícito tampoco llega al JS.
  • Colisión de NOMBRE: navigation-menu usa data-motion='fade|slide|from-start|from-end|to-start|to-end' en sus propios elementos (motion.css:14 lo anota como «dos dueños»). Valores distintos ⇒ sin clash funcional con [data-motion='reduce'] X; el rename es del eje navigation-menu (vivo, ajeno): FLAGUEAR, no tocar.

FORMA:

  1. CSS: cada bloque @media (prefers-reduced-motion: reduce) { SEL { decl } } pasa a [data-motion='reduce'] SEL { decl } (o SEL[data-motion='reduce'] cuando SEL es el propio html/raíz). Misma declaración, misma especificidad + 1 attr; revisar los 32 !important uno a uno: si el !important solo compensaba la especificidad del media, cae; si bate estilos inline, queda con acta. Los 65 selectores [data-motion='reduce'] existentes se unifican con los nuevos (sin duplicar reglas).
  2. Generador: los 4 emisores de render-css.ts emiten [data-motion='reduce'] en vez del media; npm run generate:eidos-css en el mismo movimiento; generated-css.test verde; value-channels: los --nombres emitidos NO cambian (5751/8034) — comprobarlo.
  3. GUARD: test vitest (junto a recipe-css-contract.test.ts) que falla si aparece prefers-reduced-motion en cualquier *.css de src/uix/eidos o en la salida de renderGeneratedBaseEidosCss(); con anti-vacío (número de ficheros inspeccionados > 60) y probado por mutación.
  4. Motor JS: arts/motion NO importa arts/prefs (puertos). El puerto pasa a ser un reduced inyectado por la RAÍZ desde el efectivo de prefs (createActiveUix: motion recibe una fuente () => prefs.motion.effective === 'reduce' o suscripción), y dom?.prefersReducedMotion deja de ser la fuente por defecto en modo compuesto; standalone (sin raíz) conserva el fallback del SO con acta. Test: intent 'allow' con SO reduce ⇒ el motor NO degrada; intent 'reduce' con SO no-preference ⇒ degrada.
  5. Docs: docs/theming/motion.md o el capítulo que documente reduced-motion (grep) + arts/motion/README.md + changelog: «eidos no lee medios: lee atributos; el efectivo lo decide prefs». VERIFICACIÓN: vitest eidos + arts/motion + active-uix + value-channels; check (src/ a cero; ceiling web/ del ledger); check:gate; eidos:lint; prettier de lo tocado; adversarial con re-medida (grep cero media en eidos, cuenta de reglas antes/después, !important antes/después con acta por cada uno que queda).

Powered by TurnKey Linux.