summaryrefslogtreecommitdiff
path: root/docs/stats-tab-plan.md
blob: 6b6dcc4929dfea9c93937f0342049c971dcaccfc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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