--- id: "0119" title: "kanban_cpp: leer dev/issues + dev/flows como cards (sync layer)" status: pendiente type: feature domain: - cpp-stack - kanban - dev-loop scope: app priority: alta depends: - "0112" blocks: [] related: - "0008" - "0109m" - "0114" created: 2026-05-18 updated: 2026-05-18 tags: [kanban, issues, flows, sync, frontmatter] flow: "0008" --- # 0119 — kanban_cpp sync layer: issues + flows como cards ## Problema kanban_cpp (0112) clona el backend de kanban_web con `operations.db` vacia. Pero la intencion del flow 0008 es **gestionar issues y flows directamente desde kanban_cpp**. Sin sync con `dev/issues/*.md` + `dev/flows/*.md`, el board nace vacio y el usuario tendria que recrear cards a mano. ## Decision Anadir endpoint al backend de kanban_cpp que lee frontmatter de los `.md` y los expone como cards/columnas virtuales. Lectura directa de filesystem (no via `issues_api` 0109m — el API service aun no existe; cuando exista, swap). ### Mapping `.md` -> card | Frontmatter | Campo card | |---|---| | `id` | `card.external_id` | | `title` | `card.title` | | `status` (`pendiente`/`en-curso`/`done`/`deferred`) | `column` (mapping) | | `priority` (alta/media/baja) | `card.priority` | | `type` (feature/bug/chore/app) | `card.tag` | | `tags` | `card.tags` | | `flow` | `card.flow_id` | | `dod_evidence_schema` (0114) | `card.dod_items[]` | | body `## Problema` + `## Decision` | `card.description` | ### Mapping status -> columna kanban ``` pendiente -> Backlog en-curso -> Doing en-revisión -> Review done -> Done deferred -> Deferred ``` ### Tableros separados - Board `issues`: source = `dev/issues/*.md`. - Board `flows`: source = `dev/flows/*.md`, columnas distintas (Pending / Running / Done / Deferred). flow body trae `## Definition of Done (user-facing, 4 surfaces obligatorios)`. ### Endpoints nuevos backend kanban_cpp - `GET /api/boards/issues/cards` — lee `dev/issues/*.md`, cachea 30s. - `GET /api/boards/flows/cards` — lee `dev/flows/*.md`, cachea 30s. - `PATCH /api/boards//cards/` — escribe vuelta al `.md` (cambia `status` en frontmatter). Usa `edit_yaml_frontmatter_go_core` del registry (verificar existe; si no, crear via fn-constructor). - `POST /api/boards//cards//launch` — proxy a `agent_runner_api:8486/api/runs`. ### Watcher de cambios `fsnotify` sobre `dev/issues/` + `dev/flows/`. Cuando hay write -> invalida cache + push SSE a UI -> kanban_cpp refresca board. ## Criterios de aceptacion - [ ] `apps/kanban_cpp/backend/issues_source.go` parsea frontmatter via funcion del registry. - [ ] `apps/kanban_cpp/backend/flows_source.go` idem para flows. - [ ] Endpoints arriba implementados con tests. - [ ] `fsnotify` watcher activo; cambio en `.md` propaga a UI en < 2s. - [ ] PATCH actualiza solo el campo `status` del frontmatter, preserva resto. - [ ] Round-trip: PATCH `/cards/0113` status=`en-curso` -> file mtime cambia -> `dev/issues/0113-*.md` tiene `status: en-curso`. - [ ] Click `Launch` en card invoca `agent_runner_api` con `issue_id` + DoD items extraidos del frontmatter. - [ ] Tag taxonomy issue 0103 respetada — solo statuses canonicos. - [ ] kanban_cpp UI muestra ambos boards (tabs `Issues` / `Flows`) con cards reales del repo al arrancar. - [ ] e2e_check: crear `.md` dummy -> aparece en board en <5s. ## Gotchas - Frontmatter mal formado (yaml invalid): card aparece con badge `parse-error` + tooltip detalle. NO crashea backend. - Cambios concurrentes: humano edita `.md` con vim mientras agente lo PATCHea via API. Usar lock file `.md.lock` corto + retry. - `fsnotify` no funciona bien en WSL para `/mnt/c/` paths. Backend corre en WSL, lee paths nativos (`/home/lucas/fn_registry/dev/...`). Verificar. - Issue / flow grandes (>500 lineas body): NO mandar full body en `/cards` (lento). Devolver solo frontmatter + primeras 5 lineas. Body completo via `/cards/` on demand. - Cards sin `status` (frontmatter incompleto): default `pendiente`. - Reordenamiento manual: drag-and-drop en UI cambia status (cruzar columna) PERO no orden vertical persistente — no hay campo `order` en frontmatter. Decision: orden por `updated` desc dentro de cada columna. ## Out of scope - Sync bidireccional con `issues_api` (0109m) — cuando exista, swap filesystem por API call. - Conflict resolution manual (3-way merge UI). - Edicion inline del body markdown desde la card (solo PATCH de `status` + `priority` por ahora). - Bulk operations (mover N cards a la vez).