Abort watchpr when a poll can no longer see the PR #12
Reference in New Issue
Block a user
Delete Branch "benvin/watchpr-terminal-errors"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A watched repo renamed, deleted, or made private mid-watch makes every poll 404 (Gitea hides invisible repos rather than 403ing), and the loop warned past it forever: the watcher looked healthy while reporting nothing. Transient failures had no cap either, so a wedged endpoint warned on every tick for the life of the process.
Reviewed the diff and confirmed the build/tests pass (
go build ./...,go test ./internal/agent/... -run TestWatchall green). PR body is within the convention cap. One substantive issue on the core design tension this PR is meant to resolve:404 handling isn't scoped to "PR no longer visible" — it's scoped to "any of three calls 404'd," with zero retry tolerance
FetchState(internal/agent/watch.go:23-48) makes three calls:GetPR,CommitStatus,ListComments. OnlyCommitStatus's 404 is filtered (!IsNotFound(err), line 32) — deliberately, since a squash/rebase merge deletes the head branch and that's genuinely benign (confirmedTestWatchDetectsMergeWhenCommitGonestill holds for the right reason).GetPRandListCommentsboth propagate any error, including 404, unfiltered.Then in
Watch's poll loop (watch.go:119-122),IsNotFound(err)on whateverFetchStatereturned is treated as immediately terminal — no retry, no counting towardMaxPollFailures, unlike every other error class (500/502/503/timeout/reset), which gets 20 consecutive tries. So:ListComments(issues/N/comments) is bucketed identically to "the repo/PR is gone," even thoughGetPRfor the same number just succeeded moments earlier in the same poll. That's not "the tracked PR is invisible," that's one endpoint blipping.Suggest scoping the immediate-abort path to the
GetPR404 specifically (that's the actual identity check for "is this PR still visible"), and either droppingListComments's error to a warning-and-continue likeCommitStatus, or at minimum requiring 2+ consecutive 404s before declaring a PR gone rather than aborting on the first one.Minor nit: the
MaxPollFailuresdoc comment says the cap "rides out a 20-minute outage," but abort fires on the 20th consecutive failed tick — ~19 elapsed intervals (19 min at the default 60s) after the first failure. Not a functional bug, just imprecise wording.Everything else checks out: the failure cap is genuinely per-ref (keyed by
ref.String()), resets on success before the meaningful-change check, off-by-one is consistent with the stated "20 tries," and the two new abort tests would catch a revert of either condition while the two survival tests guard against over-correction. Diff is atomic — no auth-handling or--intervalchanges bundled in.