Skip to content

feat(agent-memory): add PR-to-branch mapping module#1210

Merged
rjmurillo merged 2 commits into
mainfrom
feat/683-autonomous
Feb 21, 2026
Merged

feat(agent-memory): add PR-to-branch mapping module#1210
rjmurillo merged 2 commits into
mainfrom
feat/683-autonomous

Conversation

@rjmurillo-bot

@rjmurillo-bot rjmurillo-bot commented Feb 20, 2026

Copy link
Copy Markdown
Collaborator

Pull Request

Summary

Add Python module for maintaining explicit PR-to-branch mappings in Serena memory. This prevents cross-PR commits during multi-PR sessions, addressing the root cause identified in the PR #669 retrospective.

Specification References

Type Reference Description
Issue Fixes #683 feat(agent-memory): maintain explicit PR-to-branch mapping in Serena

Changes

  • Add scripts/pr_branch_mapping.py with CLI and library interface for PR-branch mapping operations
  • Add tests/test_pr_branch_mapping.py with 33 tests covering all operations and edge cases
  • Dataclass-based data model (PRBranchEntry, CurrentSession, PRBranchMapping)
  • Supports add, query (by PR or branch), validate, list, and cleanup commands
  • Stores mapping as JSON in a Serena memory file (pr-branch-mapping)
  • Exit codes follow ADR-035 standardization

Type of Change

  • New feature (non-breaking change adding functionality)

Testing

  • Tests added/updated
  • Manual testing completed

Agent Review

Security Review

  • No security-critical changes in this PR

Other Agent Reviews

  • QA verified test coverage

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • No new warnings introduced

Related Issues

Implement Python module for maintaining explicit PR-to-branch mappings
in Serena memory. Prevents cross-PR commits during multi-PR sessions.

Provides CLI and library interface with add, query, validate, list, and
cleanup operations. Stores data as JSON in `.serena/memories/pr-branch-mapping.md`.

Includes 33 tests covering all operations and edge cases.

Fixes #683

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@github-actions github-actions Bot added enhancement New feature or request automation Automated workflows and processes labels Feb 20, 2026
@rjmurillo-bot rjmurillo-bot enabled auto-merge (squash) February 20, 2026 04:22
@github-actions

github-actions Bot commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

✅ Pass: Memory Validation

No memories with citations found.


📊 Validation Details
  • Total memories checked: 0
  • Valid: 0
  • Stale: 0

@github-actions

Copy link
Copy Markdown
Contributor

PR Validation Report

Caution

Status: FAIL

Description Validation

Check Status
Description matches diff FAIL

QA Validation

Check Status
Code changes detected True
QA report exists false

⚠️ Blocking Issues

  • PR description does not match actual changes

⚡ Warnings

  • QA report not found for code changes (recommended before merge)

Powered by PR Validation workflow

@coderabbitai coderabbitai Bot requested a review from rjmurillo February 20, 2026 04:22

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request introduces a robust module for managing PR-to-branch mappings, which is a critical step in preventing cross-PR commit errors. The implementation is well-structured, leveraging Python dataclasses for data modeling and adhering to project standards for exit codes and subprocess handling. However, a logic flaw was identified in the add_mapping function where multiple PRs could be mapped to the same branch, potentially leading to incorrect validation results. Addressing this will ensure the tool effectively meets its goal of maintaining explicit and unique mappings.

Comment thread scripts/pr_branch_mapping.py
@coderabbitai

coderabbitai Bot commented Feb 20, 2026

Copy link
Copy Markdown

Caution

Review failed

Failed to post review comments

📝 Walkthrough

Walkthrough

Implements a new CLI-backed Python module that persists PR-to-branch mappings in a Serena memory markdown file and provides add/query/validate/list/cleanup operations; adds comprehensive pytest coverage for persistence, CLI flows, JSON handling, and git-branch interactions. (49 words)

Changes

