feat: add loop diagnostics CLI#449
Conversation
mrcfps
left a comment
There was a problem hiding this comment.
@PerishCode Thanks for shipping the new diagnostics commands — I found one behavior mismatch in the new logs <runId> path that looks worth tightening up before operators lean on it heavily.
|
|
||
| return r.outputCommand(cmd, func(ctx context.Context) (json.RawMessage, error) { | ||
| return r.getJSON(ctx, "/api/v1/loops/"+url.PathEscape(strings.TrimSpace(args[0]))+"/logs") | ||
| return r.getJSON(ctx, "/api/v1/loops/"+url.PathEscape(selector)+"/logs") |
There was a problem hiding this comment.
looper logs <runId> currently resolves the run ID to its loop ID and then still calls /api/v1/loops/{loop}/logs. That handler always loads Runs.GetLatestByLoopID(...) (internal/api/handler.go:4218), so once a loop has retried, looper logs <old-runId> will show the newest run's output instead of the run the operator selected. That makes historical failure triage misleading, especially now that the new diagnostics surfaces expose failed run IDs directly. Please either add a run-scoped logs path, or guard this shortcut so it only accepts a run ID when that run is still the loop's latest run.
There was a problem hiding this comment.
Fixed in 123dee9: added run-scoped /api/v1/runs/{runID}/logs, changed non-follow run selectors to use it, and reject --follow for run IDs so historical logs cannot silently show the latest retry output.
mrcfps
left a comment
There was a problem hiding this comment.
@PerishCode I re-reviewed the updated head and verified the new run-scoped logs route, the CLI diagnostics commands, and the added regression coverage for historical run selection and failure inspection. Thanks for tightening up the observability flow — this looks solid.
🔁 Powered by Looper · runner=reviewer · agent=opencode · An autonomous AI dev team for your GitHub repos.
Summary
looper queue failedfor failed queue-item inspection with type/project/limit filters.looper loop inspect <seq|loopId|runId>andlooper loop failuresfor structured loop diagnostics.looper logs <runId>by resolving the run id to its owning loop before calling the existing logs API.Why
CLI-first巡检 showed that common reviewer failure questions required either raw SQLite queries or ad hoc parsing of
metadataJsonand daemon logs. The new commands expose the same persisted state through first-class CLI surfaces so operators can inspect failed work without depending on internal table shape.Design notes
Authority: the diagnostic view is read-only and is based on persisted loop, run, queue-item, and agent-execution records. The failure classification is an operator-facing label only; it is not authority for scheduler, retry, publish, or recovery side effects.
New concept trade-off: the CLI adds a small heuristic failure classifier (
github_transient,git_transient,agent_idle_timeout,pull_request_unresolved, etc.) so humans can triage failures quickly. Cost is another place where diagnostic wording can drift from retry internals, so the output includes the source message and keeps the recommendation advisory. The simpler alternative, continuing to parse rawmetadataJsonor SQLite tables, was rejected because it normalizes internal storage as the observability API.Validation
HOME=/Users/zqxy123/.looper-test-home go test ./...HOME=/Users/zqxy123/.looper-test-home go vet ./...HOME=/Users/zqxy123/.looper-test-home go build ./...go run ./cmd/looper loop --helpgo run ./cmd/looper queue --help