Skip to content

fix(cli): telemetry off keeps the person's own commit hook executable - #818

Merged
blafourcade merged 1 commit into
nextfrom
fix/telemetry-off-keeps-hook-executable
Sep 10, 2026
Merged

fix(cli): telemetry off keeps the person's own commit hook executable#818
blafourcade merged 1 commit into
nextfrom
fix/telemetry-off-keeps-hook-executable

Conversation

@blafourcade

Copy link
Copy Markdown
Contributor

🎯 What & why

aidd telemetry off removes the commit-trailer delegate's line from the project's prepare-commit-msg hook. It rewrote that hook through the atomic temp-file-and-rename write, which does not keep the file's mode. An executable hook came back without its executable bit. Git skips a non-executable hook without saying so, so the rest of the person's own hook stopped running. This shipped in cli 5.3.0.

🛠️ How it works

GitAdapter.stopCallingDelegate reads isExecutable before the write and calls chmodExecutable after it, only when the bit was set. Two lines. A hook that was not executable is left as it was.

🧪 How to verify

cd cli && pnpm vitest run --project integration tests/runtime/git/git-adapter.integration.test.ts
Run Result
Without the fix "drops the one line and deletes the delegate, leaving the rest of the hook" is red: hookExecutable is false
With the fix both tests pass
Restore made unconditional (if (true)) "leaves a hook that was not executable as it found it" is red: expected true to be false

Runtime and telemetry suites: 81 files, 1084 tests passed. Typecheck, lint, test:arch, knip and type honesty are clean.

⚠️ Heads-up

🔗 Linked issue

Fixes #817

✅ I certify

  • I have read the contributing guide and followed the PR template.
  • The tests were red before the fix and every gate listed above passed locally.

🤖 Generated with Claude Code

https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb

Removing the commit-trailer delegate rewrote prepare-commit-msg through
the atomic temp-and-rename write, which does not carry the mode over: a
hook that was executable came back without its bit, and git skips such a
hook silently, so the rest of the person's own hook stopped running.

The bit is read before the write and restored after it, only when it was
set. Two tests on a real temporary repository: the removal keeps the hook
executable (red without the fix), and a hook that was not executable stays
so (red with the restore made unconditional). The second is POSIX-only.

Fixes #817

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb
AIDD-Session-Id: 4acc9a1c-19bc-4468-b8b6-e86644bcba60
@blafourcade
blafourcade requested a review from a team as a code owner September 10, 2026 08:43
blafourcade added a commit that referenced this pull request Sep 10, 2026
GitAdapter gets its first test, against a real temporary repository: hook install and
removal under this CLI and under lefthook or husky, core.hooksPath, the trailer count and
every answer of readCommitTrailerSetup. The auth adapters, the self-updater, the file
adapter, the prompter, the HTTP client, the update check, the release resolver, the
project-root and git-environment helpers and the composition root (createDeps, wireTools,
the build registry) are asserted on their exact commands, messages, headers and shapes.

The removal test found a defect rather than a mutant: prepare-commit-msg lost its
executable bit. The fix ships on its own in #818, which this branch sits on.

Runtime scope, every mutant replayed: 69.8 to 92.2 (killed 1182, timeout 16, survived 88,
uncovered 13 of 1299). Floor raised from 67 to 90.

Two POSIX-only checks skip where the platform cannot show them: a mode bit on Windows, and
a read-only directory on Windows or as root.

Refs #799

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb
AIDD-Session-Id: 4acc9a1c-19bc-4468-b8b6-e86644bcba60
@blafourcade
blafourcade merged commit 4146c2c into next Sep 10, 2026
24 checks passed
@blafourcade
blafourcade deleted the fix/telemetry-off-keeps-hook-executable branch September 10, 2026 20:10
@blafourcade
blafourcade restored the fix/telemetry-off-keeps-hook-executable branch September 10, 2026 20:12
blafourcade added a commit that referenced this pull request Sep 10, 2026
GitAdapter gets its first test, against a real temporary repository: hook install and
removal under this CLI and under lefthook or husky, core.hooksPath, the trailer count and
every answer of readCommitTrailerSetup. The auth adapters, the self-updater, the file
adapter, the prompter, the HTTP client, the update check, the release resolver, the
project-root and git-environment helpers and the composition root (createDeps, wireTools,
the build registry) are asserted on their exact commands, messages, headers and shapes.

