feat(workflows): pipeline pass rates and skill/plugin usage
Restores the five analytics sections that turned out to be worth keeping (patterns, model delegation, error propagation, session complexity, compaction impact) and reworks what the page opens on. The lane panel no longer mirrors the Workspace's live lane strip. It now answers the question the strip cannot: how often each pipeline node actually passes. GET /api/lanes/pipeline-stats aggregates every stage record of every lane AND every archived feature — a lane's own `stages` only holds its current feature, so without the archive the history resets each time a lane starts new work. Evidence-backed passes are counted apart from bare claims, the same line the pipeline map draws between `done` and `passed-no-evidence`. Beside it, GET /api/workflows/skill-usage reports which skills and plugins the sessions actually reach for. Only PreToolUse rows are counted: every call also emits a PostToolUse, and counting both would double every number. A plugin's total includes calls to the MCP tools it ships, so one used purely through MCP does not read as unused. Still dropped from issue #6: the agent collaboration network and the subagent effectiveness scorecards.
This commit is contained in:
+72
@@ -567,6 +567,78 @@ Converge the clone-root `proof/` directory (if it exists at `<lane.cwd>/proof`)
|
||||
- **200** — success
|
||||
- **404** `{ "error": { "code": "ENOLANE", "message": "lane not found" } }` — lane doesn't exist
|
||||
|
||||
#### Pipeline pass statistics
|
||||
|
||||
```http
|
||||
GET /api/lanes/pipeline-stats
|
||||
```
|
||||
|
||||
How often each pipeline node was actually passed, aggregated over every lane
|
||||
**and** every archived feature (an archived feature is a finished run of a
|
||||
pipeline, so it carries most of the history once a lane starts its next
|
||||
feature). No parameters; grouped by pipeline template, busiest first.
|
||||
|
||||
```json
|
||||
{
|
||||
"pipelines": [
|
||||
{
|
||||
"id": "default",
|
||||
"name": "Default feature pipeline",
|
||||
"runs": 4,
|
||||
"nodes": [
|
||||
{ "id": "plan", "label": "plan", "icon": "🧭", "gate": false,
|
||||
"entered": 4, "passed": 4, "withEvidence": 4, "failed": 0 }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- **`runs`** — lanes plus archived features recorded against this template.
|
||||
- **`entered`** — stage records that resolve onto this node (aliases included).
|
||||
- **`failed`** — records whose `result` is `"fail"`; **`passed`** is the rest,
|
||||
so `passed + failed === entered`.
|
||||
- **`withEvidence`** — the subset of passes that carry evidence. Tracked apart
|
||||
from `passed` because a claim and a proof are not the same fact — the same
|
||||
distinction the pipeline map draws between `done` and `passed-no-evidence`.
|
||||
|
||||
**Status codes:** **200** always (an empty `pipelines` array when no lane has
|
||||
recorded a stage yet).
|
||||
|
||||
### Workflows
|
||||
|
||||
#### Skill and plugin usage
|
||||
|
||||
```http
|
||||
GET /api/workflows/skill-usage?status=active|completed
|
||||
```
|
||||
|
||||
Skill invocations counted from `Skill` tool events — `PreToolUse` rows only,
|
||||
since every call also emits a `PostToolUse` and counting both would double
|
||||
every number. `status` filters by session lifecycle, same convention as
|
||||
`GET /api/workflows`; omit it (or pass `all`) for no filter.
|
||||
|
||||
```json
|
||||
{
|
||||
"skills": [
|
||||
{ "name": "ccam:ship-feature", "plugin": "ccam", "count": 12, "sessions": 5 },
|
||||
{ "name": "daily-report", "plugin": null, "count": 3, "sessions": 3 }
|
||||
],
|
||||
"plugins": [
|
||||
{ "name": "ccam", "skills": 1, "skillCalls": 12, "mcpCalls": 4 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- **`skills`** — top 30 by call count. `plugin` is the `plugin:skill` prefix, or
|
||||
`null` for a built-in or personal skill.
|
||||
- **`plugins`** — per-plugin totals: distinct skills used, their calls, and
|
||||
calls to the MCP tools that plugin ships (`mcp__plugin_<plugin>_<server>__*`),
|
||||
so a plugin used only through MCP does not report zero.
|
||||
|
||||
**Status codes:** **200** always; **500** with `{ "error": { "message" } }` on a
|
||||
query failure.
|
||||
|
||||
|
||||
### Locks
|
||||
|
||||
|
||||
@@ -464,6 +464,24 @@ The lane is resolved from the working directory, so no id is needed (pass one to
|
||||
|
||||
Switching re-resolves the lane's existing declared `stage` against the new node list. A stage the old template knew may resolve to nothing in the new one; the switch warns when that happens (both CLI and UI), and the next `ccam stage` fixes it.
|
||||
|
||||
### Aggregate pass rates across lanes
|
||||
|
||||
`GET /api/lanes/pipeline-stats` answers the other question about node states —
|
||||
not "where is this lane now" but "how often does this stage actually pass". It
|
||||
counts every stage record of every lane **and** every archived feature, grouped
|
||||
by pipeline template:
|
||||
|
||||
- `entered` — records that resolve onto the node (aliases included).
|
||||
- `failed` — `result: "fail"`; `passed` is the rest, so `passed + failed === entered`.
|
||||
- `withEvidence` — the passes that carry evidence, kept apart from `passed`
|
||||
because a claim and a proof are not the same fact (the same line the five node
|
||||
states draw between `done` and `passed-no-evidence`).
|
||||
|
||||
Archived features matter here: a lane's own `stages` only holds its current
|
||||
feature, so without them the history would reset every time a lane starts new
|
||||
work. The Workflows page renders this as one bar per node (see
|
||||
`client/src/components/workflows/LanePipelinePanel.tsx`).
|
||||
|
||||
## Attaching a real terminal to a lane
|
||||
|
||||
`ccam lanes shell` attaches a real terminal to the exact tmux session the dashboard's Start/Resume buttons use for this lane (`ccam-lane-<id>`), creating it if it doesn't exist yet. Type `claude` inside it like any normal terminal session — the dashboard's Workspace terminal view is just another client attached to the same tmux session, so both stay in sync live.
|
||||
|
||||
Reference in New Issue
Block a user