Skip to content

feat: add WHAT/FIX/REF remediation format to all denial messages#44

Merged
frits-v merged 10 commits intomainfrom
feat/remediation-messages
Mar 26, 2026
Merged

feat: add WHAT/FIX/REF remediation format to all denial messages#44
frits-v merged 10 commits intomainfrom
feat/remediation-messages

Conversation

@frits-v
Copy link
Copy Markdown
Owner

@frits-v frits-v commented Mar 26, 2026

Summary

  • Restructure all hook denial messages to follow WHAT/FIX/REF remediation format (directive 22)
    • lib.rs: WORKTREE_MISSING includes WHAT/FIX/REF
    • sandbox.rs: REDIRECT and fallback BLOCKED messages use WHAT/FIX/REF
    • gitcheck.rs: all 8 git safety blocks + worktree enforcement use WHAT/FIX/REF
  • Sync CLAUDE.md test count to 246 with full breakdown
  • Mention rusqlite as memory crate dependency

Reference: .agents/research/harness.md Pillar 2c — custom linters with remediation messages.

Test plan

  • cargo test — all 246 tests pass
  • cargo clippy — no warnings
  • cargo fmt --check — clean
  • CI green

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fa5acd8c-ad7a-4441-8b3f-fc6c387e5425

📥 Commits

Reviewing files that changed from the base of the PR and between 4226397 and 4af11a4.

📒 Files selected for processing (6)
  • .coderabbit.yaml
  • CLAUDE.md
  • greptile.json
  • hooks/src/gitcheck.rs
  • hooks/src/lib.rs
  • hooks/src/sandbox.rs
✅ Files skipped from review due to trivial changes (4)
  • CLAUDE.md
  • hooks/src/lib.rs
  • greptile.json
  • hooks/src/sandbox.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • hooks/src/gitcheck.rs

📝 Walkthrough

Walkthrough

Standardizes hook denial/error messages into a WHAT/FIX/REF remediation format across hooks and updates repository metadata: punctuation and test totals in CLAUDE.md, and adds rusqlite mention for the memory crate; introduces .coderabbit.yaml and greptile.json configuration files for review/enforcement automation.

Changes

