An explicit push destination needs no working directory

closes #3455 · git-validator worktree false-DENY

Try a command (pretend the session dir is on main)

Before
.
After (this PR)
.

The bug

Every commit and push from a linked worktree was denied as "Cannot commit or push directly to 'main' branch", including commands that named a feature branch as their destination.

The guard's own comments explain why. Resolution order is git -C <path>, then session-state shell_cwd — and that second path is dead:

// git-validator.ts:190
// "in 1763 recorded sessions no state file ever gained a shell_cwd (#3411)
//  ... `git push` from a worktree was therefore judged against the project dir"

So without an explicit -C, branch resolution falls back to the primary checkout, which is on main. Unknown cwd resolved to DENY.

Why the destination is sufficient on its own

If every git push in a command names its destination and none is protected, the command cannot touch a protected remote ref regardless of which directory it runs in. No cwd knowledge required.

Scope note worth stating: this deliberately covers git commit && git push origin <feature> too. Restricting it to push-only commands would have fixed neither real-world report. A commit in that chain is local-only; the protected remote ref is provably untouched, which is what "push directly to main" guards.

The laundering case

The parser is all-or-nothing on purpose. One unresolvable push must not be vouched for by a sibling that happens to name a feature branch:

git push origin feat/x && git push
// second push resolves through upstream: unknowable
// -> extractPushDestinations returns null -> falls through to the old path

A bare git push can still reach main via upstream config, so it is never treated as proof of anything.

Cases

CommandBeforeAfter

What this does not fix

This is part A of #3455. The deeper defect stands: when cwd is genuinely unresolvable and the command names no destination (a bare git push, or a plain git commit), the guard still resolves ambiguity to DENY. Part B is to make that case ASK, or to fix shell_cwd (#3411) so the second resolution path stops being dead.