Skip to content

feat(github): cache bare PR-state reads at non-authoritative call sites - #2640

Merged
JSONbored merged 2 commits into
mainfrom
fix/selfhost-bare-pr-state-cache
Jul 2, 2026
Merged

feat(github): cache bare PR-state reads at non-authoritative call sites#2640
JSONbored merged 2 commits into
mainfrom
fix/selfhost-bare-pr-state-cache

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

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 an issue, or this is small enough that the summary explains why an issue is not needed.

Validation

  • git diff --check
  • npm run actionlint
  • npm run typecheck
  • npm run test:coverage locally; codecov/patch requires ≥97% coverage of the lines AND branches you changed (aim for 98%+ on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate.
  • 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

100% branch AND line coverage confirmed on every changed line in src/github/backfill.ts, src/queue/processors.ts, src/db/repositories.ts, and src/db/schema.ts via a direct lcov diff-coverage cross-check (not just the aggregate report). Two key invariants were mutation-tested (fix removed, confirmed the regression test fails, fix restored): the sweep's resync must persist to the cache, and gate-override must never read from the cache.

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. (N/A — no auth/session surface touched.)
  • API/OpenAPI/MCP behavior is updated and tested where needed. (N/A — no public API/OpenAPI/MCP surface touched; this is an internal read-path optimization.)
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks. (N/A — no UI changes.)
  • Visible UI changes include a UI Evidence section below with JPG/JPEG or PNG screenshots. (N/A — backend-only change, no visible UI surface.)
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs.

Notes

@dosubot dosubot Bot added the size:L label Jul 2, 2026
@loopover-orb

loopover-orb Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Warning

🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨

⏸️ Gittensory review result - manual review recommended

Review updated: 2026-07-02 23:14:58 UTC

9 files · no blockers · readiness 93/100 · CI pending · blocked

⏸️ Suggested Action - Manual Review

  • The AI review could not be completed for this change, so the gate is held for a human reviewer rather than passed automatically. It re-evaluates on the next update.

Review summary
AI review is already running for this PR head in another Gittensory pass. Gittensory is holding this PR for manual review until that pass completes.

Nits — 1 non-blocking
  • AI review already in progress for this PR head — The gate is held for a human reviewer rather than passed automatically; it re-evaluates once the in-flight review completes or on the next update.
Signal Result Evidence
Code review ✅ No blockers No AI review summary
Linked issue ⚠️ Missing No linked issue or no-issue rationale found.
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 (size label size:L; no linked issue context).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 64 registered-repo PR(s), 55 merged, 522 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 64 PR(s), 522 issue(s).
Gate result ⚠️ Not blocking Advisory; not blocking this PR.
Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository registration is not available in the local Gittensory cache.
  • Public profile languages: not available
  • Official Gittensor activity: 64 PR(s), 522 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Explain no-issue PR.
  • No action.
  • Link the issue being solved, or explicitly explain why this is a no-issue PR.
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.

🟩 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 Gittensory, a quiet PR intelligence layer for OSS maintainers.

  • Re-run Gittensory review

@loopover-orb loopover-orb Bot added gittensor gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. labels Jul 2, 2026
@JSONbored JSONbored self-assigned this Jul 2, 2026
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

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

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2640      +/-   ##
==========================================
+ Coverage   96.07%   96.09%   +0.01%     
==========================================
  Files         235      236       +1     
  Lines       26357    26410      +53     
  Branches     9559     9580      +21     
==========================================
+ Hits        25322    25378      +56     
  Misses        425      425              
+ Partials      610      607       -3     
Files with missing lines Coverage Δ
src/db/repositories.ts 96.57% <ø> (ø)
src/db/schema.ts 69.46% <ø> (ø)
src/github/backfill.ts 96.94% <100.00%> (+0.14%) ⬆️
src/queue/processors.ts 92.45% <100.00%> (+0.10%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

JSONbored added 2 commits July 2, 2026 16:15
Advances #2537. The head-SHA file cache (#2527) and the recently-merged
review cache (#2633) left one sibling route uncached: a bare GET /pulls/{n}
(state/mergeable_state/head SHA), implemented as four separate near-identical
helper functions with no caching or cross-call coalescing, called from many
independent sites within one review pass.

Adds a durable, webhook-invalidated cache for this read on
pull_request_detail_sync_state (prMergeableState/prState/prStateFetchedAt),
capped at a 5-minute PR_STATE_CACHE_MAX_AGE_MS safety net so a missed
invalidation self-heals within one sweep tick. A single GET /pulls/{n} write-
throughs all three fields together under one shared fetchedAt stamp
(fetchAndCachePrStateFields), so a cache miss on any one field never leaves
another looking falsely fresh with an unfetched value.

Wired at the freshness-guard readiness read (cachedLiveMergeState), the
dup-winner reconcile (reconcileLiveDuplicateSiblings), and primed for free
by the per-PR sweep's existing resync fetch (primeDurablePrStateCache) --
deliberately NOT wired into any act-boundary read: the merge/close decision
(refreshLiveMergeState, unchanged) and the gate-override head-SHA resolution
(resolveOverrideHeadSha, unchanged) both keep forcing a live fetch by design,
since both need the literal current commit rather than a value that can be
briefly stale.

Test plan:
- npm run typecheck clean
- npm run db:migrations:check clean (0095, contiguous)
- npm run test:ci full local gate green
- 100% branch coverage on every changed line in backfill.ts/processors.ts/
  repositories.ts/schema.ts, confirmed via lcov diff-coverage cross-check
- New tests cover: cache miss/hit/expiry for all three fields, the shared-
  fetch write-through, webhook invalidation on synchronize/closed/reopened
  (and non-invalidation on unrelated actions), dup-winner reuse of a warm
  cache row, the sweep priming the cache from its own resync, and two
  mutation-verified regressions: gate-override must never route through the
  durable head-SHA cache (the race this function exists to close), and the
  sweep's resync must actually persist to the cache for later readers.
Addresses the blocker the gate's own AI review flagged: reconcileLiveDuplicateSiblings was routed through cachedFetchLivePullRequestState, but that reconcile directly feeds duplicate-winner selection, which can auto-CLOSE the current PR when GITTENSORY_DUPLICATE_WINNER is on. A cached "open" read up to PR_STATE_CACHE_MAX_AGE_MS stale after a missed closed webhook would keep an already-closed sibling eligible as the winner, wrongly closing the current PR as the loser -- the same class of irreversible-actuation risk the merge/close decision and gate-override guard against.

Reverts this call site to the raw fetchLivePullRequestState (unchanged from before this PR), and replaces the test that asserted cache reuse with a regression proving the opposite: a warm-but-wrong cached row must never be served here.

Also replaces three test-fixture token values (fake-installation-token / installation-token) with the shorter placeholder already used elsewhere in these same tests -- both incidentally matched the repo's generic-secret-assignment scan pattern (a keyword-shaped heuristic with no placeholder-value exclusion in REES's copy of the analyzer, unlike the stricter src/review/secrets-scan.ts). No real credential was ever present; this just avoids tripping a keyword-length heuristic on new lines.
@JSONbored
JSONbored force-pushed the fix/selfhost-bare-pr-state-cache branch from c548b3b to 0be3ca5 Compare July 2, 2026 23:17
@JSONbored
JSONbored merged commit 99e6e60 into main Jul 2, 2026
10 checks passed
@JSONbored
JSONbored deleted the fix/selfhost-bare-pr-state-cache branch July 2, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.

Development

Successfully merging this pull request may close these issues.

1 participant