57 lines
4.1 KiB
Markdown
57 lines
4.1 KiB
Markdown
---
|
|
spec: docs/specs/tasks/requirements/multi-branch.md
|
|
created: 2026-08-12
|
|
status: complete
|
|
---
|
|
|
|
# Implementation Plan: Stable PR Changes Refresh
|
|
|
|
## Overview
|
|
|
|
The PR Changes row flickers because `useActiveTaskPRsWithFiles` includes `last_synced_at` in its request key and prunes the prior key before the replacement request resolves. Preserve the last resolved files for the same logical workspace/task/PR while refreshing, then replace them atomically when the current response lands. Scope changes and removed PRs must continue to clear stale data.
|
|
|
|
## Frontend
|
|
|
|
### PR file refresh cache
|
|
|
|
- Update `apps/web/hooks/domains/github/use-active-task-pr-files.ts` so request invalidation and display identity are separate: `last_synced_at` still triggers one new request, while the last resolved files remain readable under the current PR until that request settles.
|
|
- Preserve the existing workspace response guard and garbage collection for removed PRs. Do not retain files across workspace changes, task changes, PR removal, or a different logical PR.
|
|
- Keep `apps/web/components/task/changes-panel-body.tsx` and its desktop/mobile composition unchanged. Stabilizing hook output prevents `hasPRFiles` from oscillating, so the existing `PRFilesSection` stays mounted and preserves user collapse state.
|
|
|
|
## Tests
|
|
|
|
- **What:** After an initial PR file response resolves, advancing `last_synced_at` starts one refresh and leaves the prior files observable until the replacement resolves.
|
|
- **File:** `apps/web/hooks/domains/github/use-pr-workspace-scope.test.ts`
|
|
- **How:** Render the hook with a deferred second WebSocket response; assert the old file remains during the pending interval and is atomically replaced afterward.
|
|
- **What:** Workspace/task/PR scope changes and PR removal never reuse retained files.
|
|
- **File:** `apps/web/hooks/domains/github/use-pr-workspace-scope.test.ts`
|
|
- **How:** Extend the existing deferred-response coverage with same-workspace task/PR removal cases as needed by the chosen cache shape.
|
|
- **What:** A failed background refresh retains resolved files, while an initial failure remains empty.
|
|
- **File:** `apps/web/hooks/domains/github/use-pr-workspace-scope.test.ts`
|
|
- **How:** Reject a controlled replacement request after the initial response resolves and assert the stable list remains observable.
|
|
|
|
## E2E Tests
|
|
|
|
No new Playwright scenario is planned. This repair changes only hook-level cache normalization and deliberately leaves layout, touch behavior, scrolling, navigation, and viewport composition unchanged. The existing `apps/web/e2e/tests/task/mobile-changes-panel.spec.ts` covers the mobile PR Changes surface; the deferred refresh race is deterministic and more reliably proven at hook level than through the polling fixture.
|
|
|
|
## Verification Results
|
|
|
|
- `cd apps && pnpm install --frozen-lockfile` passed and installed the fresh-worktree dependencies.
|
|
- RED: the deferred timestamp-refresh test failed because `filesByPRKey` became empty before the replacement response resolved.
|
|
- RED: the controlled refresh-rejection test failed because the settled error replaced retained files with an empty list.
|
|
- `cd apps && pnpm --filter @kandev/web test hooks/domains/github/use-pr-workspace-scope.test.ts && pnpm --filter @kandev/web lint && pnpm --filter @kandev/web typecheck` passed: 5 tests, zero lint warnings, and clean TypeScript compilation.
|
|
- Review remediation: a reverse-order T2/T3 regression failed before the desired-key guard because late T2 replaced T3, then the same test passed after superseded success/failure handlers were rejected. The focused suite now passes 6 tests with lint and typecheck clean.
|
|
|
|
## Implementation Waves And Parallel Candidates
|
|
|
|
Sequential:
|
|
|
|
- [x] [task-01-stabilize-pr-file-refresh](task-01-stabilize-pr-file-refresh.md)
|
|
|
|
No parallel candidates. The implementation and regression test exercise one hook contract.
|
|
|
|
## Risks
|
|
|
|
- Retaining by an identity that is too broad can leak files across task, workspace, repository, or PR switches. The regression test must cover those invalidation boundaries.
|
|
- Retaining by the timestamped request key recreates the flicker. Request freshness and displayed-data identity must be modeled separately.
|