Cohort / File(s) Summary
Documentation
CLAUDE.md
Added trailing period after resolve_readonly() in the “H-4 purity” rule; updated total tests from 219 → 246 with a more granular breakdown (hook/unit/integration categories); documented that the memory crate adds rusqlite while retaining the “5 crates” list and existing constraints.
Hook denial messages — git safety
hooks/src/gitcheck.rs
Converted single-line BLOCKED: denial texts (FR-GS-1..FR-GS-8) to multi-line WHAT: / FIX: / REF: remediation format; updated remediation wording, recommended git commands (wrapped in backticks), and adjusted suggested git -C worktree paths to include trailing slashes.
Hook denial messages — worktree missing
hooks/src/lib.rs
Rewrote worktree_missing_msg(repo: &str) -> String to emit a structured WHAT/FIX/REF denial while preserving the WORKTREE_MISSING:{repo} prefix; interpolates ensure-worktree binary path, quotes repo, wraps the run command in backticks, and adds a docs/architecture.md#key-invariants reference.
Hook denial messages — sandbox/path checks
hooks/src/sandbox.rs
Reformatted path-write denials in check_path_with_context to WHAT/FIX/REF style; for resolved system/private paths includes resolved target; for session → main-checkout writes computes explicit wt_path (.worktrees/{sess.short_id}) and embeds it in FIX guidance; revised messages for missing worktrees/repo-extraction failures.
Reviewer / automation configs
.coderabbit.yaml, greptile.json
Added .coderabbit.yaml and greptile.json to enable automated review/enforcement: conventional-commit/title/docstring checks, denial-message/token/architecture rules, fail-closed panic and I/O constraints for hooks, and AI-assisted fix/comment behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 8
✅ Passed checks (8 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commit format with a clear 'feat' type, concise lowercase description in imperative mood, and is within the 72-character guideline at 64 characters.
Description check ✅ Passed The description is well-related to the changeset, providing context about WHAT/FIX/REF remediation format changes, specific files affected, documentation updates, and a test plan.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Claude.Md Stays In Sync ✅ Passed CLAUDE.md accurately documents binary count (5), dependency count (5), all crate names backtick-quoted, rusqlite mention in memory crate, Architecture tree matches actual files, and test count (246) reflects PR updates.
Panic = Deny In All Binaries ✅ Passed PR modifies only library modules and configuration files; no binary files under hooks/src/bin/ are changed.
H-4 Purity: Permissions Never Writes ✅ Passed The PR introduces hooks/src/bin/permissions.rs with 260 lines correctly implementing H-4 purity requirement using only session::resolve_readonly() and no file write operations.
Architecture Boundaries Enforced ✅ Passed PR successfully implements WHAT/FIX/REF format in all denial messages across gitcheck.rs, sandbox.rs, and lib.rs with correct REDIRECT exception.
Harness Engineering Principles ✅ Passed PR successfully implements all harness engineering principles including message actionability, fail-closed error handling, and comprehensive test coverage for security-critical files.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/remediation-messages

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

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 26, 2026

Greptile Summary

This PR reformats denial messages in gitcheck.rs, sandbox.rs, and lib.rs to follow the WHAT/FIX/REF remediation format (directive 22), adds rusqlite mention to CLAUDE.md's dependency description, syncs the test count to 246, and introduces two reviewer-configuration files (.coderabbit.yaml, greptile.json).\n\n- All 8 git safety blocks in gitcheck.rs, all worktree-enforcement messages, the system-path denials in sandbox.rs, the fallback blocked message, and worktree_missing_msg in lib.rs now carry WHAT/FIX/REF tokens\n- The exempt REDIRECT: config path must persist across sessions message in sandbox.rs is correctly left unchanged\n- The WORKTREE_MISSING:{repo} sentinel prefix is preserved, so integration tests and lazy-worktree trigger logic remain intact\n- All REF anchors resolve to real sections in the repository\n- No logic changes — the reformatting is limited to string literals; existing tests do not assert on exact old message text

Confidence Score: 5/5

Safe to merge — changes are purely string-literal reformatting with no logic changes, all REF anchors verified valid, exempt message preserved, and WORKTREE_MISSING sentinel intact.

All denial messages in the three required files now carry WHAT/FIX/REF tokens. Every REF anchor points to a real section. The single exempt REDIRECT message is untouched. The WORKTREE_MISSING: prefix that integration tests depend on is preserved. No tests assert on the old exact message text.

No files require special attention — all changes are confined to string literals and documentation.

Important Files Changed

Filename Overview
hooks/src/gitcheck.rs All 8 FR-GS denial messages and 3 worktree-enforcement messages reformatted to WHAT/FIX/REF; no logic changes, tests only assert on GitResult::Block(_) variant not message content
hooks/src/sandbox.rs System-path denials (FR-PS-1) and FR-WE-1/WE-2 fallback reformatted to WHAT/FIX/REF; exempt REDIRECT config-path message correctly left unchanged; WORKTREE_MISSING prefix preserved
hooks/src/lib.rs worktree_missing_msg updated to WHAT/FIX/REF format while preserving the WORKTREE_MISSING:{repo} sentinel prefix that integration tests and lazy-worktree logic depend on
CLAUDE.md Test count synced to 246 with detailed per-category breakdown; rusqlite added to dependency description
.coderabbit.yaml New CodeRabbit reviewer config encoding the same invariants as the greptile.json custom rules
greptile.json New Greptile reviewer config with six custom rules; correctly self-excluded from review via ignorePatterns

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Claude Code tool call] --> B{permissions hook}
    B --> C{File write?}
    B --> D{Bash command?}
    C --> E[sandbox::check_path_with_context]
    E --> F{System path?}
    F -->|yes| G["Deny — WHAT/FIX/REF\nREF: architecture.md#forbidden-dependencies"]
    F -->|no| H{Worktree active?}
    H -->|config persist path| I["Deny — REDIRECT: config path must persist\n(exempt from WHAT/FIX/REF)"]
    H -->|main checkout| J["Deny — WHAT/FIX/REF\nREF: architecture.md#key-invariants"]
    H -->|no worktree| K["Deny — WORKTREE_MISSING:repo + WHAT/FIX/REF"]
    D --> L[gitcheck::check_git_safety]
    L -->|FR-GS-1..8 matched| M["Block — WHAT/FIX/REF\nREF: CLAUDE.md#…"]
    L -->|ok| N[gitcheck::check_worktree_enforcement]
    N -->|main checkout targeted| O["Deny — WHAT/FIX/REF\nREF: architecture.md#key-invariants"]
    N -->|ok| P[Allow]
