Summary
install-git-hooks --check exits 1 for a core.hooksPath clone even when that
directory has been wired exactly the way the installer itself prescribes,
and the verdict line then states something false: "commits are NOT gated".
The check never looks at the redirected directory. check_shims only ever reads
$HOOKS_DIR ($(git rev-parse --git-path hooks)), and the HOOKS_PATH_SET
branch converts a clean result into "dormant … exit 1" without probing
$CUSTOM_HOOKS.
Why it matters
The installer stands down under core.hooksPath on purpose and prints the
hand-wiring instructions. A consumer that follows those instructions is fully
gated — and --check still calls them ungated. Any consumer that puts
--check into a canonical validation command (drovr now has it first in
pnpm verify, DRO-258) makes that command permanently red for a configuration
the installer's own output told the user to adopt.
Reproduction
mkdir -p /tmp/hp/customhooks && cd /tmp/hp && git init -q .
install-git-hooks --repo /tmp/hp # normal install
# wire the redirected directory exactly as the installer prescribes
S=<growth-guards>/scripts
printf '#!/bin/sh\nexec %s/pre-commit "$@"\n' "$S" > customhooks/pre-commit
printf '#!/bin/sh\nexec %s/commit-msg "$1"\n' "$S" > customhooks/commit-msg
chmod +x customhooks/pre-commit customhooks/commit-msg
git config core.hooksPath customhooks
install-git-hooks --repo /tmp/hp --check
Observed:
growth-guards git hooks: dormant — core.hooksPath ('customhooks') redirects git
away from /tmp/hp/.git/hooks, so commits are NOT gated; wire that directory's
hooks to <…>/scripts, or unset core.hooksPath
exit 1
Commits in that clone ARE gated. Exit 1 with that wording is wrong on both counts.
Suggested fix
When core.hooksPath is set, resolve it (relative to the work tree, as git
does) and run the same check_hook predicate against $CUSTOM_HOOKS/pre-commit
and $CUSTOM_HOOKS/commit-msg — the wiring the installer prints is a shim that
execs the chain, so the predicate needs a second accepted shape ("delegates to
this skill's pre-commit/commit-msg") beside the line-2 sentinel it matches
today. Three outcomes rather than one:
- redirected directory wired to this skill → armed (exit 0), stating that
the gating is via core.hooksPath;
- redirected directory present but not wired → dormant / NOT armed (exit 1),
which is today's message and is then accurate;
- redirected directory unreadable → could not determine (exit 2), matching
the fail-to-measure rule the rest of --check already follows.
Keeping the conservative exit 1 for the unwired case is right; it is the wired
case that has no way to report the truth today.
Notes
Found while adopting vstack#1482 in drovr (vanillagreencom/drovr#598). drovr is
keeping --check first in pnpm verify regardless, because the un-hand-wired
case really is ungated and that is the safe failure direction — the bound is
recorded there rather than worked around.
Summary
install-git-hooks --checkexits 1 for acore.hooksPathclone even when thatdirectory has been wired exactly the way the installer itself prescribes,
and the verdict line then states something false: "commits are NOT gated".
The check never looks at the redirected directory.
check_shimsonly ever reads$HOOKS_DIR($(git rev-parse --git-path hooks)), and theHOOKS_PATH_SETbranch converts a clean result into "dormant … exit 1" without probing
$CUSTOM_HOOKS.Why it matters
The installer stands down under
core.hooksPathon purpose and prints thehand-wiring instructions. A consumer that follows those instructions is fully
gated — and
--checkstill calls them ungated. Any consumer that puts--checkinto a canonical validation command (drovr now has it first inpnpm verify, DRO-258) makes that command permanently red for a configurationthe installer's own output told the user to adopt.
Reproduction
Observed:
Commits in that clone ARE gated. Exit 1 with that wording is wrong on both counts.
Suggested fix
When
core.hooksPathis set, resolve it (relative to the work tree, as gitdoes) and run the same
check_hookpredicate against$CUSTOM_HOOKS/pre-commitand
$CUSTOM_HOOKS/commit-msg— the wiring the installer prints is a shim thatexecs the chain, so the predicate needs a second accepted shape ("delegates tothis skill's
pre-commit/commit-msg") beside the line-2 sentinel it matchestoday. Three outcomes rather than one:
the gating is via
core.hooksPath;which is today's message and is then accurate;
the fail-to-measure rule the rest of
--checkalready follows.Keeping the conservative exit 1 for the unwired case is right; it is the wired
case that has no way to report the truth today.
Notes
Found while adopting vstack#1482 in drovr (vanillagreencom/drovr#598). drovr is
keeping
--checkfirst inpnpm verifyregardless, because the un-hand-wiredcase really is ungated and that is the safe failure direction — the bound is
recorded there rather than worked around.