.maestro/playbooks/2026-02-25-CM-Issues-PRs/2026-02-25-Branch-Memory/BRANCH-MEMORY-05.md
This final phase hardens the branch memory feature for production use. It handles edge cases (detached HEAD, shallow clones, non-git directories), adds performance guards for large observation sets, and provides integration tests that verify the complete end-to-end flow. By the end, branch memory is production-ready.
Harden edge case handling in git utilities:
src/services/integrations/git-branch.ts and src/services/integrations/git-ancestry.tsasync function isGitRepository(cwd: string): Promise<boolean> utility (in git-branch.ts) that runs git rev-parse --is-inside-work-tree — use this as an early guard in resolveVisibleCommitShas to skip expensive ancestry checks when not in a git repogit rev-parse --abbrev-ref HEAD returns literal string "HEAD" — branch should be set to null, commit SHA should still be capturedgit merge-base --is-ancestor may fail on shallow clones where history is truncated — handle this gracefully by treating failed ancestry checks as "not an ancestor" rather than erroring.claude/worktrees/ worktree, git rev-parse commands should still work correctly since worktrees share the same git object store — run a quick manual test or add a test caseAdd performance guard for large observation sets:
resolveAncestorCommits in src/services/integrations/git-ancestry.ts, add batching: if candidateCommitShas has more than 100 entries, process in batches of 100 with Promise.all per batch to avoid spawning too many concurrent git processesgit log --format=%H HEAD to get all ancestor commits in a single call, then intersect with candidates using a Set — this is O(n) instead of O(n) git calls. Add this as an optimization when candidates exceed 500Write integration tests for the complete branch memory flow:
tests/branch-memory-integration.test.tsstoreObservation() with branch and commitSha parameters, then query the observation back and verify the branch and commit_sha columns are populated correctlybranch: undefined and commitSha: undefined should have NULL in the database and should always be visible in filtered queries (the commit_sha IS NULL clause)getObservationsByIds: store observations with different commit SHAs, query with a commit_sha filter array, verify only matching observations are returned (plus NULL commit_sha observations)getUniqueCommitShasForProject: store observations with various commit SHAs (including duplicates and nulls), verify the function returns the correct distinct setRun all tests and verify no regressions:
npm run build-and-syncFinal end-to-end verification:
branch and commit_sha columns: sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA table_info(observations);"sqlite3 ~/.claude-mem/claude-mem.db "SELECT id, branch, commit_sha FROM observations ORDER BY id DESC LIMIT 5;"Verification Summary (2026-02-25):
observations table has branch (col 18) and commit_sha (col 19) columnspending_messages table has branch and commit_sha columns (migration 25 applied)npm run build-and-syncCritical Bug Found & Fixed:
PendingMessageStore.enqueue() was NOT persisting branch/commit_sha to the pending_messages tablePendingMessageStore.toPendingMessage() was NOT reading them backbranch/commit_sha to enqueue() INSERT, PersistentPendingMessage interface, toPendingMessage() conversion, and added migration 25 to both SessionStore.ts and migrations/runner.tsKnown Limitations:
commit_sha IS NULL clause includes them in filtered queries)storeObservationsAndMarkComplete() method in SessionStore does NOT include branch/commit_sha (only the active storeObservations() method does)cwd to be present in hook input and the directory to be inside a git repository