Files

89 lines
3.5 KiB
Markdown
Raw Permalink Normal View History

2026-08-18 20:04:13 -07:00
# T10.9 — CLI: runs list/episode/transcript
| Field | Value |
|---|---|
| Phase | P10 — Orchestration |
| Size | S — under 1 day |
| Status | Not started |
| Flags | — |
| Spec | inlined below |
| Blocks | — |
## Goal
Three thin CLI wrappers over the HTTP API — `poimen runs list --goal <id>`,
`poimen runs episode <run_id>`, `poimen runs transcript <run_id> <step>
<attempt>` — the whole troubleshooting UX, no dashboard.
## Facts (inlined — no spec read needed)
- Thin HTTP clients, not a second implementation of the query logic already
in T10.1/T1.7/T1.6 — the CLI calls the same routes T10.4 exposes.
- Rides the eventual shared `poimen` binary (T9.3); workable as a standalone
binary if T9.3 hasn't landed yet — soft dependency, not a hard block.
- `episode` output must include failed attempts by default — T1.7's own
rule. A CLI that hides them defeats the purpose of the command.
- `transcript` dereferences the `BlobRef` server-side, via the HTTP route
(T10.4) — the CLI never talks to `BlobStore` directly.
## Steps
1. `poimen runs list [--goal <id>] [--status <state>]``GET /v1/runs`,
table output (`run_id`, `status`, `goal_id`, age).
2. `poimen runs episode <run_id>``GET /v1/runs/{id}/episode`,
human-readable rendering of `EpisodeView` including failed attempts,
clearly marked.
3. `poimen runs transcript <run_id> <step> <attempt>``GET .../transcript`,
prints prompt/output text, dereferenced server-side.
4. Exit codes: non-zero on API error, distinct code for "run not found" vs
"transport error" — operator scripting depends on this distinction.
5. Test against a live embedded API instance (T10.4's test harness) with a
run that has a retry and a rewind.
## Acceptance
- `episode` on a run with two failed attempts and one success shows all
three, visually distinguishable.
- `transcript` returns the same text content as reading the `BlobRef`
directly through `BlobStore` in a test assertion.
## Verify
**Harness:** T10.4's `axum` test instance, one run with a retry (two
attempts, one failed) and a rewind.
**Integration test**`tests/it_cli_runs_ux.rs`:
1. `runs list --goal G`; assert output contains exactly the runs tagged G,
none untagged.
2. `runs episode <id>`; assert both the failed and successful attempt
appear — count them explicitly, not just non-empty output.
3. `runs transcript <id> <step> 1` (the failed attempt) and `... 2` (the
retry); assert distinct content for each, matching their respective
`BlobRef`s byte-for-byte.
4. Run-not-found case; assert a distinct exit code from a transport-down
case.
**Command:** `cargo test -p cli runs_ux`
**False pass:**
- Step 2 checking only that output is non-empty — a CLI silently filtering
to the winning attempt (T1.7's own named trap) passes a non-empty check
while hiding exactly the debugging signal requested.
## Traps
- Filtering episode output to "just the successful attempt for clarity" —
T1.7's trap restated at the CLI layer; the failed attempts are the reason
this command exists.
- Fetching transcripts client-side by resolving `BlobRef` directly instead
of through the HTTP route. Bypasses the tenant auth checks the API
enforces.
---
Background (not required to do this task):
[T10.4-http-api-surface.md](T10.4-http-api-surface.md) ·
[T1.7-episode-query-surface.md](T1.7-episode-query-surface.md) ·
[T1.6-prompt-and-output-blob-capture.md](T1.6-prompt-and-output-blob-capture.md) ·
[T8.2-metrics.md](T8.2-metrics.md)