Skip to content

fix(backfill): stop recording a resume cursor the sampled segment can never consume - #10238

Merged
loopover-orb[bot] merged 1 commit into
mainfrom
fix/backfill-sampled-cursor-10209
Jul 31, 2026
Merged

fix(backfill): stop recording a resume cursor the sampled segment can never consume#10238
loopover-orb[bot] merged 1 commit into
mainfrom
fix/backfill-sampled-cursor-10209

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

recent_merged_pull_requests recorded a nextCursor that nothing could ever read.

It is the only segment using progressiveHistory, and the only one whose terminal status is sampled. Three independent gates make that status unresumable:

  1. complete && hasMore maps to sampled, never running — so the status that would mean "more pages pending" is never produced for this segment.
  2. canResumePreviousScan accepts only running / partial / waiting_rate_limit. sampled is absent, so both previous.nextCursor and an explicitly passed cursor are ignored and startPage falls back to 1.
  3. The automatic mode: "resume" re-send is scoped to labels / open_issues / open_pull_requests, and the scheduled cron only dispatches light or full.

Confirmed on edge-nl-01 before the change — a resume run with an explicit cursor: "11" against a segment sitting at next_cursor=11:

{"status":"sampled","fetchedCount":1758,"expectedCount":3588,"nextCursor":"11"}

fetchedCount unchanged, nextCursor still 11. It re-crawled pages 1–10 and persisted nothing new.

Which option this takes, and why

#10209 offered two. This is option 2: accept the rolling-window design and remove the misleading bookkeeping, rather than making sampled resumable.

Option 1 would build machinery to satisfy a claim no caller makes. Every consumer reads through listRecentMergedPullRequests, which is ORDER BY merged_at DESC LIMIT 200 — nothing asks for the deep history, so nothing would benefit from being able to walk it. The stored cursor's only effect today is to invite a reader to conclude the crawl is advancing when it structurally cannot.

What the segment actually is, now stated in the code: a bounded window over the most-recently-updated closed PRs, re-crawled from page 1 each run, whose coverage grows by accretion as the sort=updated window slides, and is trimmed by the 30-day updated_at retention in src/db/retention.ts. That is a defensible design. Recording a continuation position for it is not.

expectedCount is deliberately kept. "This window holds N of the M closed PRs GitHub reports" is a true and useful coverage statement; it only misleads when read as progress toward M, which is exactly what the now-absent cursor signals.

No behaviour change to the crawl

sampled is not a fresh status (isFreshSegmentStatus is complete / not_modified only), so conditionalRequestForSegment already returned undefined for these rows regardless of the cursor. The 304 conditional-request fast path is untouched, and no page is fetched or skipped differently.

Closes #10209

