--- title: CONTINUE — Eje agéntico ($agent) · punto de reanudación type: process / handoff date: 2026-07-28 branch: alpha-0.1-sec-dom (COMPARTIDA entre sesiones — disciplina abajo) spec: docs/spec/delegation-contract.md (NORMATIVA — se construye CONTRA ella) doctrina: docs/architecture/agent.md (el PORQUÉ) plan: PLAN-agent.md (el acta, fila a fila) --- # CONTINUE — Eje agéntico (`$agent`) Track del **agente como tal**; la integración por componente pertenece al track de cada componente. Este documento es el punto de reanudación: **qué hacer primero**, qué está bloqueado y qué trampas ya nos costaron tiempo. La historia está comprimida al final — si buscas el acta completa, está en [`PLAN-agent.md`](PLAN-agent.md). --- ## 1. Lo primero al abrir sesión ```bash git fetch gita && git log --oneline -3 # la rama es COMPARTIDA: mira quién tocó npm run agent:check # guard del eje (D-AG.11) npx vitest run src/arts/agent # 33/33 (10/10 son conformance) ``` Si algo de eso no está verde, **eso es el trabajo**, no lo de abajo. --- ## 2. Bloqueado: dos firmas del usuario Están escritas en **§D de la spec**, que es donde viven las decisiones abiertas de un DRAFT (al promocionar, §D debe quedar vacía). **No las firmes tú.** | | Decisión | ¿Bloquea? | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | | **§D.1 · AG-35** | Presencia: `SHOULD` o `MUST`. Recomendación razonada ya escrita en la spec: `SHOULD` + política que lo eleve a `MUST` — rehusar por defecto rompería los 30 tests del motor y le quitaría al app el derecho a expresar el ciclo a su manera (el playground de agnt ya lo hace SIN Aura) | No | | **§D.2 · AG-41** | La forma del canal de elicitación | **SÍ — bloquea F4b** | **Por qué §D.2 bloquea**: la elicitación está especificada y **no cumplida**, y la razón es estructural, no cosmética — la escalada lleva una _razón_ tipada pero **no la pregunta**, y `resolveEscalation(runId, 'continue' | 'cancel')` **no tiene por dónde llevar una respuesta**. Hacen falta los dos sentidos: ```ts AgentRunSnapshot.elicitation?: { requestId, prompt, schema? } // la pregunta sale resolveEscalation(runId, resolution, answer?) // la respuesta entra ``` Ambos aditivos (nada existente rompe), y el protocolo ya tiene la forma reservada en `elicitation-request` (AG-48). Pero **la forma es decisión de spec**, no de implementación: por eso está en §D y no en un TODO. --- ## 3. Desbloqueado: empezar por aquí **F4b — los dos manifiestos**, con dueños ya firmados en `PLAN-agent.md` §5b. No dependen de §D. 1. **Manifiesto de `form`** (forma ESQUEMA) — args tipados sium + validación + write-scope por campo. Es el único componente cuyo manifiesto el motor **ya sabe escribir**: los args de una capacidad SON schemas (`toJsonSchema`, F1 construido), así que agente→componente y componente→agente (la elicitación) son la misma proyección en los dos sentidos. 2. **Manifiesto de `table`/`tree-grid`** (forma CONJUNTO) — actos sobre N filas, OCC por fila, batch como transacción. Es donde la claim «delegación como transacción» deja de ser palabra: sobre texto es casi trivial. 3. Al aparecer el primer manifiesto en `src/uix/agent/components/`, **se encienden solas las cinco auditorías dormidas de `agent-check`** (drift manifiesto↔API · tier de madurez · veracidad de reversibilidad · calidad model-facing · no-bypass). Ya están declaradas en el script. 4. Lo demás de F4b: árbol de manifiestos · promoción `uix.agent` (cierra D-AG.1b) · `toJsonSchema` → `$sium` · wiring `identity.locale ← prefs` · **chat** como consumidor (provenance por mensaje · slot de actividad · vista conversacional del run). > **Chat y palabras son CONSUMIDORES, no jueces** (§5b). El criterio no es > disponibilidad sino dificultad: «un formato lo decide su caso peor». Ambos son > texto lineal — probar solo ahí habría sesgado el manifiesto hacia texto en > silencio. Inventario al firmar: **170 morfos, 0 con capacidad `delegate`**. **F2 — piloto palabras**: sigue GATED hasta que su track firme sus 4 ejes F-B. Cuando abra es el TERCER contexto y hereda patrón, no lo define. --- ## 4. Estado **Cerrado**: F0 doctrina · F1 motor · F3 Aura completa (0–8, audit PASS) + promoción `uix.scene` · F4a marco de integración APP · **la spec** · **los dos vehículos de conformance**. Los dos vehículos que la spec exige existen y **ambos citan requisitos** — condición para que «conformance» no sea retórica: | Vehículo | Qué verifica | Estado | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | `$agent/conformance` | El contrato, por la puerta pública. **Portable**: no importa `createEngineAgent`; habla con un `ConformanceSubject` estructural | 10/10 · cubre AG-2/4/5/6/9/10/21/25/26/50 | | `agent-check` | La participación (manifiestos) | 1 de 6 auditorías viva (anti-falsificación de actor); 5 esperando el árbol | `AG-35` y `AG-41` están **fuera del kit a propósito** mientras §D siga abierta, con un test que fija esa ausencia: afirmar un requisito sin decidir sería inventar la decisión. **Aura**: `component:audit` PASS (0 errores; 3 warnings heurísticos del harness compartido). Anillo de custodia + orbe-contorno + Status en dos líneas + tres desenlaces expresados. Variantes de `Aura.Indicator`: `orb` (defecto, afinado para 32-48px) · `portal` (esfera a contraluz, luce en superficie grande) · `aurora`. **Las elige el desarrollador.** ### Flecos (ninguno bloqueante) - **El pulso de `commit-select` del onion se corta** si el consumidor cierra el anillo al elegir: el sello dura su hold, pero el nodo ya se desmontó. Arreglo: retención tipo `Presence` en el cierre. - **`reviewing` vs `escalated` a 22° de hue**; **`loss` (plum) a 16° de `primary`**. La FORMA los distingue (AG-44, fijado por `shapes.test.ts`) y los declines van a neutral, así que no comparten superficie. Retintar de verdad exigiría una escala nueva: no hay hueco entre las 9 actuales. - Diferidos con disposición (acta en PLAN §F4a): resumen semántico de contexto (F5) · `superseded` por OCC (F2) · journal por defecto en factory. ### Sin firmar, sin bloquear - **Canal de corrección a mitad de run** (`amend`/`nudge`): no existe — un prompt nuevo es un run nuevo. Cambio de motor + protocolo; su sitio natural es la sección de reservas de la spec. - **Pre-run elicitation** (que pregunte ANTES de proponer): hoy solo puede preguntar escalando a mitad. Con `Form.AutoFields` como vehículo ya no necesita chat, pero sí decidir si el motor abre un hueco de «run de clarificación» o se compone con un run `suggest`. --- ## 5. Verificación ```bash npx vitest run src/arts/agent # 33/33 npx vitest run src/uix/eidos # 361/361 npx vitest run src/uix/soma/components/aura # 11/11 npm run agent:check # limpio npm run morfo:vocabulary # sin errores (warnings ajenos) npm run docs:check # 1 error AJENO (callout) npm run check # 73 errores = AJENOS preexistentes ``` - **`/uix/components/aura`** — demo canónica: anillo on/off, tamaños, variantes, switch **studio** (220px) y los seis estados por compuertas deterministas, SIN modelo. El sitio para juzgar el componente aislado. - **`/active/docs/agnt`** — página del arte: playground gated + §Real model (modelo real: Aura + anillo radial) + transporte + el bus como eje de iniciativa. - Entorno del usuario: **Ollama en `:11434`** con `qwen3-coder:30b` (CPU mayormente → 2-3 min/turno). El `:8080` es **Open WebUI** (API keys OFF — NO sirve como endpoint directo). --- ## 6. Disciplina y gotchas (leer ANTES de tocar) **Rama y git** - **Rama COMPARTIDA entre sesiones concurrentes**: índice y working compartidos, el staging puede evaporarse. Commits SIEMPRE en bloque atómico `git reset -q && git add && verify && commit`. **Jamás amend.** Ficheros mixtos con trabajo ajeno: stagear solo lo mío (backup → `git checkout HEAD --` → mi cambio → `add` → restaurar suyo+mío). - `contracts.test` tiene **2 fallos AJENOS** conocidos (menubar/radio-group), y `docs:check` **1** (callout). No son tuyos. - **El HEAD puede retroceder bajo tus pies**: si tus commits no salen en `git log -3`, comprueba con `git merge-base --is-ancestor HEAD` antes de alarmarte — normalmente la otra sesión commiteó encima. **Verificación visual** - **Chrome en SEGUNDO PLANO congela `rAF` y `ResizeObserver`** (`visibilityState === 'hidden'`): el canvas se queda en 300×150 y **las medidas mienten**. Verificar pintado o tamaño exige la ventana DELANTE. (Media hora perdida diagnosticando un «bug» que era esto.) - **Pane oculto**: no dispara clicks reales y tampoco compone frames. - **Vite escucha en `::1`, no en `127.0.0.1`**, y la extensión de Chrome rechaza `localhost` → hace falta `--host 127.0.0.1` (ya está en `.claude/launch.json`, config `verify`). - **MIRA el render antes de enseñar.** Regla dura re-aprendida dos veces: un efecto construido desde un resumen de texto sale mal (el `portal` nació como anillos planos porque leí «concentric layers» en vez de mirar la referencia). **Trampas de código que ya nos mordieron** - **`createEngineTimers()` como `timers` del motor TIPA pero revienta**: `EngineTimers` expone `schedule`, no `once`; el primer timeout llama a `undefined` y el run cierra como `transport-error`. La factory de `active-app` adapta el puerto justamente por eso. - **`fallbackTarget` gana sobre el `target` del morfo** (contrato de `TriggerOptions`): un provider que lo pase SIEMPRE ignora en silencio el target declarado. Aura pasa el Ring en los terminales por eso. - **`asserts condition` exige llamarse por un nombre anotado**: desestructurarlo de un objeto de contexto son 17 errores de tipo. - **Bus payloads = SOLO metadata**: jamás goal ni contenido de usuario; el suscriptor resuelve del módulo por `runId`. - **openai-chat / Ollama reutiliza `index:0`** para todas las tool calls del stream: una call nueva se detecta por `id` distinto, jamás por index. - **Chrome MCP**: coords de screenshot ≠ viewport con zoom/scroll — para sectores SVG usar DOM dispatch (`pointerdown`+`pointerup`+`click`). - **Sesión paralela regenerando rutas** → full reload del dev server que MATA runs en vuelo. No es bug propio. --- ## 7. Historia comprimida **Hasta 2026-07-22** — F1 motor · adaptador `openai-chat` (Ollama/llama.cpp/LM Studio) · conformidad bus/orca (el `goal` FUERA del payload) · Aura fases 0–8 · promoción `uix.scene` · el patrón «Aura al centro de un OnionMenu». Verificado E2E contra `qwen3-coder:30b` real: ciclo completo y escalada por `doc.clear` → Deny → `returned(aborted, user-cancel)` + documento intacto. **2026-07-23/28 — la superficie visible** (rediseño dirigido por el usuario sobre un banco de mockups con el orbe REAL dentro): - **Anillo de custodia** (`Aura.Ring`): el estado se lee como FORMA — raíl · arco que respira · segmentos = pasos · dos arcos QUIETOS esperando revisión · arco que gira · anillo cerrado + pulso. Movimiento = loops REGISTRADOS, nunca `@keyframes` de receta. - **El orbe es un contorno**: `thickness`; el hueco es real sobre cualquier fondo. Fuera la rama claro/oscuro y `backgroundColor`, que pintaba un disco opaco en el centro. - **Color = tokens de rol**: antes rotaba el hue — delta medido en OKLCH aplicado en YIQ, así que `risk` salía **verde** junto a su propio anillo naranja. - **Desenlaces expresados**: tres terminales con intent intrínseco. Antes un fallo de transporte era **indistinguible de un éxito**. - **Mapa semántico de color**: un hue = un significado en TODA la superficie. - **Status en dos líneas** (cierra D1) · **variante `portal`** · **modo studio** en la demo. **2026-07-23/28 — el contrato**: **D-AG.12** y **§5b** firmadas · la **spec DRAFT** (50 requisitos) · **`agent-check`** · **el kit de conformance**.