--- id: "0118" title: "Funcion cpp agent_runs_timeline: panel SSE de runs cross-app" status: pendiente type: feature domain: - cpp-stack - agents - registry-quality scope: registry priority: alta depends: - "0110" - "0113" blocks: [] related: - "0008" - "0112" - "0116" - "0117" created: 2026-05-18 updated: 2026-05-18 tags: [agents, timeline, sse, cpp, imgui, viz, registry-gap] flow: "0008" --- # 0118 — Funcion `agent_runs_timeline_cpp_viz` ## Problema Panel de timeline de runs es identico en kanban_cpp (0112) y skill_tree v2 (0116). Sin funcion compartida = duplicacion. ## Decision Funcion C++ en `cpp/functions/viz/agent_runs_timeline.{cpp,h,md}`. API: ```cpp namespace fn_viz { struct AgentRun { std::string id; std::string app; // "kanban_cpp" | "skill_tree" | ... std::string issue_id; std::string card_id; std::string branch; std::string status; // "pending" | "running" | "done" | "validated" | "merged" | "aborted" | "failed" int64_t started_at; int64_t finished_at; int dod_total; int dod_done; int dod_validated; }; struct TimelineFilter { std::vector apps; // vacio = todos std::vector statuses; // vacio = todos int64_t since_ts; // 0 = sin filtro }; struct TimelineState { std::string sse_url; // ej "http://localhost:8486/api/runs/sse" std::vector runs; TimelineFilter filter; std::function on_select; // callback(run_id) }; void render_agent_runs_timeline(TimelineState& state); void poll_sse_runs(TimelineState& state); // llamar 1x/frame, no bloquea } ``` Renderiza tabla con `data_table_cpp_viz`: - Cols: status (icon), app (chip color), issue/card, branch, dod_done/total, dod_validated/total, duration, started_at. - Sort por started_at desc por defecto. - Click row -> `on_select(run_id)`. - Filtros arriba: combo apps multi-select + combo statuses + date picker `since`. - SSE en background thread: append runs nuevos, update statuses en vivo. ## Criterios de aceptacion - [ ] `cpp/functions/viz/agent_runs_timeline.{cpp,h,md}` registrado. - [ ] `params_schema` y `output` completos. - [ ] Tag `agents` aplicado. - [ ] `.md` cumple contrato self-doc (`## Ejemplo`, `## Cuando usarla`, `## Gotchas`). - [ ] SSE client en background thread con reconnect + `Last-Event-ID` resume. - [ ] Demo en `cpp/apps/primitives_gallery/demos_viz.cpp` con TimelineState mock (5 runs varied status). - [ ] `kanban_cpp::panel_agent_runs` usa la funcion. - [ ] `skill_tree` `panel_timeline` usa la funcion. - [ ] `fn doctor capabilities` muestra grupo `agents` con esta funcion. - [ ] `uses_functions` declara: `http_request_cpp_core`, `data_table_cpp_viz`, `icons_tabler_cpp_core`, `tokens_cpp_core`. ## Gotchas - SSE reconnect: si `agent_runner_api` cae, reintenta cada 5s con backoff. Estado `disconnected` visible. - Thread-safety: SSE thread escribe `state.runs`; UI thread lee. Mutex o cola SPSC. - Memory: si runs > 1000 historicos, paginar (LRU 200 visibles). Antiguos se descargan on-demand via `GET /api/runs?since=...`. - App `chip color`: mapear app_name -> accent del trio (kanban_cpp `#a855f7`, skill_tree color actual). Cache. - Click row durante streaming SSE: no resetear seleccion al refrescar lista; preservar por `run_id`. ## Out of scope - Editor inline de DoD desde timeline (eso es panel DoD 0117). - Export CSV/JSON. - Notificaciones desktop al cambiar status.