Loading

Reviews (7): Last reviewed commit: "fix(sandbox): migrate FR-PS-1 system pat..." | Re-trigger Greptile

Comment thread hooks/src/gitcheck.rs Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
hooks/src/sandbox.rs (1)

133-136: Inconsistency: Persistent config redirect message still uses "REDIRECT:" prefix.

Lines 133-136 retain the old REDIRECT: format while Lines 170-174 were updated to WHAT:/FIX:/REF:. If the PR intends to standardize on WHAT/FIX/REF for all denial messages, this block should also be updated.

If the difference is intentional (REDIRECT for config paths vs WHAT for main checkout writes), the test at Line 849 correctly expects "REDIRECT" for config paths — but then Lines 170-174 shouldn't have been reached for config paths. Verify the test expectations align with the intended behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/src/sandbox.rs` around lines 133 - 136, The denial message in the
PathDecision::Deny branch that returns the persistent config redirect currently
uses the old "REDIRECT:" prefix while other denial messages were standardized to
the "WHAT:/FIX:/REF:" format; update that return string (the PathDecision::Deny
that composes the message with repo_prefix and after_id) to use the standardized
"WHAT:/FIX:/REF:" fields (providing WHAT, FIX, and REF text consistent with
other denials), and then update any tests that assert the old "REDIRECT" prefix
(or, if the "REDIRECT" behavior is intentional, ensure the other standardized
messages are adjusted instead so tests and behavior remain consistent).
hooks/src/gitcheck.rs (1)

74-78: Consider: Message format inconsistency with permissions.rs.

This file now uses WHAT:/FIX:/REF: format for denials, but per relevant snippets, permissions.rs still emits BLOCKED: prefixed messages (e.g., Lines 43-50, 203-211, 222-226). If agents parse denial output by prefix to categorize errors or trigger remediation, this inconsistency could cause issues.

This may be intentional scope for this PR, but worth confirming whether permissions.rs should be updated in a follow-up to ensure consistent agent-parseable output.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/src/gitcheck.rs` around lines 74 - 78, check_git_safety currently emits
denial messages using the WHAT:/FIX:/REF: format while permissions.rs still
emits BLOCKED:-prefixed messages, causing inconsistent, parse-unstable outputs;
pick one canonical denial format and make the other match it (either update
permissions.rs emitters that produce "BLOCKED:" to instead emit the
WHAT:/FIX:/REF: structure, or change check_git_safety to emit "BLOCKED:"),
updating all relevant message constructors/return paths in permissions.rs and
the check_git_safety function so agents can consistently parse prefixes (search
for the "BLOCKED:" literal and the check_git_safety function to locate and
change the emitters).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hooks/src/gitcheck.rs`:
- Around line 84-88: The denial message passed to GitResult::Block uses a
backslash-continued multi-line string that fails rustfmt; replace that with a
rustfmt-friendly form (for example a raw string literal r#"..."#, or use concat!
to join single-line literals) for the GitResult::Block call so the WHAT/FIX/REF
message is formatted as one clean string literal (preserve the exact text:
"WHAT: Force push without --force-with-lease. FIX: Use `git push
--force-with-lease origin <branch>` instead. REF:
CLAUDE.md#supply-chain-policy").

In `@hooks/src/sandbox.rs`:
- Around line 170-174: The failure is caused by changing the redirect message
format in PathDecision::Deny so it no longer contains "REDIRECT", breaking the
test_worktree_config_paths_redirected assertion; fix by either restoring the
"REDIRECT:" token in the deny message (update the PathDecision::Deny(...) format
string to include "REDIRECT: ..." or prepend "REDIRECT" alongside the new
"WHAT/FIX/REF" content) or by updating the test_worktree_config_paths_redirected
assertion to look for the new marker(s) (e.g., check for "WHAT" or the combined
"REDIRECT" + new format) so both the message in sandbox.rs and the test remain
consistent.
- Around line 166-174: The formatting of the multi-line format! call that builds
the deny message (around the wt_path and PathDecision::Deny usage in sandbox.rs)
is off; run rustfmt (cargo fmt) to reformat the file, or adjust the string
literal to a single properly formatted expression so that cargo fmt passes
(ensure the format! invocation wrapping the message and {wt_path} is formatted
according to rustfmt).
- Around line 197-201: The string literal passed to PathDecision::Deny in
sandbox.rs is not formatted to Rustfmt's rules; run `cargo fmt` to auto-fix or
replace the escaped multi-line literal with a properly formatted/raw string so
rustfmt can wrap it (e.g., use a raw string r#"..."# or concatenate short string
literals) and keep the return as PathDecision::Deny(... .into()) so the symbol
PathDecision::Deny and its message formatting are preserved.

---

Nitpick comments:
In `@hooks/src/gitcheck.rs`:
- Around line 74-78: check_git_safety currently emits denial messages using the
WHAT:/FIX:/REF: format while permissions.rs still emits BLOCKED:-prefixed
messages, causing inconsistent, parse-unstable outputs; pick one canonical
denial format and make the other match it (either update permissions.rs emitters
that produce "BLOCKED:" to instead emit the WHAT:/FIX:/REF: structure, or change
check_git_safety to emit "BLOCKED:"), updating all relevant message
constructors/return paths in permissions.rs and the check_git_safety function so
agents can consistently parse prefixes (search for the "BLOCKED:" literal and
the check_git_safety function to locate and change the emitters).

In `@hooks/src/sandbox.rs`:
- Around line 133-136: The denial message in the PathDecision::Deny branch that
returns the persistent config redirect currently uses the old "REDIRECT:" prefix
while other denial messages were standardized to the "WHAT:/FIX:/REF:" format;
update that return string (the PathDecision::Deny that composes the message with
repo_prefix and after_id) to use the standardized "WHAT:/FIX:/REF:" fields
(providing WHAT, FIX, and REF text consistent with other denials), and then
update any tests that assert the old "REDIRECT" prefix (or, if the "REDIRECT"
behavior is intentional, ensure the other standardized messages are adjusted
instead so tests and behavior remain consistent).
🪄 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: CHILL

Plan: Pro

Run ID: 1299f601-104f-4166-96b7-44443b779260

📥 Commits

Reviewing files that changed from the base of the PR and between 1312071 and 115899b.

📒 Files selected for processing (4)
  • CLAUDE.md
  • hooks/src/gitcheck.rs
  • hooks/src/lib.rs
  • hooks/src/sandbox.rs

Comment thread hooks/src/gitcheck.rs
Comment thread hooks/src/sandbox.rs Outdated
Comment thread hooks/src/sandbox.rs
Comment thread hooks/src/sandbox.rs
frits-v added 6 commits March 25, 2026 21:36
Update test count to 231 (178 unit + 4 doc + 17 integration + 10 proptest
+ 22 memory). Mention rusqlite as memory crate dependency. Fix trailing
period on H-4 purity bullet.
…ective 22)

Restructure all hook denial messages to follow the harness engineering
WHAT/FIX/REF format so the agent can self-repair without human
intervention:

- lib.rs: WORKTREE_MISSING now includes WHAT/FIX/REF
- sandbox.rs: REDIRECT and fallback BLOCKED messages use WHAT/FIX/REF
- gitcheck.rs: all 8 git safety blocks + worktree enforcement use
  WHAT/FIX/REF with pointers to CLAUDE.md and docs/architecture.md

Reference: harness.md Pillar 2c — custom linters with remediation messages.
Greptile correctly identified the count (231) didn't match the actual
cargo test output (246). Missing: claude_md (5), memory integration (4),
separate proptest binary (10).

Correct: 188 hooks unit + 5 claude_md + 17 integration + 10 proptest
+ 22 memory unit + 4 memory integration = 246.
@frits-v frits-v force-pushed the feat/remediation-messages branch 2 times, most recently from 4e09c2a to 5549c67 Compare March 26, 2026 04:52
@frits-v frits-v force-pushed the feat/remediation-messages branch from 5549c67 to 90a258d Compare March 26, 2026 04:54
@frits-v
Copy link
Copy Markdown
Owner Author

frits-v commented Mar 26, 2026

@greptile-apps

@frits-v frits-v merged commit 86578eb into main Mar 26, 2026
12 checks passed
@frits-v frits-v deleted the feat/remediation-messages branch March 26, 2026 05:33
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