The removal test found a defect rather than a mutant: prepare-commit-msg lost its
executable bit. The fix ships on its own in #818, which this branch sits on.

Runtime scope, every mutant replayed: 69.8 to 92.2 (killed 1182, timeout 16, survived 88,
uncovered 13 of 1299). Floor raised from 67 to 90.

Two POSIX-only checks skip where the platform cannot show them: a mode bit on Windows, and
a read-only directory on Windows or as root.

Refs #799

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb
AIDD-Session-Id: 4acc9a1c-19bc-4468-b8b6-e86644bcba60
blafourcade added a commit that referenced this pull request Sep 10, 2026
…819)

* test(cli): kill the surviving mutants of the kernel

Every error class now has its exact name and message pinned, and the pure kernel helpers
that had no test of their own (jsonc stripping, confined file names, the JSON narrowers,
describeError, isMergeContentEmpty, removeRedundantGitkeeps) get one. The frontmatter
parser, semver precedence, plugin-source messages and the built-cache path parsers are
asserted structure by structure, so a dropped anchor, a swapped join or a missing branch
turns a test red.

Kernel scope, every mutant replayed: 75.2 to 97.1 (killed 1449, timeout 32, survived 45,
uncovered 0 of 1526). The 45 left are documented equivalents plus seven stryker records
as survived although the hand-applied mutation turns the named test red. Floor raised
from 71 to 95.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb
AIDD-Session-Id: 4acc9a1c-19bc-4468-b8b6-e86644bcba60

* test(cli): kill the surviving mutants of the runtime

GitAdapter gets its first test, against a real temporary repository: hook install and
removal under this CLI and under lefthook or husky, core.hooksPath, the trailer count and
every answer of readCommitTrailerSetup. The auth adapters, the self-updater, the file
adapter, the prompter, the HTTP client, the update check, the release resolver, the
project-root and git-environment helpers and the composition root (createDeps, wireTools,
the build registry) are asserted on their exact commands, messages, headers and shapes.

The removal test found a defect rather than a mutant: prepare-commit-msg lost its
executable bit. The fix ships on its own in #818, which this branch sits on.

Runtime scope, every mutant replayed: 69.8 to 92.2 (killed 1182, timeout 16, survived 88,
uncovered 13 of 1299). Floor raised from 67 to 90.

Two POSIX-only checks skip where the platform cannot show them: a mode bit on Windows, and
a read-only directory on Windows or as root.

Refs #799

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb
AIDD-Session-Id: 4acc9a1c-19bc-4468-b8b6-e86644bcba60

* test(cli): skip the trailer setup's mode-bit checks on Windows

Windows CI failed two readCommitTrailerSetup tests that expect a hook or
a delegate to read as not executable: there `access(X_OK)` answers like
`F_OK`, so every existing file reads as executable, and git needs no mode
bit to run a hook. They skip on Windows, as the removal test already does.

Refs #799

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb
AIDD-Session-Id: 4acc9a1c-19bc-4468-b8b6-e86644bcba60

* test(cli): name the mode-bit skip once in the git adapter tests

The same Windows explanation sat above three skips. Stacked with the
telemetry tests, the repetition pushed tests/ past its comment baseline
(2989 against 2987); one named predicate says it once.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb
AIDD-Session-Id: 4acc9a1c-19bc-4468-b8b6-e86644bcba60

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
blafourcade added a commit that referenced this pull request Sep 11, 2026
GitHub closes a pull request whose base branch is deleted, unless the merge
itself deletes it. Deleting the base of #819 through the API after #818
merged closed #819 instead of retargeting it. `vcs.md` now says to retarget
first, and how to replay a dependent branch after its base was squashed.

Fixes #843


Claude-Session: https://claude.ai/code/session_011x4ms5qcGuZgYhCxfdHMUb
AIDD-Session-Id: 4acc9a1c-19bc-4468-b8b6-e86644bcba60

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@blafourcade
blafourcade deleted the fix/telemetry-off-keeps-hook-executable branch September 11, 2026 07:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant