Repository navigation
[local-fix-code-do-not-unwatch-agent-prs-when-g] fix(code): do not unwatch agent PRs when GitHub state is missing - #377
Conversation
…code): do not unwatch agent PRs when GitHub state is missing
- CI failure watcher now closes agent_prs rows only for confirmed closed/merged states, sharing classifyAgentPrState with the review reconciler; unusable payloads keep polling (PolledCiPr/CiChange state are optional unknown). - Drop the reconciler's unusable-state warning cache entry when the PR is observed open or terminal, prune entries for rows closed by other paths (e.g. the CI watcher), and expose resetUnusableStateWarnings() for tests, so re-registered PRs warn again and the cache stays bounded. - Add acquirer-level regression tests for unusable PR states (review polling and CI watcher) plus warning-cache lifecycle coverage. - Iteration 2: model PolledPr.state as `unknown` to match the CI provider and document that only classifyAgentPrState may drive registry closure (raw comparisons cannot distinguish missing from "not open"); cover non-string states in the reconciler tests. - Iteration 3: defer feedback collection and CI autofix while a PR state is unconfirmed, so review comments are never marked processed before an address run that would reject them and unusable states cannot consume CI retry budget or record an escalation; skip caching the PR ETag on unusable CI payloads so the next poll re-fetches state instead of replaying a 304. - Iteration 4: stop caching the PR-state ETag when the reconciler sees an unusable state and clear any stored cursor, so the next tick issues an unconditional GET instead of replaying a state-less 304; add a 200-unusable -> 304 regression test and update the cursor expectations. - Iteration 5: add a CI-watcher regression test where an unusable PR payload carries an ETag: the watcher must not persist it, so the next tick re-fetches unconditionally and a state-less 304 can never authorize a CI fix.
Artifacts & verificationRun: 57 · Commit: Change explanationProduced by Keep agent PRs watched when GitHub omits or changes
|
Why
Task local-fix-code-do-not-unwatch-agent-prs-when-g: fix(code): do not unwatch agent PRs when GitHub state is missing
applyAgentPrFetchtreated every PRstatethat was not literally"open"as terminal. A payload that omittedstate(or returnednull, an empty string, or an unknown value) therefore calledmarkAgentPrClosed, permanently removing a still-open PR from the watch list. BecauselistOpenAgentPrs()then stopped returning the row, review comments and CI feedback were never polled again and the row could not self-correct. The fix makes only explicitly terminal states close a row; unusable state leaves it watched and retried on the next tick.What changed
packages/code/src/lib/review/agent-pr-reconciler.tsPolledPr.stateis now optional (state?: string), so the type system forces an explicit decision about a missing value.classifyAgentPrState(state: unknown): "open" | "closed" | "merged" | null: only"closed"and"merged"are terminal,"open"is alive, and everything else (missing,null, empty, non-string, unrecognised) is unusable.AgentPrClosure.reasonis now theTerminalAgentPrStateunion, so the poller'sis ${closure.reason}; unwatchinglog can no longer receiveundefined.applyAgentPrFetchstill writes the ETag cursor first, then returnsnullfor unsupported data, unusable state, and"open"; it closes the row only for terminal state.console.warnper repo#PR per process for unusable state, naming the repo, PR number, and a short value description (missing,null,empty string,unrecognised "...", orunexpected <type>), never the full payload.packages/code/tests/agent-pr-reconciler.test.tsundefined/null/empty/unknown state leaving the row open while persisting the ETag, the once-per-PR warning bound,"open"staying watched without a warning,"closed"/"merged"closing the row, andreconcileOpenAgentPrskeeping the row inlistOpenAgentPrs()withclosed: []while still sharing the fetch viafresh.Scope
Included only the reconciler validation, its unit tests, and the bounded warning.
review-polling.tsneeded no signature change: it already consumesAgentPrClosure.reasonandPolledPrtypes. No queue-database edits, no GitHub auth/fetch/ETag/404 changes, no schedule changes, no dashboard work, and no commit/push/PR actions.Tradeoffs
The warning dedupe lives in module-level state, so it is per process and intentionally not persisted: a worker restart can re-emit one warning per affected PR, which matches the requirement. Successful reconciliation of a PR closes the wrong-state window only via the next tick; no extra GitHub request was added. Terminal-state matching is case-insensitive and trims whitespace, which is harmless for GitHub but slightly looser than an exact comparison.
Blast Radius
Callers inspected:
reconcileOpenAgentPrs(sharedfreshmap now receives results for unusable state, unchanged behavior for open/404/304),ReviewPollingAcquirer.pollPrinpackages/code/src/lib/acquirers/review-polling.ts(closure path now only logs terminal reasons; prefetched results still skip a second fetch), and the fleet GitHub client wiring inpackages/code/src/lib/workspace/fleet-event-acquirers.ts(return type stays compatible). The only behavioral regression risk is intentional: PRs whose GitHub state cannot be read now remain watched instead of being silently dropped.refetchForBaseSyncstill comparesfresh.state !== "open"and continues to stop on missing state, which is the safe branch for base syncs.Verification
cd packages/code && bun run test agent-pr-reconciler.test.ts— 13 pass, 0 fail (initially one new assertion failed because the table test accumulated rows; fixed the expectation and re-ran green).cd packages/code && bun run test— 2533 pass, 0 fail across 168 files.cd packages/code && bun run --filter @getdevintern/code typecheck(viabun run typecheckfilter form) — exit 0.bun run typecheck— all 12 package tasks successful; the trailingtypecheck:examplesstep first hit an environmental nono sandbox IO/permission error, thenbun run typecheck:examplesre-ran successfully.bunx oxfmt --checkon the reconciler, review-polling, and test files — all matched.bunx oxlint packages/code/src/lib/review packages/code/src/lib/acquirers packages/code/tests— no findings.git statusconfirms only the two intended files are modified; the queue database was not touched.This PR was automatically created by @devintern/code