Resolve the gate's cache dir with --git-common-dir, and say when it cannot (#258) #260

Merged
JMR-dev merged 1 commits from fix/gate-cache-in-worktrees into main 2026-09-06 23:02:22 +00:00
JMR-dev commented 2026-09-06 22:54:34 +00:00 (Migrated from github.com)

Closes #258. Found by the #252 agent paying for it four times over, because the tool never said anything.

The bug

CACHE_DIR was the literal ".git/lmc-verify". In a linked worktree .git is a file, not a directory — it contains gitdir: /path/to/.git/worktrees/<name>. So:

$ cd .claude/worktrees/agent-…  &&  mkdir -p .git/lmc-verify
mkdir: cannot create directory '.git': Not a directory      (exit 1)

The write is the last thing the script does, so it failed while the gate printed green and exited 0. Every commit and push from a worktree then re-swept API 33–36 for nothing.

That is the worst shape a cache can fail in: invisible and expensive. It looks exactly like a cache that is working and simply never hits.

The fix

CACHE_DIR="$(git rev-parse --git-common-dir)/lmc-verify"

Measured in both repo shapes: .git/lmc-verify from the main checkout, the absolute real path from a worktree, mkdir exit 0 in each.

--git-common-dir rather than --git-dir, deliberately — so the cache is shared between worktrees. The key is the app/src tree hash, and identical content is identical content whichever worktree produced it. A sweep run in one is evidence for all of them, which is worth having when agents work in parallel checkouts.

And the write stops being silent

record_sweep() now prints when it cannot record:

could not record the sweep under <dir> — it will re-run next time. Not fatal, but it means every commit and push pays for it again.

Not fatal, because failing to cache a green sweep should never block a commit. But not silent either — a cache that never fills is indistinguishable from one that is working, which is precisely how this survived.

Verification

shellcheck and actionlint clean at CI's pinned digests. No app/src change, so both hook runs correctly skipped the sweep.

Closes #258. Found by the #252 agent paying for it four times over, because the tool never said anything. ## The bug `CACHE_DIR` was the literal `".git/lmc-verify"`. **In a linked worktree `.git` is a file**, not a directory — it contains `gitdir: /path/to/.git/worktrees/<name>`. So: ``` $ cd .claude/worktrees/agent-… && mkdir -p .git/lmc-verify mkdir: cannot create directory '.git': Not a directory (exit 1) ``` The write is the last thing the script does, so it failed **while the gate printed green and exited 0**. Every commit and push from a worktree then re-swept API 33–36 for nothing. That is the worst shape a cache can fail in: invisible and expensive. It looks exactly like a cache that is working and simply never hits. ## The fix ```bash CACHE_DIR="$(git rev-parse --git-common-dir)/lmc-verify" ``` Measured in both repo shapes: `.git/lmc-verify` from the main checkout, the absolute real path from a worktree, `mkdir` exit 0 in each. **`--git-common-dir` rather than `--git-dir`, deliberately** — so the cache is *shared* between worktrees. The key is the `app/src` tree hash, and identical content is identical content whichever worktree produced it. A sweep run in one is evidence for all of them, which is worth having when agents work in parallel checkouts. ## And the write stops being silent `record_sweep()` now prints when it cannot record: > `could not record the sweep under <dir> — it will re-run next time. Not fatal, but it means every commit and push pays for it again.` Not fatal, because failing to *cache* a green sweep should never block a commit. But not silent either — a cache that never fills is indistinguishable from one that is working, which is precisely how this survived. ## Verification shellcheck and actionlint clean at CI's pinned digests. No `app/src` change, so both hook runs correctly skipped the sweep.
Sign in to join this conversation.