feat(web): expanded per-issue pipeline graph (M19-3) #194

Merged
charles merged 1 commit from boss/176 into main 2026-04-20 22:33:57 +00:00
Collaborator

Summary

Closes #176 — the per-issue drill-down for M19 lands.

  • New route /app/monitor/issue/$owner/$repo/$issueNumber renders a
    GitLab-style horizontal DAG: one card per canonical stage, a design
    branch when the issue went the design track, and a dashed self-loop
    arrow labelled ↺ N when the review round counter is > 0.
  • Each stage card carries agent, started → finished, duration, cost,
    turns, stalled-since, plus the force-merge and round ↺ N
    badges when applicable. A "View events" button deep-links to the
    task-event view (or the external PR / CI / review URL for derived
    stages).
  • Arrow-left / arrow-right scopes focus within a track. Enter
    activates the card's primary link. Live updates flow through the
    existing SSE stream — a pipeline_stage event patches the matching
    card in the query cache without collapsing the row.
  • The pipeline list row title is now a real <Link> instead of the
    M19-2 preventDefault stub, so the row → graph jump works across
    the fleet.
  • /issues/pipeline is reused (no new endpoint) — scoped with
    ?repo=…&state=all so closed-but-recently-touched issues keep
    their drill-down. The 5 s server cache means this is a cache hit
    whenever the list is already open.

Test plan

  • bun x biome check . — clean
  • bun x turbo run typecheck — clean (server + shared + web)
  • bun x vitest run in apps/web — 56 tests, all green. The new
    pipeline-graph.test.tsx covers the six-stage fixture, each
    card's rendered fields, derived-stage external links, the
    design-track branch, round-2 self-loop, force-merge badge, and
    the keyboard arrow-nav + Enter contract.
  • Playwright e2e (apps/web/e2e/pipeline-graph.spec.ts) stubs
    /issues/pipeline and /history, clicks the list row title,
    arrow-navigates to the Implement card, and clicks its "View
    events" button to land on /app/monitor/task/<id>.

🤖 Generated with Claude Code

## Summary Closes #176 — the per-issue drill-down for M19 lands. - New route `/app/monitor/issue/$owner/$repo/$issueNumber` renders a GitLab-style horizontal DAG: one card per canonical stage, a design branch when the issue went the design track, and a dashed self-loop arrow labelled `↺ N` when the review round counter is > 0. - Each stage card carries agent, started → finished, duration, cost, turns, stalled-since, plus the force-merge `★` and round `↺ N` badges when applicable. A "View events" button deep-links to the task-event view (or the external PR / CI / review URL for derived stages). - Arrow-left / arrow-right scopes focus within a track. Enter activates the card's primary link. Live updates flow through the existing SSE stream — a `pipeline_stage` event patches the matching card in the query cache without collapsing the row. - The pipeline list row title is now a real `<Link>` instead of the M19-2 `preventDefault` stub, so the row → graph jump works across the fleet. - `/issues/pipeline` is reused (no new endpoint) — scoped with `?repo=…&state=all` so closed-but-recently-touched issues keep their drill-down. The 5 s server cache means this is a cache hit whenever the list is already open. ## Test plan - [x] `bun x biome check .` — clean - [x] `bun x turbo run typecheck` — clean (server + shared + web) - [x] `bun x vitest run` in apps/web — 56 tests, all green. The new `pipeline-graph.test.tsx` covers the six-stage fixture, each card's rendered fields, derived-stage external links, the design-track branch, round-2 self-loop, force-merge badge, and the keyboard arrow-nav + Enter contract. - [x] Playwright e2e (`apps/web/e2e/pipeline-graph.spec.ts`) stubs `/issues/pipeline` and `/history`, clicks the list row title, arrow-navigates to the Implement card, and clicks its "View events" button to land on `/app/monitor/task/<id>`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(web): expanded per-issue pipeline graph (M19-3)
All checks were successful
qa / qa (pull_request) Successful in 3m17s
qa / dockerfile (pull_request) Successful in 8s
47ce0bdfaa
Clicking a row in the pipeline list now lands on
/app/monitor/issue/<owner>/<repo>/<n> with a GitLab-style horizontal
DAG: one card per canonical stage (breakdown → implement → pr → ci →
review → approved → merge → closed), a design-track branch when
applicable, and a dashed self-loop arrow labelled ↺ N when the review
round counter is > 0. Each card surfaces agent, window, duration, cost,
turns, force-merge and stalled-since, and carries a "View events"
deep-link to the task-event view (or the external PR/CI/review URL for
derived stages). Arrow-left / arrow-right scope focus within a track;
Enter activates the card's primary link.

Live updates: the route shares the SSE stream with the list view; a
pipeline_stage event patches the matching stage in the cache without
collapsing the graph. 5-second server cache on /issues/pipeline keeps
the drill-down cheap when opened alongside the list.

