You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
src/db/repo-identity-rename.ts's renameRepositoryIdentity(env, oldFullName, newFullName) fixes a real bug where a GitHub repo-rename webhook orphans every row already recorded under the old owner/repo string (see the module's own header comment: GitHub sends the same installation + the new full_name, but upsertRepositoryFromGitHub's onConflictDoUpdate keys on full_name, so the very next webhook after a rename silently forks a second, disconnected row instead of updating the existing one).
The fix walks every src/db/schema.ts table that carries a repo_full_name-shaped identity column and moves the old name's rows forward to the new name (fold-then-rename where a unique constraint could collide, plain rename otherwise). The module's own comment states the intended contract explicitly: "New tables extend this function directly, following the same shape."
That contract has drifted. Seven tables in src/db/schema.ts carry a repo_full_name column, are actively read/written by live code, and are not touched by renameRepositoryIdentity at all — a rename webhook silently leaves their rows pinned to the old name forever, exactly the bug this module exists to prevent:
Table (schema.ts var / SQL name)
Column shape
Live writer
Correct fold strategy
repositoryAiKeys / repository_ai_keys
repo_full_namePRIMARY KEY
src/db/repositories.ts (BYOK provider-key store)
Fold-then-rename (delete any pre-existing newFullName row, then UPDATE ... WHERE repo_full_name = oldFullName) — same anchor-table shape as repositories/burdenForecasts/repoQueueTrendSnapshots/repoSyncState already in the module.
repositoryLinearKeys / repository_linear_keys
repo_full_namePRIMARY KEY
src/db/repositories.ts (Linear API key store, #3186)
Fold on colliding issue_number values, same shape as the module's existing pullRequests/issues handling.
reviewSuppression / review_suppression
UNIQUE (repo_full_name, category, path_glob, pattern_hash) — a 4-column composite key
src/db/repositories.ts
Per-tuple fold (select the colliding (category, path_glob, pattern_hash) triples under oldFullName, delete any matching newFullName rows, then rename), same shape as the module's existing checkSummaries handling.
agentPendingActions / agent_pending_actions
UNIQUE (repo_full_name, pull_number, action_class) — a 3-column composite key
src/db/repositories.ts (the agent-layer approval queue, #779)
Per-tuple fold on (pull_number, action_class), same shape as the module's existing pullRequestFiles handling.
No unique index touches repo_full_name (its only unique index is (answer_id, actor_hash); repo_full_name/issue_number are only a non-unique index)
src/db/repositories.ts
Plain rename (UPDATE ... WHERE repo_full_name = oldFullName), no fold needed — same shape as the module's existing repoSnapshots/repoGithubTotalsSnapshots handling.
Every one of these tables is actively queried by live application code (verified via grep across src/), so this is not the "orphaned table, no live writer" case the module explicitly and deliberately excludes for review_targets/repo_chunks/the four AI-result caches. A repo rename today silently and permanently disconnects a repo's BYOK provider keys, Linear integration key, open bounties, review-suppression rules, pending agent approval-queue actions, issue-watch subscriptions, and command-feedback votes from the renamed repo — each of those features degrades or breaks for that repo until an operator notices and manually re-keys them.
Requirements
Extend renameRepositoryIdentity in src/db/repo-identity-rename.ts to cover all seven tables listed above, using the exact fold strategy noted for each (mirroring the existing per-table blocks already in the file for tables with the same key shape — do not invent a new generic cross-table helper; this file's own header comment explains why it's deliberately one explicit block per table).
Import the seven Drizzle table objects from ../db/schema alongside the existing imports.
Preserve the function's existing invariants: idempotent (safe to re-run for a redelivered webhook), collision-safe (a row that already exists under newFullName is folded away in favor of the pre-existing oldFullName row, never the reverse), and a no-op when oldFullName === newFullName.
Do not touch any of the tables the module's own comment deliberately excludes (the AI/LLM result caches, review_targets, repo_chunks).
Deliverables
repositoryAiKeys fold-then-rename added to renameRepositoryIdentity.
repositoryLinearKeys fold-then-rename added.
bounties fold-then-rename (on issue_number) added.
reviewSuppression per-tuple fold (on category, path_glob, pattern_hash) added.
agentPendingActions per-tuple fold (on pull_number, action_class) added.
issueWatchSubscriptions fold (on login) added.
githubAgentCommandFeedback plain rename added.
Test Coverage Requirements
src/db/repo-identity-rename.ts is under src/**, so it is Codecov patch-gated at 99%, branch-counted. test/unit/repo-identity-rename.test.ts already has one describe block per existing table with a consistent pattern — for each of the seven new tables, add a matching block asserting:
A row under oldFullName with no colliding row under newFullName is renamed cleanly (all identity columns updated).
A row under oldFullName that collides with a pre-existing row under newFullName (same unique key) folds correctly — the oldFullName row's data wins, the stray newFullName row is removed, no duplicate remains.
A rename with nothing under oldFullName for that table is a safe no-op (already covered by the top-level "safe no-op when nothing exists yet" test, but confirm the new table doesn't throw).
renameRepositoryIdentity is idempotent (running it twice in a row for the same table produces the same end state).
Expected Outcome
A GitHub repository rename correctly carries a repo's BYOK AI key, Linear integration key, open bounties, review-suppression rules, pending agent-approval-queue actions, issue-watch subscriptions, and command-feedback votes forward to the new name — none of them are silently orphaned under the stale old name.
Links & Resources
src/db/repo-identity-rename.ts — the function to extend.
Context
src/db/repo-identity-rename.ts'srenameRepositoryIdentity(env, oldFullName, newFullName)fixes a real bug where a GitHub repo-rename webhook orphans every row already recorded under the oldowner/repostring (see the module's own header comment: GitHub sends the same installation + the newfull_name, butupsertRepositoryFromGitHub'sonConflictDoUpdatekeys onfull_name, so the very next webhook after a rename silently forks a second, disconnected row instead of updating the existing one).The fix walks every
src/db/schema.tstable that carries arepo_full_name-shaped identity column and moves the old name's rows forward to the new name (fold-then-rename where a unique constraint could collide, plain rename otherwise). The module's own comment states the intended contract explicitly: "New tables extend this function directly, following the same shape."That contract has drifted. Seven tables in
src/db/schema.tscarry arepo_full_namecolumn, are actively read/written by live code, and are not touched byrenameRepositoryIdentityat all — a rename webhook silently leaves their rows pinned to the old name forever, exactly the bug this module exists to prevent:repositoryAiKeys/repository_ai_keysrepo_full_namePRIMARY KEYsrc/db/repositories.ts(BYOK provider-key store)newFullNamerow, thenUPDATE ... WHERE repo_full_name = oldFullName) — same anchor-table shape asrepositories/burdenForecasts/repoQueueTrendSnapshots/repoSyncStatealready in the module.repositoryLinearKeys/repository_linear_keysrepo_full_namePRIMARY KEYsrc/db/repositories.ts(Linear API key store, #3186)bountiesUNIQUE (repo_full_name, issue_number)src/db/repositories.ts, read acrosssrc/signals/data-quality.ts,src/signals/local-branch.ts,src/signals/review-risk.ts,src/mcp/server.ts,src/openapi/spec.ts,src/github/commands.ts,src/queue/signal-snapshot.ts,src/api/routes.ts,src/services/decision-pack.ts,src/services/agent-orchestrator.ts,src/services/issue-quality.tsissue_numbervalues, same shape as the module's existingpullRequests/issueshandling.reviewSuppression/review_suppressionUNIQUE (repo_full_name, category, path_glob, pattern_hash)— a 4-column composite keysrc/db/repositories.ts(category, path_glob, pattern_hash)triples underoldFullName, delete any matchingnewFullNamerows, then rename), same shape as the module's existingcheckSummarieshandling.agentPendingActions/agent_pending_actionsUNIQUE (repo_full_name, pull_number, action_class)— a 3-column composite keysrc/db/repositories.ts(the agent-layer approval queue, #779)(pull_number, action_class), same shape as the module's existingpullRequestFileshandling.issueWatchSubscriptions/issue_watch_subscriptionsUNIQUE (login, repo_full_name)src/db/repositories.tsloginvalues, same single-column-fold shape as the module's existingcontributorRepoStatshandling.githubAgentCommandFeedback/github_agent_command_feedbackrepo_full_name(its only unique index is(answer_id, actor_hash);repo_full_name/issue_numberare only a non-unique index)src/db/repositories.tsUPDATE ... WHERE repo_full_name = oldFullName), no fold needed — same shape as the module's existingrepoSnapshots/repoGithubTotalsSnapshotshandling.Every one of these tables is actively queried by live application code (verified via
grepacrosssrc/), so this is not the "orphaned table, no live writer" case the module explicitly and deliberately excludes forreview_targets/repo_chunks/the four AI-result caches. A repo rename today silently and permanently disconnects a repo's BYOK provider keys, Linear integration key, open bounties, review-suppression rules, pending agent approval-queue actions, issue-watch subscriptions, and command-feedback votes from the renamed repo — each of those features degrades or breaks for that repo until an operator notices and manually re-keys them.Requirements
renameRepositoryIdentityinsrc/db/repo-identity-rename.tsto cover all seven tables listed above, using the exact fold strategy noted for each (mirroring the existing per-table blocks already in the file for tables with the same key shape — do not invent a new generic cross-table helper; this file's own header comment explains why it's deliberately one explicit block per table).../db/schemaalongside the existing imports.newFullNameis folded away in favor of the pre-existingoldFullNamerow, never the reverse), and a no-op whenoldFullName === newFullName.review_targets,repo_chunks).Deliverables
repositoryAiKeysfold-then-rename added torenameRepositoryIdentity.repositoryLinearKeysfold-then-rename added.bountiesfold-then-rename (onissue_number) added.reviewSuppressionper-tuple fold (oncategory, path_glob, pattern_hash) added.agentPendingActionsper-tuple fold (onpull_number, action_class) added.issueWatchSubscriptionsfold (onlogin) added.githubAgentCommandFeedbackplain rename added.Test Coverage Requirements
src/db/repo-identity-rename.tsis undersrc/**, so it is Codecovpatch-gated at 99%, branch-counted.test/unit/repo-identity-rename.test.tsalready has onedescribeblock per existing table with a consistent pattern — for each of the seven new tables, add a matching block asserting:oldFullNamewith no colliding row undernewFullNameis renamed cleanly (all identity columns updated).oldFullNamethat collides with a pre-existing row undernewFullName(same unique key) folds correctly — theoldFullNamerow's data wins, the straynewFullNamerow is removed, no duplicate remains.oldFullNamefor that table is a safe no-op (already covered by the top-level "safe no-op when nothing exists yet" test, but confirm the new table doesn't throw).renameRepositoryIdentityis idempotent (running it twice in a row for the same table produces the same end state).Expected Outcome
A GitHub repository rename correctly carries a repo's BYOK AI key, Linear integration key, open bounties, review-suppression rules, pending agent-approval-queue actions, issue-watch subscriptions, and command-feedback votes forward to the new name — none of them are silently orphaned under the stale old name.
Links & Resources
src/db/repo-identity-rename.ts— the function to extend.src/db/schema.ts— table definitions (repositoryAiKeys~L110,repositoryLinearKeys~L130,bounties~L553,reviewSuppression~L788,agentPendingActions~L807,issueWatchSubscriptions~L1169,githubAgentCommandFeedback~L1206).test/unit/repo-identity-rename.test.ts— existing test file to extend, follow its established per-table pattern.