Development record
ahoy install writes .githooks/pre-commit but leaves 'git config core.hooksPath .githooks' to the user, so the hook is committed but not running on the clone that just installed it. Detection knows this (hooks_path_armed=false) yet emits no gap for it. Proposal: a user-state gap that arms the clone after checking .git/hooks has no non-sample hooks the redirect would bypass, refusing with a note when it does.
ahoy install writes .githooks/pre-commit but leaves 'git config core.hooksPath .githooks' to the user, so the hook is committed but not running on the clone that just installed it. Detection knows this (hooks_path_armed=false) yet emits no gap for it. Proposal: a user-state gap that arms the clone after checking .git/hooks has no non-sample hooks the redirect would bypass, refusing with a note when it does.
Relocated from another repository's ledger on 2026-09-15. It was captured by an
ahoy install onboarding session whose working directory was a teaching-materials
repository, so the finding landed where nothing could resolve or detect it: that
tree has no installer, no plugin root and no ~/.local/bin surface. The id,
the found_during stamp and the body are unchanged; only the ledger it sits in
has moved. The store resolved correctly — it wrote to the repository it was
standing in — and the reason nothing refused the write is recorded as
iss-2609120511058115.
Remedy grounds (2026-09-29)
- The pre-commit framework refuses to install when core.hooksPath is set rather than override a person's hook dispatcher: https://github.com/pre-commit/pre-commit/issues/1198 and https://github.com/pre-commit/pre-commit/issues/1298 (consulted 2026-09-29), the same override the deferral names, so the automatic branch copies that refusal.
- Rejected: arming unconditionally, which silently disables a person's global hooks in that clone.
Evidence 2026-10-08 (overnight drain)
Once run-2610080127501542 (iss-2610020704152920) lands, ahoy reports hooks_path as armed, unarmed or foreign, and hooks_path_armed reads true for a global .githooks too. A check for this gap should read hooks_path == "unarmed", not hooks_path_armed == false, or it reports a clone under a global hooks dispatcher as a false gap.
Frontmatter
| id | iss-2609120447480903 |
|---|---|
| type | issue |
| lifecycle | open |
| severity | minor |
.abcd/work/issues/open/iss-2609120447480903-ahoy-install-writes-githooks-pre-commit.md
open on GitHub ↗ · commit history ↗
mentions2
- iss-2609120511058115Nine findings about abcd's own installer are sitting in a teaching-materials
- iss-2610020704152920banlist.hooks_path_armed reports false, in the bare ahoy status and in --json, when the committed .githooks/ hooks are reached through a global core.hooksPath dispatcher that chains to them: a false negative. hooksPathArmed (internal/core/ahoy/banlist_scaffold.go) reads only git config --local core.hooksPath and compares it to the clone's .githooks, so it cannot see a global hooks path, and it never asks whether the hook actually runs. Reproduced at tip with a scratch global gitconfig whose core.hooksPath names a dispatcher that runs <toplevel>/.githooks/pre-commit and then .git/hooks/pre-commit: 'git hook run pre-commit' ran abcd's name guard and exited 0, yet hooks_path_armed was false and the bare status said '(arm this clone: git config core.hooksPath .githooks)'. Following that advice sets a local core.hooksPath that overrides the person's global dispatcher in this clone, dropping whatever else it chains, so the false negative turns into harmful advice. Related: open iss-2609120447480903 proposes raising a gap on hooks_path_armed=false, which would make this a false gap.