Skip to content

test: cover stale Claude hook pruning#271

Merged
Gradata merged 1 commit into
mainfrom
gra-2052-prune-stale-hooks
Jun 8, 2026
Merged

test: cover stale Claude hook pruning#271
Gradata merged 1 commit into
mainfrom
gra-2052-prune-stale-hooks

Conversation

@Gradata

@Gradata Gradata commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds a GRA-2052 regression test for Claude Code hook install pruning stale Gradata hook entries across PostToolUse, PreCompact, PreToolUse, and Stop.
  • Covers the exact stale temp brain paths reported in the issue.
  • Verifies reinstall leaves only the current production brain hook command per module.

Verification

  • env -u BRAIN_DIR -u GRADATA_BRAIN python3 -m pytest tests/test_hook_adapters.py -q → 22 passed
  • env -u BRAIN_DIR -u GRADATA_BRAIN python3 -m pytest tests/test_cli_install_agent.py tests/test_hook_adapters.py -q → 31 passed, 1 skipped
  • git diff --check → passed
  • /home/olive/.local/bin/uvx ruff check tests/test_hook_adapters.py → All checks passed

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Gradata, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 23 minutes and 6 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3d20cf2c-9b72-46c5-8cc1-2ff5670cccd9

📥 Commits

Reviewing files that changed from the base of the PR and between 7ee0f2a and a816dc3.

📒 Files selected for processing (1)
  • Gradata/tests/test_hook_adapters.py
📝 Walkthrough

Walkthrough

A regression test is added to test_hook_adapters.py that verifies the Claude Code adapter prunes stale temp-brain hook entries across multiple hook events during install() and formats remaining hook commands correctly.

Changes

Claude Code Hook Pruning Test

Layer / File(s) Summary
Regression test for stale hook pruning
Gradata/tests/test_hook_adapters.py
Import sys module and add test_claude_code_install_prunes_stale_temp_brain_hooks_across_events that seeds the Claude Code adapter config with multiple stale temp-brain entries across several hook events, invokes install(), verifies stale paths are removed, and asserts each affected event's remaining hook command matches the expected BRAIN_DIR=<brain_dir> sys.executable -m gradata.hooks.<module> form.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Possibly related PRs

  • Gradata/gradata#248: The regression test directly exercises the Claude hook install deduping and stale entry removal behavior introduced in #248.
  • Gradata/gradata#242: The test validates the Claude Code adapter install/uninstall logic refactored in #242 that governs how per-event hook entries are written and removed.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'test: cover stale Claude hook pruning' accurately and concisely describes the main change: adding a test to cover the pruning of stale Claude Code hooks, which is the primary purpose of this pull request.
Description check ✅ Passed The description clearly relates to the changeset by explaining the regression test being added (GRA-2052), the hook points it covers, and providing verification that the test passes along with other tests and linting checks.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gra-2052-prune-stale-hooks

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Gradata/tests/test_hook_adapters.py`:
- Around line 319-326: The test builds the expected hook command string manually
which doesn't account for quoting used by hook_command(), so replace the manual
expected value with a call to hook_command(...) to match implementation;
specifically, in the loop over stale_by_event (and where you collect
hook["command"] from settings["hooks"][event]), assert commands ==
[hook_command(brain_dir, module)] (import or reference the existing hook_command
function) so both brain_dir and sys.executable are quoted the same way as
production.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3cb9b738-778f-4d64-8e68-24d56c5e2f38

📥 Commits

Reviewing files that changed from the base of the PR and between acde088 and 7ee0f2a.

📒 Files selected for processing (1)
  • Gradata/tests/test_hook_adapters.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: pytest macos-latest / py3.11
  • GitHub Check: pytest windows-latest / py3.11
  • GitHub Check: pytest (py3.11)
  • GitHub Check: pytest ubuntu-latest / py3.12
  • GitHub Check: pytest ubuntu-latest / py3.11
  • GitHub Check: pytest macos-latest / py3.12
  • GitHub Check: pytest windows-latest / py3.12
  • GitHub Check: pytest (py3.12)
🧰 Additional context used
📓 Path-based instructions (1)
Gradata/tests/**/*.py

📄 CodeRabbit inference engine (Gradata/AGENTS.md)

Gradata/tests/**/*.py: Set BRAIN_DIR environment variable via tmp_path in conftest.py for test isolation — ensure _paths.py module cache refreshes when calling Brain.init() directly inside tests
Add unit tests in tests/test_*.py for every CI push without LLM calls (deterministic); mark integration tests with @pytest.mark.integration and skip them by default (they hit real LLM APIs)

Files:

  • Gradata/tests/test_hook_adapters.py
🧠 Learnings (3)
📓 Common learnings
Learnt from: Gradata
Repo: Gradata/gradata PR: 0
File: :0-0
Timestamp: 2026-04-17T17:18:07.439Z
Learning: In PR `#102` (gradata/gradata), Round 2 addressed: cli.py env-first brain resolution (GRADATA_BRAIN > --brain-dir > cwd), _tenant.py corrupt .tenant_id overwrite, _env_int default clamping to minimum, and _events.py tenant-scoped fallback SELECT for dedup. All ruff and 99 tests green after these fixes.
📚 Learning: 2026-05-01T15:50:32.772Z
Learnt from: CR
Repo: Gradata/gradata PR: 0
File: Gradata/AGENTS.md:0-0
Timestamp: 2026-05-01T15:50:32.772Z
Learning: Applies to Gradata/tests/**/*.py : Set `BRAIN_DIR` environment variable via `tmp_path` in conftest.py for test isolation — ensure `_paths.py` module cache refreshes when calling `Brain.init()` directly inside tests

