feat(github): surface pull request merge queue status (#2928)

This commit is contained in:
Carlos Florêncio
2026-08-22 19:51:59 +00:00
committed by GitHub
parent 26ef699b00
commit 690a1ec3fe
51 changed files with 2306 additions and 166 deletions
+91 -22
View File
@@ -9,9 +9,13 @@ status: complete
## Overview
Extend the existing GitHub merge boundary to use GitHub's asynchronous,
queue-aware merge request and return a typed merged-or-queued outcome. Then
reuse that outcome in the existing PR merge button across the desktop detail,
compact status, and mobile Review surfaces, with targeted unit and E2E proof.
queue-aware merge request and return a typed merged-or-queued outcome. Observe
the resulting merge-queue entry through the existing GraphQL status sync,
persist its state, one-based position, and optional estimated duration, and
project it through the existing task and PR status surfaces. Reuse the typed
outcome and the persisted status in the existing PR merge button across the
desktop detail, compact status, and mobile Review surfaces, with targeted unit
and E2E proof.
## Backend
@@ -37,6 +41,21 @@ compact status, and mobile Review surfaces, with targeted unit and E2E proof.
`{"status":"merged"}` or `{"status":"queued"}` and retain the existing
operational-auth and provider-error mapping.
### Queue observation, persistence, and bounded projection
- Extend the batched GraphQL pull-request selection and normalized `PRStatus`
with `mergeQueueEntry { state position estimatedTimeToMerge }`. A populated
GraphQL result replaces all three queue fields atomically; queue-unaware REST
and `gh pr view` reads preserve the last complete observation, while an
authoritative null or terminal lifecycle state clears it.
- Add the queue state, one-based position, and optional estimate in seconds to
every `TaskPR` schema, migration, write, restore, and update path. Extend
the mock controller so integrated tests can seed the same contract.
- Carry queue membership through live and restart-built task status summaries
as the bounded `queued` state. Terminal states precede queue membership;
queue membership precedes other non-terminal states for one PR, while the
existing aggregate ranking keeps a failing sibling above a queued sibling.
## Frontend
### Queue-aware merge action
@@ -54,6 +73,22 @@ compact status, and mobile Review surfaces, with targeted unit and E2E proof.
`apps/web/src/locales/*/github.json`; generate the Traditional Chinese pair
through the repository script rather than translating them independently.
### Queue status color and surfaces
- Add the normalized queue fields to the web `TaskPR` contract and the shared
queued semantic color `text-[#966600]`. Terminal colors remain first; an
active queue entry is second, so hydrated failure, draft, dirty, or behind
fields cannot overwrite queue presentation. Multi-PR aggregation still ranks
a failing sibling above a queued sibling.
- Extend the task hover summary, compact desktop popover, phone status drawer,
and PR detail panel with translated queue state, one-based position, and an
optional estimate rounded up to localized whole minutes. Missing estimates
omit only the estimate line. Recognized provider states retain their labels;
future non-empty states use generic `Queued` copy.
- Keep queue derivation shared across desktop and mobile. Mobile display uses
the existing drawer and Review destination; the mobile merge-action test
separately verifies the existing 44px action target.
### Mobile design contract
- Desktop outcome: the existing PR detail header and compact status surface
@@ -92,31 +127,59 @@ compact status, and mobile Review surfaces, with targeted unit and E2E proof.
and refresh callback. **File:**
`apps/web/components/github/pr-merge-button.test.tsx`. **How:** component tests
with mocked API outcomes.
- **What:** queue observation, persistence, queue-unaware read preservation,
terminal clearing, and bounded live/restart projection. **Files:**
`apps/backend/internal/github/*merge_queue_status_test.go`,
`apps/backend/internal/github/store_taskpr_schema_drift_test.go`,
`apps/backend/internal/task/statussummary/merge_queue_status_test.go`, and
`apps/backend/internal/backendapp/status_summary_adapter_test.go`. **How:**
focused GraphQL, real-store, and projection tests.
- **What:** queue color precedence, failing-sibling aggregation, translated
queue metadata, estimate boundaries, terminal queue clearing, and generic
fallback copy. **Files:**
`apps/web/components/github/pr-task-icon.test.ts`,
`pr-task-status-summary.test.ts`, `pr-status-chip.test.tsx`,
`pr-merge-queue-status.test.tsx`, `pr-mergeability-row.test.tsx`, and
`pr-detail-panel.test.tsx`. **How:** pure formatter and focused component
tests for terminal, queued, future-state, missing-estimate, sub-minute, and
minute-boundary cases.
## E2E Tests
- **Scenario:** eligible direct merge reports merged. **File:**
`apps/web/e2e/tests/pr/pr-merge-queue.spec.ts`. **What to verify:** the desktop
PR surface exposes the action, submits it, and shows the merged notification.
- **Scenario:** queue-required merge reports queued and does not resubmit.
**File:** `apps/web/e2e/tests/pr/pr-merge-queue.spec.ts`. **What to verify:**
the desktop action remains available for the queue-required state and the
accepted queue notification is shown once.
- **Scenario:** phone Review surface provides the same queued outcome. **File:**
`apps/web/e2e/tests/pr/mobile-pr-merge-queue.spec.ts`. **What to verify:**
Review navigation, touch activation, queued notification, a touch-sized
action, and no document horizontal overflow.
- **Scenario:** an eligible queue-required merge is accepted. **File:**
`apps/web/e2e/tests/pr/pr-merge-queue.spec.ts`, action test. **What to
verify:** the desktop PR surface exposes `Merge PR`, the merge request
returns `{"status":"queued"}`, the success notification appears, and the
accepted state suppresses the duplicate action.
- **Scenario:** an already queued PR exposes hydrated queue metadata. **File:**
`apps/web/e2e/tests/pr/pr-merge-queue.spec.ts`, display test. **What to
verify:** task icon color, task hover summary, compact popover, and detail
notice show queued state, position, and estimated duration.
- **Scenario:** the same accepted action is touch-usable. **File:**
`apps/web/e2e/tests/pr/mobile-pr-merge-queue.spec.ts`, action test. **What to
verify:** Review navigation, touch activation, queued notification, a
minimum 44px action target, and no document horizontal overflow.
- **Scenario:** an already queued PR is readable on a phone. **File:**
`apps/web/e2e/tests/pr/mobile-pr-merge-queue.spec.ts`, display test. **What to
verify:** the existing PR status drawer and full-height Review surface show
queued state, position, and estimate without hover or horizontal overflow.
## Verification Results
- Backend: `make -C apps/backend test ARGS='./internal/github/...'` passed; the
Make target executed the full backend `go test -tags fts5 ./...` suite.
- Frontend: 96 focused Vitest tests passed; `pnpm run i18n:check` and
`pnpm run typecheck` passed.
- Desktop E2E: `pnpm e2e:run --no-build tests/pr/pr-merge-queue.spec.ts`
passed (1 test).
- Mobile E2E: `pnpm e2e:run --no-build --project mobile-chrome
tests/pr/mobile-pr-merge-queue.spec.ts` passed (1 test).
Recorded after the remediation run:
- Backend: `cd apps/backend && go test -tags fts5
./internal/github/... ./internal/task/statussummary/...
./internal/backendapp` passed 2,193 tests across 3 packages, including the
queue precedence regression.
- Frontend: the six-file queue-status command passed 160 tests. `pnpm run
typecheck` and `pnpm run lint` passed. `pnpm run i18n:check` passed with
7,223 referenced keys, 8,779 English entries, 48 orphans, and all five
required catalogs complete.
- Desktop E2E: the fresh-build `cd apps/web && pnpm e2e:run
tests/pr/pr-merge-queue.spec.ts` passed 2 tests in 12.2 seconds. Mobile E2E:
`pnpm e2e:run --no-build --project mobile-chrome
tests/pr/mobile-pr-merge-queue.spec.ts` passed 2 tests in 9.6 seconds.
## Implementation Waves And Parallel Candidates
@@ -129,5 +192,11 @@ Wave 2:
Wave 3:
- [x] [task-03-desktop-mobile-e2e](task-03-desktop-mobile-e2e.md)
The detailed queue-observation task package under
`docs/plans/github-pr-merge-queue-status/` is the synchronized execution record
for the persistence, projection, queue color, metadata, and responsive display
work described above. Its E2E task and this parent plan intentionally record
the same two desktop and two mobile scenarios.
Execution is sequential in the primary conversation unless the user explicitly
authorizes subagents.
@@ -25,6 +25,11 @@ spec: "../../specs/github-pr-merge-queue/spec.md"
- `apps/backend/internal/github/noop_client.go`
- `apps/backend/internal/github/service_pr.go`
- `apps/backend/internal/github/controller.go`
- `apps/backend/internal/github/graphql.go`
- `apps/backend/internal/github/models.go`
- `apps/backend/internal/github/store.go`
- `apps/backend/internal/github/service_pr_watch.go`
- `apps/backend/internal/task/statussummary/projector_pr.go`
- Their focused `*_test.go` files
## Acceptance
@@ -35,6 +40,10 @@ spec: "../../specs/github-pr-merge-queue/spec.md"
including already-queued idempotency, and unknown results fail closed.
- The workspace-scoped HTTP endpoint returns the normalized outcome while
retaining auth routing, cache invalidation, validation, and error mapping.
- The existing GraphQL status sync observes queue state, one-based position,
and optional estimate; persistence preserves queue-unaware reads, clears
authoritative exits and terminal states, and the bounded task projection
exposes the queued state with multi-PR attention ranking.
## Verification
@@ -35,11 +35,15 @@ spec: "../../specs/github-pr-merge-queue/spec.md"
PR state, and prevent duplicate submission; rejected requests remain retryable.
- Desktop, compact, and mobile Review surfaces reuse the same mutation and
eligibility behavior with accessible, touch-usable controls.
- An active queue entry uses the dedicated `#966600` color before other
non-terminal review, check, draft, dirty, or behind states. A failing sibling
still wins multi-PR aggregation, terminal colors remain authoritative, and
future non-empty queue states use generic queued copy.
## Verification
```bash
cd apps && pnpm install --frozen-lockfile && pnpm --filter @kandev/web test -- lib/api/domains/github-api.test.ts components/github/pr-task-icon.test.ts components/github/pr-merge-button.test.tsx && cd web && pnpm run i18n:check && pnpm run typecheck
cd apps && pnpm install --frozen-lockfile && pnpm --filter @kandev/web test -- lib/api/domains/github-api.test.ts components/github/pr-task-icon.test.ts components/github/pr-merge-button.test.tsx components/github/pr-task-status-summary.test.ts components/github/pr-status-chip.test.tsx components/github/pr-merge-queue-status.test.tsx && cd web && pnpm run i18n:check && pnpm run typecheck
```
## Dependencies And Risks
@@ -52,12 +56,21 @@ cd apps && pnpm install --frozen-lockfile && pnpm --filter @kandev/web test -- l
## Results
- `pnpm --filter @kandev/web test -- --run lib/api/domains/github-api.test.ts components/github/pr-task-icon.test.ts` passed: 96 tests.
- `pnpm run i18n:check` passed with all supported catalogs complete.
- The six-file queue-status command passed 160 tests, including the queue
precedence, failing-sibling, and future-state fallback regressions. The
existing API and merge-button action tests remain covered by Task 02's
frontend suite.
- `pnpm run i18n:check` passed with 7,223 referenced keys, 8,779 English
entries, 48 orphans, and all supported catalogs complete.
- `pnpm run typecheck` passed.
- Review remediation keeps GitHub's overloaded `blocked` state visually neutral
and labels the pre-submit action `Merge PR`; only the accepted response claims
that GitHub added the PR to its merge queue.
- Queue state is checked after terminal state and before other non-terminal
states in both task-icon and compact-chip status derivation. Multi-PR status
ranking still lets a failing sibling dominate a queued sibling.
- Future provider queue enums map to the generic queued status rather than an
`Unknown` label.
- Queue feedback is driven by GitHub's terminal `enqueued` result, not
asynchronous `pending` acceptance.
- Focused terminal-outcome coverage passes for merged, queued, rejected, and
@@ -26,18 +26,24 @@ spec: "../../specs/github-pr-merge-queue/spec.md"
## Acceptance
- Desktop E2E proves merge-queue acceptance from the existing PR UI.
- Component coverage proves immediate merge feedback and duplicate-submission
suppression without duplicating those deterministic cases in Playwright.
- Mobile E2E reaches the same queued outcome through Review using touch and
verifies action size and absence of horizontal document overflow.
- The managed runner builds fresh backend/frontend artifacts and both focused
projects pass without retries masking failures.
- Desktop E2E has separate action and display scenarios. The action scenario
proves the existing PR UI exposes `Merge PR`, returns the queued API outcome,
shows the success notification, and suppresses the accepted action. The
display scenario proves task hover, compact popover, and detail notice expose
queued state, position, and estimated duration.
- Mobile E2E has separate action and display scenarios. The action scenario
reaches the queued outcome through Review using touch, verifies a minimum
44px action target, and checks the success notification. The display scenario
verifies the existing status drawer and Review surface expose queue metadata
without hover.
- Both display scenarios retain the absence-of-horizontal-document-overflow
assertion, and the managed runner builds fresh backend/frontend artifacts
before the focused projects pass without retries masking failures.
## Verification
```bash
cd apps && pnpm install --frozen-lockfile && cd web && pnpm e2e:run tests/pr/pr-merge-queue.spec.ts && pnpm e2e:run --project mobile-chrome tests/pr/mobile-pr-merge-queue.spec.ts
cd apps && pnpm install --frozen-lockfile && cd web && pnpm e2e:run tests/pr/pr-merge-queue.spec.ts && pnpm e2e:run --no-build --project mobile-chrome tests/pr/mobile-pr-merge-queue.spec.ts
```
## Dependencies And Risks
@@ -50,10 +56,15 @@ cd apps && pnpm install --frozen-lockfile && cd web && pnpm e2e:run tests/pr/pr-
## Results
- Desktop managed E2E passed with one discovered test.
- Mobile Chrome managed E2E passed with one discovered test, including the
touch action, minimum target height, and horizontal-overflow assertions.
- `pnpm run typecheck` passed after the final E2E helper and spec changes.
- Isolated desktop and mobile screenshots were captured under
`/tmp/kandev-merge-queue-screenshots-20260817/`; capture-only test hooks were
removed and both specs passed again afterward.
Recorded after the remediation run:
- Desktop managed E2E passed with two discovered tests in 12.2 seconds: the
merge action and the queued-status display scenario.
- Mobile Chrome managed E2E passed with two discovered tests in 9.6 seconds:
the Review merge action with the minimum target-height assertion and the
drawer/Review queue display scenario. Both retained the horizontal-overflow
assertion.
- The fresh-build desktop command was followed by the mobile `--no-build`
command, so both projects exercised the same newly built artifacts.
- Existing queue-status screenshots remain valid for the display scenario;
action coverage is behavioral and does not add capture assets.