Skip to content

feat(graph): per-branch graph identity (T17 #651)#675

Draft
DvirDukhan wants to merge 1 commit into
mcp/t1-scaffoldfrom
dvirdukhan/mcp-t17-per-branch-graphs
Draft

feat(graph): per-branch graph identity (T17 #651)#675
DvirDukhan wants to merge 1 commit into
mcp/t1-scaffoldfrom
dvirdukhan/mcp-t17-per-branch-graphs

Conversation

@DvirDukhan
Copy link
Copy Markdown

Closes #651.

Stacked on #666 (mcp/t1-scaffold).

What

Each FalkorDB graph is now identified by (project, branch) rather
than just project. Concurrent agents indexing the same repo on
different branches no longer overwrite each other.

New graph name format: code:{project}:{branch} (default branch:
_default). The companion Redis info hash becomes
{project}:{branch}_info and the git-history graph becomes
{project}:{branch}_git.

Highlights

  • Graph / AsyncGraphQuery constructors accept branch=None.
  • All /api/* endpoints accept an optional branch field; responses
    include branch so the frontend can disambiguate.
  • CLI gains --branch on every read/index command and auto-detects
    from git rev-parse --abbrev-ref HEAD when omitted.
  • New cgraph migrate command (idempotent, --dry-run supported)
    promotes legacy <project> graphs to code:<project>:_default.
  • 24 new unit tests in tests/test_per_branch_graphs.py. Existing
    test_async_graph.py / test_cli.py / test_list_repos.py
    updated for the new dict return shape of get_repos.

Backward compatibility

  • Graph("foo") still works → composes to code:foo:_default.
  • Info reads fall back to the legacy {foo}_info key when the
    new key is absent, so un-migrated repos remain queryable until
    the operator runs cgraph migrate.
  • parse_graph_name returns None for legacy bare names so
    callers can detect and special-case them.

Migration story

One-shot rename of legacy artifacts via cgraph migrate:

  • graph <project>code:<project>:_default
  • Redis hash {<project>}_info{<project>}:_default_info
  • graph {<project>}_git{<project>}:_default_git

Safe to re-run. --dry-run previews actions without writing.

Not in scope

  • The MCP tools themselves (T4+) — those land in follow-up PRs.
  • Per-branch indexing of git history beyond what process_git_history
    already does (it now writes to the per-branch git graph but does
    not yet track multiple branches in a single run).

Test status

  • tests/test_per_branch_graphs.py: 24 ✅
  • tests/test_async_graph.py: 6 ✅
  • tests/test_cli.py: 10 ✅

Pre-existing failures unrelated to T17 (missing tests/git_repo
fixture, hard-coded port 6379 in test_graph_ops.py, analyzer
tests requiring specific source builds) remain unchanged from
mcp/t1-scaffold.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Refactor FalkorDB graph naming so each (project, branch) pair gets
its own graph: 'code:{project}:{branch}'. This lets concurrent agents
working on different branches of the same repo index in parallel
without overwriting each other.

Changes:
- api/graph.py: add DEFAULT_BRANCH, compose_graph_name(),
  parse_graph_name(); Graph and AsyncGraphQuery constructors now
  accept (name, branch=None); Graph.from_raw_name() classmethod for
  internal callers that need to bypass composition (e.g. clone());
  get_repos()/async_get_repos() now return {project, branch, graph}
  dicts.
- api/info.py: branch-aware Redis hash keys
  ('{repo}:{branch}_info'); reads fall back to legacy '{repo}_info'
  for un-migrated graphs.
- api/git_utils: GitRepoName() and switch_commit() thread branch
  through; LegacyGitRepoName() retained for the migration helper.
- api/project.py: detect_branch() via 'git rev-parse --abbrev-ref
  HEAD'; Project.__init__ / from_git_repository /
  from_local_repository accept branch.
- api/index.py: all Pydantic request models gain
  'branch: Optional[str]'; endpoints thread it into
  AsyncGraphQuery + info functions; responses include 'branch'.
- api/cli.py: --branch flag on index / index-repo / search /
  neighbors / paths / info; new 'cgraph migrate' command.
- api/migrations/per_branch.py (NEW): idempotent migration that
  renames legacy '<project>' graphs to 'code:<project>:_default',
  '{<project>}_info' Redis keys to '{<project>}:_default_info',
  and '{<project>}_git' graphs to '{<project>}:_default_git'.
  Supports --dry-run.

Tests:
- tests/test_per_branch_graphs.py (NEW): 24 unit tests covering
  compose/parse helpers, Graph constructor branch awareness,
  AsyncGraphQuery, info-key shape, GitRepoName shape, and migration
  idempotency (with mocked FalkorDB).
- tests/test_async_graph.py, tests/test_cli.py,
  tests/endpoints/test_list_repos.py: updated assertions for the
  new dict return shape from get_repos / async_get_repos.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5643d3e1-0a81-4689-a674-384b85682843

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dvirdukhan/mcp-t17-per-branch-graphs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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.

1 participant