Applied to files:

  • Gradata/tests/test_hook_adapters.py
📚 Learning: 2026-04-17T17:18:07.439Z
Learnt from: Gradata
Repo: Gradata/gradata PR: 0
File: :0-0
Timestamp: 2026-04-17T17:18:07.439Z
Learning: In PR `#102` (gradata/gradata), Round 2 addressed: cli.py env-first brain resolution (GRADATA_BRAIN > --brain-dir > cwd), _tenant.py corrupt .tenant_id overwrite, _env_int default clamping to minimum, and _events.py tenant-scoped fallback SELECT for dedup. All ruff and 99 tests green after these fixes.

Applied to files:

  • Gradata/tests/test_hook_adapters.py
🔇 Additional comments (2)
Gradata/tests/test_hook_adapters.py (2)

5-5: LGTM!


265-318: LGTM!

Comment on lines +319 to +326
for event, (_matcher, module) in stale_by_event.items():
commands = [
hook["command"]
for group in settings["hooks"][event]
for hook in group["hooks"]
if f"gradata.hooks.{module}" in hook["command"]
]
assert commands == [f"BRAIN_DIR={brain_dir} {sys.executable} -m gradata.hooks.{module}"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Use hook_command() for assertion to match implementation quoting.

The assertion constructs the expected command manually, but hook_command() (from context snippet 1) uses shlex.quote() for both brain_dir and sys.executable. If paths contain special characters (spaces, quotes), this assertion will fail even when the code is correct.

♻️ Refactor to use hook_command
+from gradata.hooks.adapters._base import AGENTS, adapter_config_path, get_adapter, hook_command
-from gradata.hooks.adapters._base import AGENTS, adapter_config_path, get_adapter
     for event, (_matcher, module) in stale_by_event.items():
         commands = [
             hook["command"]
             for group in settings["hooks"][event]
             for hook in group["hooks"]
             if f"gradata.hooks.{module}" in hook["command"]
         ]
-        assert commands == [f"BRAIN_DIR={brain_dir} {sys.executable} -m gradata.hooks.{module}"]
+        assert commands == [hook_command(brain_dir, module)]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Gradata/tests/test_hook_adapters.py` around lines 319 - 326, The test builds
the expected hook command string manually which doesn't account for quoting used
by hook_command(), so replace the manual expected value with a call to
hook_command(...) to match implementation; specifically, in the loop over
stale_by_event (and where you collect hook["command"] from
settings["hooks"][event]), assert commands == [hook_command(brain_dir, module)]
(import or reference the existing hook_command function) so both brain_dir and
sys.executable are quoted the same way as production.

@Gradata Gradata force-pushed the gra-2052-prune-stale-hooks branch from 7ee0f2a to a816dc3 Compare June 8, 2026 06:58

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@Gradata Gradata merged commit 2b12800 into main Jun 8, 2026
7 of 9 checks passed
@Gradata Gradata deleted the gra-2052-prune-stale-hooks branch June 8, 2026 06:59
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