[Bug] Memory store path mismatch between transcript and index in repository subdirectories
Environment
- CLI 2.1.246, macOS darwin-arm64, Max 20x
- Related: #82056 (no way to tell whether the memory index loaded whole), where this was found
What happens
Inside a git repository subdirectory, a session's transcript and its auto-memory index resolve to two different project directories at once:
cwd = <repo>/sub
transcript written to ~/.claude/projects/<slug of repo/sub>/<uuid>.jsonl
index READ from ~/.claude/projects/<slug of repo>/memory/MEMORY.md
The transcript keys on the working directory. The index keys on the git repository root. <repo>/sub therefore ends up with a project directory that holds its own transcripts and its own memory/ store, and that store is never read.
How it was measured
A distinct canary index was planted in each of four stores, then one question was asked from each location and the answer read back:
probed from answered transcripts landed in
repo root / subdir <repo>/sub REPOROOT <repo>/sub (1 jsonl)
<repo> (0 jsonl)
<repo>/sub carried CANARY-REPOSUB in its own store. It was not returned. The enclosing repo-root index was.
Why it matters
- A memory written from a subdirectory can become unreachable. If anything ever writes into the subdirectory's store, that store is orphaned: it accumulates files that no session will read.
- The store path is not derivable from
transcript_path. That is the obvious handle, because aSessionStarthook is handed it directly. I built exactly such a hook and it resolved to the wrong directory in every repository subdirectory until this test. Any correct implementation has to callgit rev-parse --show-toplevelfirst and fall back to cwd, which is not documented anywhere I can find.
- A probe that looks correct can be reading the wrong file with no symptom. This is the same trap reported from the other side in #82056, where a seven-arm test unknowingly read one enclosing index seven times. Anything keyed on where the transcript lives inherits the bug.
Also observed, same area
A project directory is created by a session that never authenticated. A first pass here ran under an isolated CLAUDE_CONFIG_DIR that was not logged in. Every arm returned Not logged in · Please run /login, and all four project directories were created anyway. So a directory under projects/ does not prove a session ran, only that one was launched, and any check answering "does this project have a memory store?" returns yes for a directory produced by a failed login.
The cd asymmetry reproduces on darwin. Reported on linux-x64 and win32 in #82056; this is the third platform.
outside a repo, root -> its own store
outside a repo, sub/deeper -> a DIFFERENT store, no roll-up to the parent
inside a repo, root -> repo root store
inside a repo, subdir -> the SAME repo root store (control)
plain/sub/deeper answered CANARY-DEEPER, its own index, not the parent's. The in-repo pair is the control and behaves as documented, so a harness fault would have shown up as the documented half failing.
Ask
- Key the transcript and the index to the same directory, whichever is correct, and say which in the documentation.
- If the divergence is deliberate, expose the resolved store path to hooks (a field on the
SessionStartpayload) so it does not have to be re-derived and guessed at. - Do not create a project directory for a session that fails to authenticate.
What this does not claim
- n=1 per arm, one platform, single trial. Each arm is deterministic and predicted its own outcome, which is not a substitute for repetition.
- No wire capture. The canary was read back out of a completion rather than off the request, and tools were not disabled, so a model reaching for disk instead of context is not excluded on my side. The main finding is corroborated independently in #82056 by a separate reporter's run; the cd asymmetry is corroborated on two other platforms.
- Nothing about the index caps. No fixture here goes near either boundary.
Written with AI assistance (Claude); every figure re-derived from the fixtures before posting.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