diff options
Diffstat (limited to 'docs/stats-tab-plan.md')
| -rw-r--r-- | docs/stats-tab-plan.md | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/docs/stats-tab-plan.md b/docs/stats-tab-plan.md new file mode 100644 index 0000000..6b6dcc4 --- /dev/null +++ b/docs/stats-tab-plan.md @@ -0,0 +1,147 @@ +# Stats Tab — Implementation Plan + +Generated: 2026-03-11 + +--- + +## Goal + +Add a **Stats** tab to the Claudomator web UI that shows: +1. Task state distribution (counts by state) +2. Execution health metrics for the last 24h (total runs, success rate, total cost, avg duration) +3. A simple visual bar chart of execution outcomes + +--- + +## Data Sources (no backend changes needed) + +| Metric | Endpoint | Fields Used | +|--------|----------|-------------| +| Task state counts | `GET /api/tasks` | `state` | +| Execution history | `GET /api/executions?since=24h` | `state`, `cost_usd`, `duration_ms`, `started_at`, `finished_at` | + +Both endpoints already exist. No new API endpoints required. + +--- + +## Component Structure + +``` +<div data-panel="stats" hidden> + <div class="stats-section"> + <h2>Task Overview</h2> + <div class="stats-counts"> <!-- grid: one box per non-zero state --> + <div class="stats-count-box" data-state="RUNNING"> + <span class="stats-count-number">3</span> + <span class="stats-count-label">RUNNING</span> + </div> + ... + </div> + </div> + + <div class="stats-section"> + <h2>Executions (Last 24h)</h2> + <div class="stats-kpis"> <!-- 4 KPI boxes --> + <div class="stats-kpi-box"> + <span class="stats-kpi-value">42</span> + <span class="stats-kpi-label">Total Runs</span> + </div> + <div class="stats-kpi-box"> + <span class="stats-kpi-value">88%</span> + <span class="stats-kpi-label">Success Rate</span> + </div> + <div class="stats-kpi-box"> + <span class="stats-kpi-value">$1.24</span> + <span class="stats-kpi-label">Total Cost</span> + </div> + <div class="stats-kpi-box"> + <span class="stats-kpi-value">4m 12s</span> + <span class="stats-kpi-label">Avg Duration</span> + </div> + </div> + <div class="stats-bar-chart"> <!-- bar chart of outcome distribution --> + <!-- one bar per outcome (completed/failed/cancelled/etc.) --> + </div> + </div> +</div> +``` + +--- + +## Data Transformation Functions (exported for testing) + +### `computeTaskStats(tasks)` +Input: `Task[]` +Output: +```js +{ + byState: { PENDING: 2, RUNNING: 1, COMPLETED: 45, ... } // all states present in tasks +} +``` + +### `computeExecutionStats(executions)` +Input: `RecentExecution[]` +Output: +```js +{ + total: 42, + successRate: 0.88, // fraction (0–1) + totalCostUSD: 1.24, + avgDurationMs: 252000, // null if no finished executions + byOutcome: { completed: 37, failed: 3, cancelled: 2, ... } +} +``` + +--- + +## Files Changed + +| File | Change | +|------|--------| +| `web/index.html` | Add Stats tab button + `<div data-panel="stats">` | +| `web/app.js` | Add `computeTaskStats`, `computeExecutionStats`, `renderStatsPanel`; update `switchTab` and `poll` | +| `web/style.css` | Add `.stats-*` CSS rules | +| `web/test/stats.test.mjs` | Unit tests for `computeTaskStats` and `computeExecutionStats` | + +--- + +## Visualization Approach + +No external library. Pure CSS: +- **State count boxes**: small colored badges using existing `--state-*` CSS variables +- **KPI boxes**: large number + label in a 4-column grid +- **Bar chart**: flex row of divs with percentage widths, colored per outcome state + +--- + +## Tab Integration + +In `switchTab(name)`: +- When `name === 'stats'`: fetch tasks + recent executions, then call `renderStatsPanel` +- Hide `#btn-new-task` (same as other non-tasks tabs) + +In `poll()`: +- If stats tab is active: re-render stats after fetching tasks + +--- + +## Tests (TDD — write first, then implement) + +`web/test/stats.test.mjs`: +1. `computeTaskStats` groups tasks by state correctly +2. `computeTaskStats` returns zero counts for missing states +3. `computeExecutionStats` calculates total, success rate, cost, avg duration +4. `computeExecutionStats` handles empty array (zero total, null avg duration) +5. `computeExecutionStats` calculates success rate = 0 when all failed +6. `computeExecutionStats` ignores executions with no `duration_ms` in avg calculation + +--- + +## Implementation Order (TDD) + +1. Write `web/test/stats.test.mjs` — all tests fail (red) +2. Add `computeTaskStats` and `computeExecutionStats` to `app.js` — tests pass (green) +3. Add `renderStatsPanel` and integrate into `switchTab` / `poll` +4. Add HTML panel to `index.html` +5. Add CSS to `style.css` +6. Manual smoke test |
