fix(sessions): bind forge into session key to prevent cross-forge collision #534

Merged
code-lead merged 1 commit from boss/520 into main 2026-04-28 13:06:12 +00:00
Collaborator

Closes #520.

Summary

  • Session keys now include the forge as the leading segment: <forge>:<type>:<owner>/<name>:<issue>. Two repos with the same <owner>/<name> on different forges keep independent Claude resume sessions.
  • dropAllForIssue is forge-scoped — closing issue #4 on forgejo:acme/widget no longer wipes sessions for github:acme/widget. Cleanup callers compute forge via getForgeForRepo.
  • One-shot boot migration migrateSessionKeysAddForgePrefix backfills any pre-existing un-prefixed key with forgejo: (the only forge that ran before this change). Idempotent. Runs after migrateArchitectSessionKeys so legacy architect:<…> rows get renamed first then prefixed.
  • Migration choice: backfill (not drop) — pre-#520 deployments were single-forge Forgejo, so forgejo: is the correct historical default.

Test plan

  • just qa — typecheck + Biome + 2452 tests green
  • New cross-forge isolation (#520) describe in sessions.test.ts proves same <owner>/<name> on different forges round-trips independently and dropAllForIssue is forge-scoped
  • New migrateSessionKeysAddForgePrefix describe covers backfill, leave-prefixed-alone, idempotent, no-clobber
Closes #520. ## Summary - Session keys now include the forge as the leading segment: `<forge>:<type>:<owner>/<name>:<issue>`. Two repos with the same `<owner>/<name>` on different forges keep independent Claude resume sessions. - `dropAllForIssue` is forge-scoped — closing issue #4 on `forgejo:acme/widget` no longer wipes sessions for `github:acme/widget`. Cleanup callers compute forge via `getForgeForRepo`. - One-shot boot migration `migrateSessionKeysAddForgePrefix` backfills any pre-existing un-prefixed key with `forgejo:` (the only forge that ran before this change). Idempotent. Runs after `migrateArchitectSessionKeys` so legacy `architect:<…>` rows get renamed first then prefixed. - **Migration choice**: backfill (not drop) — pre-#520 deployments were single-forge Forgejo, so `forgejo:` is the correct historical default. ## Test plan - [x] `just qa` — typecheck + Biome + 2452 tests green - [x] New `cross-forge isolation (#520)` describe in `sessions.test.ts` proves same `<owner>/<name>` on different forges round-trips independently and `dropAllForIssue` is forge-scoped - [x] New `migrateSessionKeysAddForgePrefix` describe covers backfill, leave-prefixed-alone, idempotent, no-clobber
fix(sessions): bind forge into session key to prevent cross-forge collision (#520)
All checks were successful
qa / qa (pull_request) Successful in 11m43s
qa / dockerfile (pull_request) Successful in 13s
303a1039af
Session keys now include the forge as the leading segment
(`<forge>:<type>:<owner>/<name>:<issue>`), so two repos with the same
`<owner>/<name>` on different forges keep independent Claude resume
sessions instead of clobbering each other on the same JSON file row.

Migration is a one-shot backfill on boot: any pre-existing key without a
forge prefix gains `forgejo:` (the only forge that ran before this
change). Runs after `migrateArchitectSessionKeys` so legacy
`architect:<…>` rows get renamed first, then prefixed. Idempotent: a
second pass finds nothing to rewrite.

`dropAllForIssue` is now forge-scoped — closing issue #4 on
`forgejo:acme/widget` no longer drops sessions for `github:acme/widget`.
Cleanup callers compute the forge from the repo via `getForgeForRepo`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
reviewer approved these changes 2026-04-28 13:01:04 +00:00
reviewer left a comment

Session key shape, dropAllForIssue forge-scoping, migration ordering (migrateArchitectSessionKeysmigrateSessionKeysAddForgePrefix), and all call sites (agent-runner, cleanup, /reset) are correct. CI green, cross-forge isolation tests present.

Nit not worth blocking: FORGE_PREFIXES in migrateSessionKeysAddForgePrefix is a hardcoded list — acceptable given the no-shared-import constraint, but worth a comment noting it must be kept in sync if a new forge type is added to @claude-hooks/shared.

Session key shape, `dropAllForIssue` forge-scoping, migration ordering (`migrateArchitectSessionKeys` → `migrateSessionKeysAddForgePrefix`), and all call sites (`agent-runner`, `cleanup`, `/reset`) are correct. CI green, cross-forge isolation tests present. Nit not worth blocking: `FORGE_PREFIXES` in `migrateSessionKeysAddForgePrefix` is a hardcoded list — acceptable given the no-shared-import constraint, but worth a comment noting it must be kept in sync if a new forge type is added to `@claude-hooks/shared`.
code-lead deleted branch boss/520 2026-04-28 13:06:16 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!534
No description provided.