---
name: dod_evidence_panel
kind: function
lang: cpp
domain: viz
version: "0.1.0"
purity: impure
signature: "void fn_viz::render_dod_evidence_panel(DodPanelState& state)"
description: "Panel ImGui que renderiza items DoD + evidencias (screenshot/log/url/cmd) con botones validate/reject por item y badge required-missing"
tags: [agents, dod, evidence, imgui, viz, panel, cpp-dashboard-viz]
uses_functions: [tokens_cpp_core]
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [imgui]
tested: true
tests:
  - "count_status: total = items.size"
  - "count_status: unknown status counts as pending"
  - "count_status: missing_required only when required+no evidence+unresolved"
  - "find_evidence: returns matching evidence"
  - "find_evidence: empty state returns nullptr"
  - "status_icon_id: mapping per status"
  - "status_color_token: mapping per status"
test_file_path: "cpp/tests/test_dod_evidence_panel.cpp"
file_path: "cpp/functions/viz/dod_evidence_panel.cpp"
framework: imgui
params:
  - name: state
    desc: "DodPanelState con items (DodItem[]), evidences (DodEvidence[]), run_id y callbacks on_validate/on_reject (std::function<void(string item_id)>)"
output: "void — renderiza header (run_id + counts) + tabla 6-col (status icon | id | kind | expected | evidence preview | actions) inline en current ImGui window"
---

# dod_evidence_panel

Panel ImGui reutilizable para validar la **Definition of Done** de un agente o run. Compone:

- Header con `run_id` y counts por status (`total / done / validated / failed`) + badge rojo si hay items required sin evidence.
- Tabla con icono de status (TI_CIRCLE_DASHED/DOT/CHECK/X), id, kind, expected, preview de la evidence segun kind, y botones Validate/Reject.

Logica pura (count, find, status mappers) en `dod_evidence_panel_helpers.{h,cpp}` — testeada sin ImGui. El `.cpp` del panel hace render real y se compila SOLO cuando una app lo lista en su CMakeLists.

## Ejemplo

```cpp
#include "viz/dod_evidence_panel.h"

fn_viz::DodPanelState state;
state.run_id = "run_abc123";

fn_viz::DodItem it1;
it1.id = "screenshot_home";
it1.kind = "screenshot";
it1.expected = "Landing page con KPI cards visibles";
it1.required = true;
it1.status = "done";
state.items.push_back(it1);

fn_viz::DodEvidence ev1;
ev1.item_id = "screenshot_home";
ev1.kind = "screenshot";
ev1.payload_path = "/tmp/screenshots/home.png";
state.evidences.push_back(ev1);

state.on_validate = [&](const std::string& id) { db.mark_validated(id); };
state.on_reject   = [&](const std::string& id) { db.mark_failed(id); };

// En el render callback de fn::run_app:
ImGui::Begin("DoD evidence");
fn_viz::render_dod_evidence_panel(state);
ImGui::End();
```

## Cuando usarla

Usala cuando una app necesita mostrar al humano los items pendientes de validacion de un run de agente (DoD) con sus evidencias para aprobar/rechazar a mano. Encaja en dashboards de orquestador (`fn-orquestador`), kanban de issues con sub-checks visuales, o paneles "human-in-the-loop" donde se requiere firma manual antes de marcar `done`.

## Gotchas

- **Screenshot preview es stub textual**. La carga real PNG requiere GL context y un cache `map<string, GLuint>` que el panel no posee. Si necesitas thumbnails reales, mantenlos en la app consumidora y pasalos a un callback custom (issue futura).
- **URL open**: en Linux usa `system("xdg-open '<url>' &")`, en Windows `ShellExecuteA`. NO valida la URL antes — si la URL viene de input no confiable, sanitizar antes de poner en `payload_url`.
- **Log preview** lee primeras 5 lineas con `std::ifstream` por frame. Para logs muy grandes o cuando el panel se redibuja a 60fps, considera cachear externamente.
- **Cmd diff** compara strings exactamente (`==`). No hace trimming ni normalizacion de whitespace — el caller decide.
- **Callbacks pueden mutar `state`**: las apps suelen mover el item a `validated`/`failed` desde el `on_validate`/`on_reject`. El panel re-renderiza con el nuevo status en el siguiente frame.
- **`required` + `missing_required`**: solo se cuenta `missing_required` cuando el item es required, NO tiene evidence, y el status NO es `done`/`validated`. Un item required marcado `done` sin evidence no aparece como missing (la app ya lo cerro a mano).
- Llamar dentro de un frame ImGui activo (entre `NewFrame`/`Render`). Fuera, `ImGui::BeginTable` aborta.
