git-validator · guard-denial circuit breaker

The guard was right 8 times in a row. Nothing it printed could break the loop.

The incident — 2026-08-10, one session, one command

shell cwd:  .worktrees/ghlabel   (branch fix/ghlabel)   ← a feature branch
hook sees:  project dir           (branch main)          ← the hook is a separate process
command:    git add -A && git commit -m "..."            no -C, no leading cd

re-sends:   ■ ■ ■ ■ ■ ■ ■ ■  8 byte-identical denials, all correct
message:    "Required workflow: 1. git checkout -b ..."  ← wrong: a branch already exists

The guard resolves the effective directory from the COMMAND STRING only, so a session already inside a worktree is indistinguishable from one sitting on the trunk. Every denial rendered identically, so the 8th carried exactly as much information as the 1st.

Try it — send the same command twice

attempts: (none yet)

Press "Send command".

What changed

(a) rewrite     deny text now prints the exact copyable git -C <abs path> <args>
                when linked worktrees on feature branches exist; alternatives listed.
                A command that already names its own -C is never rewritten.

(b) breaker     short-TTL (30 min), session-scoped ledger keyed by a hash of the
                exact command bytes. 2nd identical denial leads with a banner.
                A reworded command restarts at 1 — changing shape is the goal.

enumeration     reads <gitdir>/worktrees/*/{gitdir,HEAD} directly, never spawns
                `git worktree list` (#2970 precedent; git's locks stalled #2948).

fail-open       neither half can turn a deny into an allow. Any fs failure
                degrades to the previous plain block.