Summary
PullRequestRecord (the type for OPEN PRs) has no changedFiles field, unlike
RecentMergedPullRequestRecord, which does. prItem() in src/signals/engine.ts (which converts an
open PR into a CollisionItem for the collision/related-work engine) never populates changedFiles,
while recentMergedItem() does.
The only place file paths are genuinely compared today, buildPreStartCheck(), is explicitly scoped to
merged history only — its own code comment says "Open PR records carry no file metadata in the
cache." It's wired only to an opt-in MCP tool and API route, never invoked automatically by the webhook
review pipeline.
The live per-PR review path (src/queue/processors.ts) calls buildCollisionReport() with no
recentMergedPullRequests argument and builds a buildPreflightResult() input that omits
changedFiles, even though the PR's diff has often already been resolved a few lines earlier for the
secret-scan/AI-review gates. The data model already has what's needed — the pull_request_files table
is populated per open PR by the routine detail-sync backfill, and listRepoPullRequestFilePaths can
already query file paths across an arbitrary PR-number set for a repo.
Net effect: two independently-open PRs touching the same file get zero warning from Gittensory's
"Related work" panel today — it reads "No same-issue or scoped active PR overlap found" for exactly
this case, wasting review cycles on work that will conflict.
Fix
Populate changedFiles on PullRequestRecord/prItem() from the pull_request_files cache so the
existing termOverlap()/collision-scoring machinery (which already tokenizes changedFiles for merged
PRs) gets real path signal for open-vs-open PR pairs too — not just title/label/linked-issue text.
Guarded by a same-author exclusion: a contributor's own two PRs sharing a file (follow-up / stacked PR)
must not be flagged as a collision — that's legitimate iteration, not duplicate work. The guard is
scoped specifically to matches driven by path terms; pre-existing title/label-overlap behavior between
same-author items (already shipped, already tested) is unchanged.
Flag-gated (GITTENSORY_OPEN_PR_FILE_COLLISION, default OFF) for the live-wiring rollout since this
touches the shared collision/preflight path several other gates depend on.
Summary
PullRequestRecord(the type for OPEN PRs) has nochangedFilesfield, unlikeRecentMergedPullRequestRecord, which does.prItem()insrc/signals/engine.ts(which converts anopen PR into a
CollisionItemfor the collision/related-work engine) never populateschangedFiles,while
recentMergedItem()does.The only place file paths are genuinely compared today,
buildPreStartCheck(), is explicitly scoped tomerged history only — its own code comment says "Open PR records carry no file metadata in the
cache." It's wired only to an opt-in MCP tool and API route, never invoked automatically by the webhook
review pipeline.
The live per-PR review path (
src/queue/processors.ts) callsbuildCollisionReport()with norecentMergedPullRequestsargument and builds abuildPreflightResult()input that omitschangedFiles, even though the PR's diff has often already been resolved a few lines earlier for thesecret-scan/AI-review gates. The data model already has what's needed — the
pull_request_filestableis populated per open PR by the routine detail-sync backfill, and
listRepoPullRequestFilePathscanalready query file paths across an arbitrary PR-number set for a repo.
Net effect: two independently-open PRs touching the same file get zero warning from Gittensory's
"Related work" panel today — it reads "No same-issue or scoped active PR overlap found" for exactly
this case, wasting review cycles on work that will conflict.
Fix
Populate
changedFilesonPullRequestRecord/prItem()from thepull_request_filescache so theexisting
termOverlap()/collision-scoring machinery (which already tokenizeschangedFilesfor mergedPRs) gets real path signal for open-vs-open PR pairs too — not just title/label/linked-issue text.
Guarded by a same-author exclusion: a contributor's own two PRs sharing a file (follow-up / stacked PR)
must not be flagged as a collision — that's legitimate iteration, not duplicate work. The guard is
scoped specifically to matches driven by path terms; pre-existing title/label-overlap behavior between
same-author items (already shipped, already tested) is unchanged.
Flag-gated (
GITTENSORY_OPEN_PR_FILE_COLLISION, default OFF) for the live-wiring rollout since thistouches the shared collision/preflight path several other gates depend on.