Skip to content

fix: scope CodebaseGraphManager to current repo for concurrent sessions (alternative approach)#538

Merged
scottfrasso merged 1 commit intoshotgun-sh:mainfrom
lchachurski:fix/scoped-manager-concurrent-sessions
Apr 14, 2026
Merged

fix: scope CodebaseGraphManager to current repo for concurrent sessions (alternative approach)#538
scottfrasso merged 1 commit intoshotgun-sh:mainfrom
lchachurski:fix/scoped-manager-concurrent-sessions

Conversation

@lchachurski
Copy link
Copy Markdown
Contributor

Problem

When two Shotgun sessions run simultaneously on different repositories in the same parent directory, a startup health check scans every .kuzu file in ~/.shotgun-sh/codebases/. Kuzu uses exclusive file locks, so any database held open by a peer session is reported as "locked" — even though the current repo's database is perfectly fine. This shows a blocking dialog and prevents the second session from starting.

Reported in #534.

Root cause

Three methods in CodebaseGraphManager glob the entire storage directory:

  • detect_database_issues() — the startup health check
  • list_graphs() — used by shotgun codebase list and graph service
  • cleanup_corrupted_databases() — called during startup and recovery

This fix (alternative to #535)

Add a single process-wide class variable _scope_graph_ids to CodebaseGraphManager, set once at process startup from the current working directory. A new _iter_databases() method replaces all three .glob("*.kuzu") calls. Any future method that enumerates databases uses _iter_databases() and automatically inherits the scope — no parameter threading required.

main.py (2 lines)
  └─ CodebaseGraphManager._scope_graph_ids = [generate_graph_id(cwd)]

manager.py (~15 lines)
  └─ _scope_graph_ids: ClassVar[list[str] | None] = None
  └─ _iter_databases() → replaces 3 glob sites

cli/codebase/commands.py (1 line)
  └─ list_codebases(): _scope_graph_ids = None  # needs all DBs

Total: 3 files changed, 43 insertions(+), 9 deletions(-)

Comparison with PR #535

PR #535 This PR
Approach graph_ids parameter on each method + .meta.json sidecars Process-wide ClassVar, set once in main.py
Files changed 8 3
New future-proofing Must thread parameter / update sidecar for every new method _iter_databases() handles it automatically
shotgun codebase list Shows all codebases (uses full glob) Explicitly unscopes for this one command

How it works

Every Shotgun process starts from a CWD. main.py calls generate_graph_id(os.getcwd()) and stores the result in the class variable. Because _scope_graph_ids is a ClassVar, every instance of CodebaseGraphManager created anywhere in the process automatically respects the scope — TUI, shotgun run, shotgun codebase index, benchmarks, all covered by the two lines in main.py.

The only exception is shotgun codebase list, which legitimately needs to show all indexed repositories. It clears the scope before querying.

Tests

Standalone test script using real_ladybug==0.15.1 and multiprocessing to hold real Kuzu file locks. 3 simulated repos (project-alpha, project-beta, project-gamma). All 8 tests pass:

# Scenario Result
T1 Bug reproduced: OLD globs all, 2 peers locked, blocks 3rd PASS
T2 NEW scope set → alpha/beta never opened, gamma starts clean PASS
T3 list_graphs scoped: opens 1/3 not 3/3 PASS
T4 Each CWD's scope targets only its own graph PASS
T5 Unrelated CWD returns empty PASS
T6 Scoped cleanup avoids locked peers PASS
T7 Backward compat: scope=None still full-scans PASS
T8 graph_id uniqueness across 3 repos PASS

Closes #534

Made with Cursor

Adds a process-wide class variable _scope_graph_ids to
CodebaseGraphManager, set once at startup from the CWD. A single
_iter_databases() helper replaces every .glob("*.kuzu") call, so all
existing and future enumeration methods automatically respect the scope.

Root cause: detect_database_issues(), list_graphs(), and
cleanup_corrupted_databases() all globbed every .kuzu file in
~/.shotgun-sh/codebases/. When another Shotgun session was running on
a different repo, its database was exclusively locked by Kuzu. The
health check reported this as an issue, showing a blocking "database
locked" dialog — even though the current repo's database was fine.

Changes:
- manager.py: add _scope_graph_ids ClassVar (default None) and
  _iter_databases() method. Replace 3 glob sites with _iter_databases().
- main.py: set _scope_graph_ids = [generate_graph_id(cwd)] once in
  main() before any subcommand runs. Covers TUI, shotgun run, and all
  other CLI commands in a single place.
- cli/codebase/commands.py: unset scope in list_codebases() — the one
  command that legitimately needs to enumerate all indexed databases.

This approach is ~15 lines of meaningful change across 3 files with
zero parameter passing. Any future method that enumerates databases
uses _iter_databases() and automatically inherits the scope.

Alternative approach: PR shotgun-sh#535 patches each method individually using
optional graph_ids parameters and .meta.json sidecar files.

Tested with real_ladybug==0.15.1 against 3 simulated repos under real
Kuzu file locks (multiprocessing). All 8 tests pass:
  T1: bug reproduced (OLD globs all, 2 locked, blocks 3rd session)
  T2: fix validates (NEW scope, alpha/beta never opened)
  T3: list_graphs scoped (opens 1/3 not 3/3)
  T4: each CWD yields correct scope isolation
  T5: unrelated CWD returns empty
  T6: scoped cleanup avoids locked peers
  T7: backward compat (scope=None full scan still works)
  T8: graph_id uniqueness across 3 repos

Closes shotgun-sh#534

Made-with: Cursor
@lchachurski
Copy link
Copy Markdown
Contributor Author

Hey team! I hd a bit more time to think about the problem today and above is a cleaner fix approach.

@scottfrasso scottfrasso merged commit 25bcf6b into shotgun-sh:main Apr 14, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Cannot run concurrent sessions on different repositories - startup locks ALL codebase databases

2 participants