Scope

  • The PR title follows type(scope): short summary Conventional Commit format, for example fix(api): restore profile access checks.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked a currently open issue this PR resolves (e.g. Closes #123) — a linked open issue is required for every contributor PR.

Validation

  • git diff --check
  • npm run actionlint
  • npm run typecheck
  • npm run test:coverage locally; codecov/patch requires ≥99% coverage of the lines AND branches you changed
  • npm run test:workers
  • npm run build:mcp
  • npm run test:mcp-pack
  • npm run ui:openapi:check
  • npm run ui:lint
  • npm run ui:typecheck
  • npm run ui:build
  • npm audit --audit-level=moderate
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries

Detail:

  • Full suite: 26,597 passed, 0 failed.
  • The diff has exactly one executable changed line (nextCursor = undefined); everything else is comment. Verified against lcov line-by-line: that line has 3 hits, and no changed line is uncovered.
  • Mutation-tested: removing the assignment fails both new regression tests.
  • Drift sweep green: db:migrations:check, db:schema-drift:check, selfhost:env-reference:check, docs:drift-check, coverage-boltons:check, dead-exports:check, manifest:drift-check.
  • Unchecked boxes cover surfaces this diff does not touch (no workflow, MCP, UI, binding or schema change) and are left to CI. npm audit reports only pre-existing advisories transitive under release-please; this PR changes no dependencies.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests.
  • API/OpenAPI/MCP behavior is updated and tested where needed.
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks.
  • Visible UI changes include a UI Evidence section below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails.
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs.

The /v1/internal/jobs/backfill-repo-segment/run response drops nextCursor for this segment, which is the point — it previously reported a continuation that did not exist. No other field changes shape.

UI Evidence

Not applicable — no visible UI, frontend, docs, or extension change.

Notes

The defect is latent, not user-visible, which is why #10209 was filed separately from #10203 rather than folded into it. It bounds how much history the table can ever hold and makes the cursor/expectedCount bookkeeping misleading to anyone reasoning about coverage — including the 2026-07-10 → 2026-07-23 hole #10193 opened, which no supported path can backfill. This PR does not change what is reachable; it stops the stored row claiming otherwise. Widening the window, if that is ever wanted, is a separate decision with a real GitHub-cost tradeoff.

… never consume

recent_merged_pull_requests is the only progressiveHistory segment and the only one
whose terminal status is 'sampled'. Three independent gates make that status
unresumable: complete+hasMore maps to 'sampled' rather than 'running';
canResumePreviousScan accepts only running/partial/waiting_rate_limit, so both a
stored nextCursor and an explicitly passed cursor are ignored and startPage falls
back to 1; and the automatic resume re-send is scoped to labels/open_issues/
open_pull_requests while the cron only dispatches light/full.

So the nextCursor this segment faithfully recorded was written and never read.
Confirmed on edge-nl-01: a resume run with an explicit cursor '11' against a segment
at next_cursor=11 re-crawled pages 1-10, persisted nothing new, and handed back the
same cursor it started with.

Takes the second of the two options on #10209: accept the rolling-window design and
remove the misleading bookkeeping, rather than making 'sampled' resumable. Nothing
consumes the deep history -- every reader goes through listRecentMergedPullRequests,
which is ORDER BY merged_at DESC LIMIT 200 -- so option 1 would build machinery to
satisfy a claim no caller makes.

expectedCount is deliberately kept: 'this window holds N of the M closed PRs GitHub
reports' is a true coverage statement. It only misleads when read as progress toward
M, which is exactly what the now-absent cursor signals.

No behaviour change to the crawl itself: sampled is not a fresh status, so
conditionalRequestForSegment already returned undefined for it regardless of the
cursor, and the 304 fast path is untouched.

Closes #10209
@loopover-orb

loopover-orb Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-31 14:17:06 UTC

2 files · 1 AI reviewer · no blockers · readiness 95/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This PR removes the `nextCursor` write in the `sampled` branch of `fetchPagedSegment` (backfill.ts:1819-1836), on the well-argued premise that a `sampled`-status segment can never resume from that cursor: `canResumePreviousScan`-equivalent gating (per the PR's own trace) only accepts running/partial/waiting_rate_limit, and the automatic resume path is scoped to labels/open_issues/open_pull_requests only. The fix is a one-line change (`nextCursor = undefined`) directly at the point of production, matching the 'wrong-layer fix' anti-pattern's opposite — this is the correct-layer fix. The new tests exercise the real `backfillRepositorySegment` end-to-end path (not a fabricated payload) and the second test empirically confirms the claimed behavior (explicit cursor '11' is ignored, crawl restarts at page 1), which is a live-verified regression test rather than a synthetic one. `expectedCount` is deliberately preserved, which is consistent with the PR's stated reasoning that it's a true coverage statement independent of the cursor.

Nits — 6 non-blocking

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #10209
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 9 registered-repo PR(s), 8 merged, 299 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 9 PR(s), 299 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Addressed
The issue explicitly offers option 2 (accept the rolling-sample design and stop recording a nextCursor that can never be consumed) as a defensible resolution, and the PR implements exactly that: it clears nextCursor on the 'sampled' terminal status while keeping expectedCount, with regression tests verifying the cursor is no longer stored and that resume dispatches restart at page 1 as documented.

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: not available
  • Official Gittensor activity: 9 PR(s), 299 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Then work through the remaining 1 step in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask <question> answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat <question> answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@JSONbored JSONbored self-assigned this Jul 31, 2026
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.38%. Comparing base (ff28627) to head (a62221b).
⚠️ Report is 5 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #10238      +/-   ##
==========================================
- Coverage   92.25%   91.38%   -0.87%     
==========================================
  Files         938      938              
  Lines      114659   114660       +1     
  Branches    27680    27680              
==========================================
- Hits       105774   104781     -993     
- Misses       7580     8769    +1189     
+ Partials     1305     1110     -195     
Flag Coverage Δ
backend 94.13% <100.00%> (-1.55%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/github/backfill.ts 96.08% <100.00%> (+<0.01%) ⬆️

... and 3 files with indirect coverage changes

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit e28d90b into main Jul 31, 2026
8 checks passed
@loopover-orb
loopover-orb Bot deleted the fix/backfill-sampled-cursor-10209 branch July 31, 2026 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(backfill): progressive history never progresses — 'sampled' is unresumable, so recent_merged_pull_requests' nextCursor is written and never read

1 participant