Cohort / File(s) Summary
PR-Branch Mapping Module
scripts/pr_branch_mapping.py
New module. Adds data models (PRBranchEntry, CurrentSession, PRBranchMapping), constants (MEMORY_FILENAME, MEMORY_RELATIVE_PATH), load/save of JSON embedded in .serena/memories/pr-branch-mapping.md, add/update/query/validate/remove_merged functions, CLI subcommands (add, query, validate, list, cleanup), helpers, and explicit exit-code handling.
Module Test Suite
tests/test_pr_branch_mapping.py
New tests covering mapping load/save (missing file, corrupt JSON), current_session presence/absence, add/update behavior and timestamp/session handling, branch uniqueness rules, query utilities (by PR and branch), branch/PR consistency validation (with git branch mocking), removal of merged/closed entries, serialization (to_dict), and CLI command flows and exit codes.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI
  participant Module as PRBranchMapping
  participant Git as Git (git)
  participant FS as FileSystem (.serena/memories)

  CLI->>Module: add(prNumber, branchName, sessionId)
  Module->>Git: git branch --show-current
  Git-->>Module: branch name / error
  Module->>FS: read `pr-branch-mapping.md`
  FS-->>Module: markdown (may contain JSON block)
  Module->>Module: parse JSON, merge/update mapping, set current_session
  Module->>FS: write markdown with embedded JSON
  Module-->>CLI: exit 0

  CLI->>Module: validate()
  Module->>FS: read memory file
  FS-->>Module: markdown
  Module->>Git: git branch --show-current
  Git-->>Module: branch name / error
  Module-->>CLI: report consistency / exit code
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • rjmurillo
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.54% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title follows conventional commit format with 'feat' type and descriptive scope/subject.
Description check ✅ Passed Description clearly explains PR purpose, changes made, and links to issue #683.
Linked Issues check ✅ Passed All coding requirements from #683 are implemented: data structures, add/query/validate/cleanup operations, and JSON persistence in Serena memory.
Out of Scope Changes check ✅ Passed Both files are in-scope: pr_branch_mapping.py implements required module and tests file covers all operations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/683-autonomous

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

@coderabbitai coderabbitai Bot added agent-memory Context persistence agent area-workflows GitHub Actions workflows labels Feb 20, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (7)
tests/test_pr_branch_mapping.py (3)

226-231: Unused variable msg.

Ruff RUF059 flags unpacked variable msg as unused. Prefix with underscore.