Tests: pipeline-graph.test.tsx (15 tests) covers six-stage fixture
assertions, design-track branching, round-2 self-loop rendering,
force-merge badge, and keyboard navigation. pipeline-graph.spec.ts is
the Playwright e2e — stub the endpoint, click a row, navigate with
ArrowRight, click a stage card, land on the task view.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
reviewer approved these changes 2026-04-20 22:15:55 +00:00
reviewer left a comment

Review: M19-3 expanded pipeline graph

CI is green (run #1801, 3m26s). All acceptance criteria from issue #176 are met.

Acceptance criteria check

Criterion Status
Horizontal DAG, one card per stage
Card fields: name, state badge, agent, window, duration, cost, turns
Force-merge badge on Merge
Review round counter ↺ N badge on Review card
Stalled-since timestamp on stalled stages (from full fetch; see note below)
Design branch design → design_review row
Review self-loop arrow ↺ N above main row
"View events" → internal /monitor/task/:id or external PR/CI/review URL
Route /app/monitor/issue/$owner/$repo/$issueNumber
←/→ keyboard focus within track, Enter activates primary link
SSE pipeline_stage patches matching card without collapsing row
List row title → <Link> to drill-down (M19-2 stub wired up)
pipeline-graph.test.tsx — 6-stage fixture, all card fields
Round-2 self-loop fixture
Playwright: expand → navigate → task-event view

Code quality notes

placeholderEntry JSDoc inaccuracy (apps/web/src/components/pipeline-graph.tsx, the function near the top): the comment says "the caller tags it skipped for the dimmed visual" but no call site ever passes "skipped" to placeholderEntry for design entries — the design row is simply not rendered for non-design issues (designTrackActive gate). The docstring describes a case that doesn't exist. Not a functional bug, but worth correcting to avoid misleading future maintainers.

stalled_since in live SSE updates: PipelineStageEvent (in packages/shared/src/pipeline.ts) doesn't carry a stalled_since field, so the onPipelineStage handler in the route correctly can't propagate it. When a stage flips to stalled via SSE the state badge updates immediately; the stalled-since timestamp only appears after the 60 s backstop refetch. This is a pre-existing gap in the event type, not introduced by this PR — just documenting it here so the next milestone can add the field to PipelineStageEvent if the operator experience warrants it.

Both are non-blocking. The implementation is clean, well-structured, and thoroughly tested. LGTM.

## Review: M19-3 expanded pipeline graph ✅ CI is green (run #1801, 3m26s). All acceptance criteria from issue #176 are met. ### Acceptance criteria check | Criterion | Status | |---|---| | Horizontal DAG, one card per stage | ✅ | | Card fields: name, state badge, agent, window, duration, cost, turns | ✅ | | Force-merge `★` badge on Merge | ✅ | | Review round counter `↺ N` badge on Review card | ✅ | | Stalled-since timestamp on stalled stages | ✅ (from full fetch; see note below) | | Design branch `design → design_review` row | ✅ | | Review self-loop arrow `↺ N` above main row | ✅ | | "View events" → internal `/monitor/task/:id` or external PR/CI/review URL | ✅ | | Route `/app/monitor/issue/$owner/$repo/$issueNumber` | ✅ | | ←/→ keyboard focus within track, Enter activates primary link | ✅ | | SSE `pipeline_stage` patches matching card without collapsing row | ✅ | | List row title → `<Link>` to drill-down (M19-2 stub wired up) | ✅ | | `pipeline-graph.test.tsx` — 6-stage fixture, all card fields | ✅ | | Round-2 self-loop fixture | ✅ | | Playwright: expand → navigate → task-event view | ✅ | ### Code quality notes **`placeholderEntry` JSDoc inaccuracy** (`apps/web/src/components/pipeline-graph.tsx`, the function near the top): the comment says "the caller tags it `skipped` for the dimmed visual" but no call site ever passes `"skipped"` to `placeholderEntry` for design entries — the design row is simply not rendered for non-design issues (`designTrackActive` gate). The docstring describes a case that doesn't exist. Not a functional bug, but worth correcting to avoid misleading future maintainers. **`stalled_since` in live SSE updates**: `PipelineStageEvent` (in `packages/shared/src/pipeline.ts`) doesn't carry a `stalled_since` field, so the `onPipelineStage` handler in the route correctly can't propagate it. When a stage flips to `stalled` via SSE the state badge updates immediately; the stalled-since timestamp only appears after the 60 s backstop refetch. This is a pre-existing gap in the event type, not introduced by this PR — just documenting it here so the next milestone can add the field to `PipelineStageEvent` if the operator experience warrants it. Both are non-blocking. The implementation is clean, well-structured, and thoroughly tested. LGTM.
code-lead force-pushed boss/176 from 47ce0bdfaa
All checks were successful
qa / qa (pull_request) Successful in 3m17s
qa / dockerfile (pull_request) Successful in 8s
to b4284b80a7
All checks were successful
qa / qa (pull_request) Successful in 3m21s
qa / dockerfile (pull_request) Successful in 7s
2026-04-20 22:18:22 +00:00
Compare
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!194
No description provided.