fix(review): make listPullRequestFiles order deterministic to stabilize content fingerprints - #4481
Conversation
…ze content fingerprints listPullRequestFiles had no ORDER BY, so row order was whatever the query planner returned -- not guaranteed stable across repeat calls for the same unchanged PR. buildUnifiedReviewDiff only fully orders files by (priority bucket, added-line count); files tied on both fall through to this function's own order, so an unstable order silently reorders the diff string and flips any hash built from it. Confirmed live: JSONbored/metagraphed#4532 re-ran its linked-issue-satisfaction LLM call 12 times across 7 hours on one unchanged head SHA, despite a matching cache row already existing, because the fingerprint (which includes the diff text) never matched between passes. Adds an explicit ORDER BY path (unique per repo+pull per the table's own index, so no secondary tie-break is needed) and a regression test pinning the deterministic order.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4481 +/- ##
=======================================
Coverage 94.03% 94.03%
=======================================
Files 420 420
Lines 37521 37521
Branches 13701 13701
=======================================
Hits 35282 35282
Misses 1583 1583
Partials 656 656
🚀 New features to boost your workflow:
|
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-09 21:53:15 UTC
⏸️ Suggested Action - Manual Review
Review summary Nits — 5 non-blocking
Concerns raised — review before merging
Review context
Contributor next steps
Signal definitions
🟩 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.
|
… file-listing fix listPullRequestFiles now returns files in path-ascending order (previous commit). This test's fixture seeded files as [src/a.ts, README.md] and asserted that exact (insertion) order, which only happened to match the old undefined query order by coincidence -- README.md sorts before src/a.ts alphabetically. Full unsharded suite confirmed this was the only test relying on the old order (12844 passed).
…on queries (#4501) (#4560) Two queries in repositories.ts ordered by a timestamp column alone with no secondary tiebreak, the same bug class already fixed in listPullRequestFiles (#4481): same-millisecond ties under concurrent writes make row order (and therefore which rows survive a cap) query-plan-dependent instead of deterministic. Adds an id tiebreak to the product-usage daily rollup's main and retention scans, and to review-suppression's eviction and read queries, matching the established desc(id) convention elsewhere in this file.
Summary
listPullRequestFiles(src/db/repositories.ts) had noORDER BY, so row order was whatever the query planner returned — not guaranteed stable across repeat calls for the same unchanged PR.buildUnifiedReviewDiffonly fully orders files by(priority bucket, added-line count); files tied on both (common — e.g. multiple source files with 0 net additions) fall through to this function's own (previously undefined) order.linkedIssueSatisfactionCacheInputFingerprintand similar), so a silent reorder alone changes the hash and defeats caches even though the diff's actual content never changed.JSONbored/metagraphed#4532re-ran its linked-issue-satisfaction LLM call 12 times across 7 hours on one unchanged head SHA, despite a matching cache row already existing (496 rows total in that cache table, 0 recorded hits ever) — the PR's own title/body and its linked issue's title/body were both unedited during that window (verified via the GitHub timeline API), ruling out a legitimate content change as the cause..orderBy(pullRequestFiles.path).pathis unique per(repoFullName, pullNumber)per the table's own unique index, so it alone is a total, stable order — no secondary tie-break needed.Scope
type(scope): short summaryConventional Commit format.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
npm run typechecknpx vitest run test/unit/backfill.test.ts test/unit/backfill-file-hydration-scoping.test.ts test/unit/data-spine.test.ts test/unit/queue.test.ts test/unit/repository-settings-linked-issue-satisfaction.test.ts(1002 passed)npm run test:coveragenot re-run unsharded locally for this diff; relying on CI's full gate given the change is a single-line, well-covered, low-surface-area fix (one new.orderBy()call).If any required check was skipped, explain why:
Safety
Notes
ai_review/ai_slop's own cache hit rates (both build diffs through the samebuildAiReviewDiff/buildUnifiedReviewDiffpath), though those two also have upstream freeze/pause gates as a primary defense, so the practical impact there is smaller.linked_issue_satisfactionhas no such upstream gate today and relies entirely on this fingerprint cache, which is why it was fully exposed to this bug.