Files
kandev/apps/backend/internal/github/AGENTS.md
T
2026-09-10 23:39:56 +01:00

56 lines
2.9 KiB
Markdown

# GitHub PR status synchronization
Apply these rules to watch identity, PR lifecycle persistence, and batched lookup changes.
Paths and symbols refer to this package unless a path starts with `apps/`.
## Watch identity
A `github_pr_watches` row is unique per session, repository, and branch.
Once a watch finds a PR, it remains that PR's synchronization handle.
Both the poller and on-demand synchronization iterate these watches.
On branch switches, re-point only a searching watch (`pr_number=0`) for the same repository.
Otherwise, add a watch for the new branch.
Apply this rule in `resetPRWatchForBranchSwitch` and `syncPRWatchBranch`.
Retain one searching watch per session/repository and one watch per discovered PR.
## Lifecycle persistence
Watches cannot cover every task PR because sessions can disappear and users can link PRs by URL.
Keep the orphan sweep in `service_pr_unwatched.go`.
It reconciles unwatched `github_task_prs` rows and writes lifecycle fields,
the current `head_sha`, and stored `workflow_attention` when already present.
Exclude terminal and detached rows to bound the sweep.
Actions workflow reads belong to watched sync and feedback paths; the orphan
sweep does not collect new workflow evidence. Check and review aggregates belong
to the watch-driven path that fetches their evidence.
The REST PR response alone cannot supply those aggregates.
The backend is the only writer of `github_task_prs`.
The feedback read persists through `SyncTaskPR` in `service_pr_feedback_sync.go`.
Its `github.task_pr.updated` event updates every frontend surface.
Do not patch lifecycle fields only in a frontend store copy.
Keep both derivations on `newPRStatus`.
Persist inside the TTL cache's fetch closure so a cache hit causes no write.
Log persistence failures without failing the feedback read.
Use workspace-scoped `ListTaskPRsByPRNumber` to match the authorized credential scope.
`resolveTerminalMergeState` prevents a merged PR from leaving `merged`.
Do not extend this rule to `closed`: GitHub permits `closed -> open`.
## Batched lookup budget
An alias with zero nodes definitively means no open PR on that branch.
Carry this result through `branchBatchResult.ResolvedEmpty` to `applyBatchedSearchingWatch`.
Do not repeat that lookup with `client.FindPRByBranch`.
After a definitive negative result, only the unqueried fork parent needs another lookup.
Cache fork identity with `forkParentRepositoryForLookup` per credential scope, owner, and repository.
Two or more open PRs are ambiguous, not a definitive negative result.
For ambiguity or an unresolved alias, retain the full fork-network fallback.
Throttle this production batched path with `last_checked_at` and `PRSyncFreshnessWindow`, as `triggerPRDetection` does.
For lookup changes, run `service_pr_watch_batched_budget_test.go` coverage.
Retain call-count assertions: a correct final `PRStatus` cannot detect duplicate API requests.