Proposed fix
-        is_ok, msg = validate_branch_pr_consistency(
+        is_ok, _msg = validate_branch_pr_consistency(
             sample_mapping, current_branch="feat/add-widget"
         )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_pr_branch_mapping.py` around lines 226 - 231, The test unpacks
validate_branch_pr_consistency into is_ok, msg but never uses msg which triggers
RUF059; change the unpack to use a prefixed-underscore name (e.g., is_ok, _msg =
validate_branch_pr_consistency(...) or is_ok, _ =
validate_branch_pr_consistency(...)) in tests/test_pr_branch_mapping.py where
validate_branch_pr_consistency is called, and ensure no subsequent references to
msg remain.

334-345: Unused capsys parameter.

Ruff ARG002 flags capsys as unused. Either remove it or use it to verify stdout content.

Option A: Remove unused parameter
-    def test_query_by_pr(self, tmp_path: Path, capsys: object) -> None:
+    def test_query_by_pr(self, tmp_path: Path) -> None:
Option B: Actually verify output
-    def test_query_by_pr(self, tmp_path: Path, capsys: object) -> None:
+    def test_query_by_pr(self, tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
         mapping = PRBranchMapping()
         add_mapping(mapping, 42, "feat/test")
         save_mapping(tmp_path, mapping)
 
         exit_code = main([
             "--project-root", str(tmp_path),
             "query", "--pr", "42",
         ])
 
         assert exit_code == 0
+        captured = capsys.readouterr()
+        assert "feat/test" in captured.out
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_pr_branch_mapping.py` around lines 334 - 345, The test function
test_query_by_pr currently declares an unused capsys parameter causing Ruff
ARG002; either remove the capsys parameter from test_query_by_pr (and leave the
rest as-is using PRBranchMapping, add_mapping, save_mapping and main) or, if you
intend to validate CLI output, use capsys to capture stdout after calling main
(e.g., call capsys.readouterr() and assert on its .out) to verify the expected
output for the "query --pr 42" invocation; update assertions accordingly and
keep the rest of the setup (PRBranchMapping, add_mapping, save_mapping) intact.

221-221: Repeated import inside test methods.

CurrentSession is imported inside 4 test methods (lines 221, 236, 253, 310). Move to module-level imports at line 15-27 for consistency.

Proposed fix at module level
 from scripts.pr_branch_mapping import (
+    CurrentSession,
     MEMORY_RELATIVE_PATH,
     PRBranchEntry,
     PRBranchMapping,

Then remove the from scripts.pr_branch_mapping import CurrentSession lines from inside test methods.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_pr_branch_mapping.py` at line 221, Multiple tests import
CurrentSession inside their bodies; move the import to the module-level with the
other imports at the top of the test file and remove the four in-function
imports. Specifically, add "from scripts.pr_branch_mapping import
CurrentSession" to the top import block (with the other test imports) and delete
the in-test occurrences of that import in the methods that currently re-import
CurrentSession.
scripts/pr_branch_mapping.py (4)

27-28: Direct file I/O bypasses MemoriesManager.

Per external tools context, repository docs describe MemoriesManager as the canonical API for project-local memories under .serena/memories/. Direct writes bypass name normalization, file-size limits, and audit semantics.

Consider refactoring to use MemoriesManager in a follow-up if consistency with other memory tools is required.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/pr_branch_mapping.py` around lines 27 - 28, The code creates
MEMORY_FILENAME and MEMORY_RELATIVE_PATH constants that point directly at
".serena/memories/...", which bypasses the project's MemoriesManager; replace
direct file path usage by obtaining the canonical memory path or handle from the
MemoriesManager API (e.g., call MemoriesManager.get_memory_path(name) or
MemoriesManager.open/create with MEMORY_FILENAME) so name normalization, size
limits and audit semantics are applied instead of hardcoding
MEMORY_RELATIVE_PATH; update any code that referenced MEMORY_RELATIVE_PATH to
use the MemoriesManager methods (retain MEMORY_FILENAME only as a logical name
if needed).

87-89: Simplify with dict.get().

Ruff RUF019 flags the redundant key check. dict.get() handles missing keys cleanly.

Proposed fix
     current = None
-    if "current_session" in data and data["current_session"]:
-        current = CurrentSession(**data["current_session"])
+    session_data = data.get("current_session")
+    if session_data:
+        current = CurrentSession(**session_data)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/pr_branch_mapping.py` around lines 87 - 89, The code redundantly
checks "current_session" in data before instantiating CurrentSession; replace
that pattern with dict.get() to satisfy Ruff RUF019 by retrieving the value via
data.get("current_session") and only instantiate CurrentSession(**...) when the
returned value is truthy (e.g., use a conditional expression or an if on value)
so the variable current is None when there is no session and becomes
CurrentSession(**value) when present.

385-387: Blind exception catch loses stack trace.

Ruff BLE001 flags this. For a CLI tool, catching all exceptions is acceptable to prevent crashes. But the current message swallows the traceback, making debugging harder.

Consider logging the exception type or using logging.exception() when verbose mode is added.

Proposed fix
     except Exception as exc:
-        print(f"FATAL: {exc}", file=sys.stderr)
+        print(f"FATAL: {type(exc).__name__}: {exc}", file=sys.stderr)
         return 2
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/pr_branch_mapping.py` around lines 385 - 387, The broad except block
that prints only the exception message (in the except Exception as exc: ...
return 2) loses the traceback; update that handler to emit the full traceback
and exception type so failures are debuggable (e.g., use logging.exception(...)
or traceback.print_exc(file=sys.stderr) instead of print(f"FATAL: {exc}", ...)).
Locate the top-level exception handler in the script (the except Exception as
exc: block that returns 2) and replace the single-line print with a call that
logs the traceback and message; if a verbose/logging mode exists or is added,
prefer logging.exception for consistent logging.

109-148: Function mutates input and returns it.

add_mapping modifies mapping in place and also returns it. This dual pattern can confuse callers about ownership—some may expect a pure function returning a new object, others may expect a void mutator.

Current usage appears consistent, but consider documenting this explicitly in the docstring or picking one pattern.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/pr_branch_mapping.py` around lines 109 - 148, The add_mapping
function mutates the provided PRBranchMapping in place and also returns it,
which can confuse callers; update the add_mapping docstring to explicitly state
that it modifies the supplied mapping object (PRBranchMapping) in-place and
returns the same modified instance, and reference the behavior of fields
updated/added (mapping.mappings appends PRBranchEntry, existing entry fields
branch_name/last_session are updated, and mapping.current_session is replaced
with a CurrentSession) so callers know it is not a pure copy-producing function
(alternatively, if you prefer an immutable API, replace in-place updates in
add_mapping/_find_entry with code that clones mapping and returns a new
PRBranchMapping — choose one approach and make docstring/signature consistent).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@scripts/pr_branch_mapping.py`:
- Around line 27-28: The code creates MEMORY_FILENAME and MEMORY_RELATIVE_PATH
constants that point directly at ".serena/memories/...", which bypasses the
project's MemoriesManager; replace direct file path usage by obtaining the
canonical memory path or handle from the MemoriesManager API (e.g., call
MemoriesManager.get_memory_path(name) or MemoriesManager.open/create with
MEMORY_FILENAME) so name normalization, size limits and audit semantics are
applied instead of hardcoding MEMORY_RELATIVE_PATH; update any code that
referenced MEMORY_RELATIVE_PATH to use the MemoriesManager methods (retain
MEMORY_FILENAME only as a logical name if needed).
- Around line 87-89: The code redundantly checks "current_session" in data
before instantiating CurrentSession; replace that pattern with dict.get() to
satisfy Ruff RUF019 by retrieving the value via data.get("current_session") and
only instantiate CurrentSession(**...) when the returned value is truthy (e.g.,
use a conditional expression or an if on value) so the variable current is None
when there is no session and becomes CurrentSession(**value) when present.
- Around line 385-387: The broad except block that prints only the exception
message (in the except Exception as exc: ... return 2) loses the traceback;
update that handler to emit the full traceback and exception type so failures
are debuggable (e.g., use logging.exception(...) or
traceback.print_exc(file=sys.stderr) instead of print(f"FATAL: {exc}", ...)).
Locate the top-level exception handler in the script (the except Exception as
exc: block that returns 2) and replace the single-line print with a call that
logs the traceback and message; if a verbose/logging mode exists or is added,
prefer logging.exception for consistent logging.
- Around line 109-148: The add_mapping function mutates the provided
PRBranchMapping in place and also returns it, which can confuse callers; update
the add_mapping docstring to explicitly state that it modifies the supplied
mapping object (PRBranchMapping) in-place and returns the same modified
instance, and reference the behavior of fields updated/added (mapping.mappings
appends PRBranchEntry, existing entry fields branch_name/last_session are
updated, and mapping.current_session is replaced with a CurrentSession) so
callers know it is not a pure copy-producing function (alternatively, if you
prefer an immutable API, replace in-place updates in add_mapping/_find_entry
with code that clones mapping and returns a new PRBranchMapping — choose one
approach and make docstring/signature consistent).

In `@tests/test_pr_branch_mapping.py`:
- Around line 226-231: The test unpacks validate_branch_pr_consistency into
is_ok, msg but never uses msg which triggers RUF059; change the unpack to use a
prefixed-underscore name (e.g., is_ok, _msg =
validate_branch_pr_consistency(...) or is_ok, _ =
validate_branch_pr_consistency(...)) in tests/test_pr_branch_mapping.py where
validate_branch_pr_consistency is called, and ensure no subsequent references to
msg remain.
- Around line 334-345: The test function test_query_by_pr currently declares an
unused capsys parameter causing Ruff ARG002; either remove the capsys parameter
from test_query_by_pr (and leave the rest as-is using PRBranchMapping,
add_mapping, save_mapping and main) or, if you intend to validate CLI output,
use capsys to capture stdout after calling main (e.g., call capsys.readouterr()
and assert on its .out) to verify the expected output for the "query --pr 42"
invocation; update assertions accordingly and keep the rest of the setup
(PRBranchMapping, add_mapping, save_mapping) intact.
- Line 221: Multiple tests import CurrentSession inside their bodies; move the
import to the module-level with the other imports at the top of the test file
and remove the four in-function imports. Specifically, add "from
scripts.pr_branch_mapping import CurrentSession" to the top import block (with
the other test imports) and delete the in-test occurrences of that import in the
methods that currently re-import CurrentSession.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Feb 20, 2026
Address Gemini code review comment that add_mapping allowed duplicate
branch mappings across different PRs. Now removes any existing mapping
for a branch before adding a new one, ensuring 1:1 PR-to-branch
relationship.

Added two tests to verify:
- Old PR mapping is removed when new PR claims same branch
- Other PR mappings with different branches are preserved

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added the infrastructure-failure CI infrastructure failure (Copilot CLI auth, rate limits, etc.) label Feb 21, 2026
@github-actions

github-actions Bot commented Feb 21, 2026

Copy link
Copy Markdown
Contributor

AI Quality Gate Review

Warning

⚠️ Final Verdict: WARN

Walkthrough

This PR was reviewed by six AI agents in parallel, analyzing different aspects of the changes:

  • Security Agent: Scans for vulnerabilities, secrets exposure, and security anti-patterns
  • QA Agent: Evaluates test coverage, error handling, and code quality
  • Analyst Agent: Assesses code quality, impact analysis, and maintainability
  • Architect Agent: Reviews design patterns, system boundaries, and architectural concerns
  • DevOps Agent: Evaluates CI/CD, build pipelines, and infrastructure changes
  • Roadmap Agent: Assesses strategic alignment, feature scope, and user value

Review Summary

Agent Verdict Category Status
Security CRITICAL_FAIL INFRASTRUCTURE
QA CRITICAL_FAIL INFRASTRUCTURE
Analyst CRITICAL_FAIL INFRASTRUCTURE
Architect CRITICAL_FAIL INFRASTRUCTURE
DevOps CRITICAL_FAIL INFRASTRUCTURE
Roadmap CRITICAL_FAIL INFRASTRUCTURE

💡 Quick Access: Click on individual agent jobs (e.g., "🔒 security Review", "🧪 qa Review") in the workflow run to see detailed findings and step summaries.

Security Review Details

VERDICT: CRITICAL_FAIL
MESSAGE: Copilot CLI infrastructure failure after 3 attempts (exit code 1). Check COPILOT_GITHUB_TOKEN scope, rate limits, or network connectivity.

QA Review Details

VERDICT: CRITICAL_FAIL
MESSAGE: Copilot CLI infrastructure failure after 3 attempts (exit code 1). Check COPILOT_GITHUB_TOKEN scope, rate limits, or network connectivity.

Analyst Review Details

VERDICT: CRITICAL_FAIL
MESSAGE: Copilot CLI infrastructure failure after 3 attempts (exit code 1). Check COPILOT_GITHUB_TOKEN scope, rate limits, or network connectivity.

Architect Review Details

VERDICT: CRITICAL_FAIL
MESSAGE: Copilot CLI infrastructure failure after 3 attempts (exit code 1). Check COPILOT_GITHUB_TOKEN scope, rate limits, or network connectivity.

DevOps Review Details

VERDICT: CRITICAL_FAIL
MESSAGE: Copilot CLI infrastructure failure after 3 attempts (exit code 1). Check COPILOT_GITHUB_TOKEN scope, rate limits, or network connectivity.

Roadmap Review Details

VERDICT: CRITICAL_FAIL
MESSAGE: Copilot CLI infrastructure failure after 3 attempts (exit code 1). Check COPILOT_GITHUB_TOKEN scope, rate limits, or network connectivity.


Run Details
Property Value
Run ID 22251757737
Triggered by pull_request on 1210/merge
Commit 080e0884d20b4a1532ad6d0e7556cf8d0e6304a8

Powered by AI Quality Gate workflow

@rjmurillo rjmurillo closed this Feb 21, 2026
auto-merge was automatically disabled February 21, 2026 06:12

Pull request was closed

@rjmurillo rjmurillo reopened this Feb 21, 2026
@rjmurillo rjmurillo merged commit 6e62841 into main Feb 21, 2026
110 of 117 checks passed
@rjmurillo rjmurillo deleted the feat/683-autonomous branch February 21, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-memory Context persistence agent area-workflows GitHub Actions workflows automation Automated workflows and processes enhancement New feature or request infrastructure-failure CI infrastructure failure (Copilot CLI auth, rate limits, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(agent-memory): maintain explicit PR-to-branch mapping in Serena

2 participants