perf(tracker): tail the PR-history walks — per-branch done-signal, windowed listings #179
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/coding-lab!179
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/176"
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?
Problem (#176)
Everything touching the forge slowed as PR history grew, forever.
Tracker.Pulls()listed every PR the repo ever had —state=all, 50/page, sequentially until an empty page — and two hot paths ran that walk: the AFK reaper once per repo per tick (854 walks in 17 h, only to ask "does an open-or-merged PR exist for this run's branch"), andlabctl pr list(6.7 s measured while the reaper's own request stream loaded the forge). TheIssues(closed|all)views had the same unbounded shape.Change
Done-signal →
PullsForHead(head, base)— a new seam method on all three backends, one bounded read per active run per tick (O(active runs), independent of history), with its ownpulls_for_headmetrics op:GET /pulls/{base}/{head}fast path (branch names path-escaped —afk/Ntravels as one segment). Two live-verified quirks pinned in tests: a merged PR whose branch was deleted renders a syntheticrefs/pull/N/head, soHeadBranchis filled from the queried name; and the upstream lookup has no ORDER BY, so only a closed-unmerged answer (which could shadow a live sibling and falsely fail a run) pays for a fallback walk — 404/open/merged stay one request.head=owner:branchfilter (owner prefix mandatory) + defensive client-side re-filter.Semantics preserved exactly:
DonePull/PullStateremain the single collision authority (open > merged > closed; closed-unmerged is not a done-signal), conformance-tested with the same table across all three backends. The read is base-scoped (the basehandlePRCreatepins for every lab PR); the reaper gains per-run error isolation.Pulls()andIssues(closed|all)→ windowed: full open set + theRecentClosedWindow(50) most recently closed items (sort=recentclose/recentupdateon Forgejo,updated-desc on GitHub,number DESC LIMITon the builtin store). The walk-to-empty-page pattern (and its guaranteed wasted probe) survives only where the open working set bounds it. Request counts are pinned by tests.labctl pr listdocuments the window in its usage line.Docs: ADR-0048 records the decisions; ADR-0009's "Pulls are fetched in ALL states" pin gains a revision pointer; CONTEXT.md's done-signal relationship updated.
Acceptance criteria from the brief
PullsForHeadcalls, zeroPullscalls)pr listrequest count constant in history (test pins: forgejo 60-open repo ⇒ exactly 4 requests however deep the closed history)pr liststill shows all open PRs + recently merged window (documented in usage)pulls_for_head)Issues(state)walk bounded the same way (closed/all views)Verification
golangci-lint(0 issues) green;internal/tmuxxintegration failures are environmental (identical on clean HEAD in this sandbox — no tmux session spawn).pr listpattern = 2 requests / ~1.1 s constant; per-run done-signal fast path = 1 request / ~70 ms. Post-deploy,lab_tracker_requests_total{op="pulls"}should stop growing per tick in favor ofop="pulls_for_head".Closes #176
🤖 Generated with Claude Code
[autoland] verdict: reject
FAIL — the PR is sound on its own merits, but it no longer merges into
main, and the resolution is semantic, not mechanical. An autonomous lander must not pick a side on that.Verification signal relied on:
labctl pr checks 179 --wait→ aggregatesuccess(ci / native (pull_request), 6m20s, run 200). That green vouches for the branch tip as authored — it does not vouch for the merged tree, and the merged tree is where the problem is.What passes
perf(tracker): tail the PR-history walks — per-branch done-signal, windowed listings— Conventional Commits ✓Closes #176✓Issues/Pulls,pulls_for_headop, ADR + CONTEXT.md) — no drive-by changes ✓Blockers
mainadvanced by four merged PRs (#183, #184, #186, #187, #190) that rework the exact reaper path and tracker seam this PR touches.git merge origin/mainon the head branch conflicts:1.
internal/afk/reaper.go— semantic, both sides rewrote the same loop. This PR replaces the per-repotrk.Pulls(ctx)listing with a per-runtrk.PullsForHead(ctx, run.Branch, repo.DefaultBranch).main(#182/#181) kept the single listing and added verdict kinds on top of it:Resolving this is a design decision, not a merge: the bounded per-branch read has to be shown correct for the verdict kinds (whose PR pre-exists the run),
classifyAndClaim's new(done, escalated)signature has to meet this PR's per-run error isolation, and the twocontinue-on-unreadable paths have to compose. Escalating rather than guessing.2.
internal/afk/engine_test.go—fakeTrackerconflict (2 hunks). The fake must now serve both this PR'sPullsForHeadcounters/args andmain'sReviews/PullCommentsautoland reads. Falls out of (1); thepullsCallsmust-stay-zero assertion needs rechecking against the verdict-kind path.3.
internal/tracker/instrument_test.go—opOrder. Mechanical (unionOpPullsForHeadintomain's list, which addedOpReviews,OpRerequestReview,OpCommentPull,OpPullComments) — but it must matchdriveAll's order, so it lands with (1).4. ADR number collision — not a git conflict, so the merge will not catch it. This PR adds
docs/adr/0048-bounded-tracker-reads.md;mainalready shipsdocs/adr/0048-autoland-fix-forward.mdand0049-one-priority-ordered-spawn-pass.md. Renumber to 0050 and update the back-reference added indocs/adr/0009-tracker-seam-builtin-issues.mdplus anyCONTEXT.mdpointer.To hand back
Merge
origin/mainintoafk/176(merge, never rebase — the PR is open), resolve (1)–(3) with the verdict-kind interaction settled explicitly, renumber the ADR per (4), then re-run the full suite +golangci-linton the resolved tree — CI's current green predates all of this — andlabctl pr rerequest 179.[autoland] verdict: fix-done
[autoland] verdict: pass