Skip to content

feat: edit-time comment gate — scope/block-all, narration/density heuristics + PostToolUse hook#11

Open
robdmoore wants to merge 11 commits into
mainfrom
feat/edit-time-comment-gate
Open

feat: edit-time comment gate — scope/block-all, narration/density heuristics + PostToolUse hook#11
robdmoore wants to merge 11 commits into
mainfrom
feat/edit-time-comment-gate

Conversation

@robdmoore

@robdmoore robdmoore commented Jul 9, 2026

Copy link
Copy Markdown
Member

What & why

Morphs the ideas from jackawatts/claude-comment-gate into @makerx/verify's comment tooling, re-expressed in our AST-based, cross-agent TS architecture. The comments check gains real heuristics and an edit-time gate so an agent gets back-pressure the moment it writes a low-value comment — not just at verify/CI time.

The comments check — two axes + a strictness dial

  • Scope--scope diff (default: only comments on changed lines) or --scope all (whole codebase).
  • Strictness — heuristics (default), --block-all (every non-exempt comment fails), or, at its strictest, --block-all --no-context-override (a no-comments-at-all, JSDoc-only policy). --block-new-comments is the alias for --scope diff --block-all.
  • context: overridecontext:-prefixed comments are exempt by default; --no-context-override (config comments.contextOverride: false) disables that, judging them like any other comment. Useful for a stricter gate or to drive a context: cleanup. When disabled, all output goes context-free: the reports drop their "prefix with context:" lines and --pushback swaps to a strict variant that offers no escape.

Heuristics (JSDoc / context: / machine directives exempt): long blocks, narration (session narration + LLM punctuation tells), density (comment share of the lines in scope, with a net-trim guard).

Example invocations

# Default: gate the current diff — long blocks, narration, density (context:/JSDoc/machine directives exempt)
verifyx comments --pushback

# Audit the whole codebase, not just the diff
verifyx comments --scope all --pushback

# Block every comment introduced on changed lines (context:/JSDoc still allowed) — the old --block-new-comments
verifyx comments --block-all              # == --scope diff --block-all
verifyx comments --block-new-comments     # alias

# Zero-comment policy across the whole repo, JSDoc only (no context: escape)
verifyx comments --scope all --block-all --no-context-override

# Stricter heuristics on the diff: no context: escape, tighter density, narration only
verifyx comments --no-context-override --comment-density 0.2
verifyx comments --comment-density 0            # disable density; keep blocks + narration

# Drive a context: cleanup — surface every context: comment as if it were any other
verifyx comments --scope all --no-context-override

# Edit-time hook (reads the PostToolUse payload on stdin; wired up by init)
echo "$TOOL_JSON" | verifyx comments-hook

# Scaffolding presets
verifyx init                                    # interactive: scope + 3-way strictness prompts
verifyx init --yes --comment-scope all          # non-interactive, whole-repo scope
verifyx init --yes --comment-strict             # no-comments/JSDoc-only preset (block-all + no-context-override)

Edit-time PostToolUse hook (verifyx comments-hook)

Reads the Claude Code tool payload on stdin (Write/Edit/MultiEdit; no git), scans only the text the edit introduced, and on a violation writes the canonical pushback to stderr and exits 2 — surfaced to the agent in the same turn. Honours contextOverride (context-free feedback when disabled).

Scaffolding & remediation (verifyx init)

  • Registers the hook, and drops a prune-comments skill + a comments-only-when-non-obvious rule (keep/delete criteria + worked examples).
  • Prompts for the comment gate's scope and a 3-way strictness (heuristics / block-all / strict-no-comments), baking the flags into the scaffolded verify:comments script; also --comment-scope, --comment-block-all, --comment-strict.
  • Monorepo-safe: writes to the nearest existing .claude (cwd → nearest ancestor within 3 levels, never past the git root → cwd), with --claude-dir to override, and prints where it landed.

Config (verify.config.json#comments)

scope, blockAll, narration, density, minAddedLines, contextOverride, ignore.

Divergences from claude-comment-gate (deliberate)

  • Language coverage: TS/JS/YAML only (TS compiler API), vs his ~18 languages (bash prefix-matching).
  • Hook input: we parse the tool payload (exact edit, incl. MultiEdit, no git/jq); his re-derives via git diff HEAD of the file.

Testing

  • npm run verify green (all checks + tests + lint + format + types + knip + duplicate-code), including the gates running against this PR's own diff.
  • Unit tests cover scope diff/all, block-all, punctuation tells, density net-trim, the context: opt-out (check + hook), payload parsing, the .claude resolver, and the init flag/preset emission.

🤖 Generated with Claude Code

Comment thread .claude/skills/prune-comments/SKILL.md Outdated
Comment thread .claude/skills/prune-comments/SKILL.md Outdated
Comment thread src/scaffold/claudeSettings.ts
Comment thread src/hook/analyze.ts Outdated
Comment thread src/commands/registerCommentsHook.ts
@robdmoore robdmoore force-pushed the feat/edit-time-comment-gate branch from 0228c6e to 16ec6a7 Compare July 9, 2026 11:12
@robdmoore robdmoore changed the title feat: edit-time comment gate — narration/density heuristics + PostToolUse hook feat: edit-time comment gate — scope/block-all, narration/density heuristics + PostToolUse hook Jul 9, 2026
@makerxbot makerxbot requested a review from Copilot July 10, 2026 17:13

Copilot AI 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.

Pull request overview

This PR extends the built-in comments check from a single long-block heuristic into a two-axis gate (scope: diff|all, strictness: heuristics vs --block-all) and adds an edit-time Claude PostToolUse hook (verifyx comments-hook) that rejects low-value comments immediately after Write/Edit/MultiEdit operations.

Changes:

  • Expand verifyx comments to support diff/all scoping, narration detection, comment-density gating, and --block-all (with --block-new-comments as an alias).
  • Add a Claude PostToolUse hook pipeline (payload parsing + added-text analysis + CLI command) and scaffold/init support for writing hook/settings + new skills/rules.
  • Add templates + generated .claude/ artifacts and update documentation/tests to cover the new behavior.

Reviewed changes

Copilot reviewed 33 out of 33 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
templates/skills/prune-comments/SKILL.md Adds a remediation skill template for pruning low-value comments.
templates/rules/comments-only-when-non-obvious.md Adds a rule template defining when comments are justified vs noise.
src/shared/diff.ts Adds parsing of removed diff lines to support density net-trim logic.
src/shared/config.ts Extends verify config schema for comments scope/strictness/heuristics tuning.
src/shared/comment-scan.ts Refactors comment scanning to accept source text (enables hook scanning).
src/scaffold/init.ts Adds init flags and wiring for comment gate options and hook installation.
src/scaffold/init.test.ts Tests init script emission for comment gate options.
src/scaffold/claudeSettings.ts Implements idempotent merge into .claude/settings.json for PostToolUse hook.
src/scaffold/claudeSettings.test.ts Tests settings merge/idempotence/unparseable handling.
src/scaffold/claudeDir.ts Adds monorepo-safe resolution of the target .claude directory.
src/scaffold/claudeDir.test.ts Tests .claude resolution rules (ancestor search + git root cap + override).
src/scaffold/agentFiles.ts Scaffolds new prune-comments skill and comment rule into agent integrations.
src/report.ts Adds reporting for block-all, narration, and density violations; exports PUSHBACK.
src/hook/payload.ts Parses Claude PostToolUse payloads and extracts added text for scanning.
src/hook/payload.test.ts Tests payload parsing across tool variants and edge cases.
src/hook/analyze.ts Runs comment heuristics against added text and formats hook feedback.
src/hook/analyze.test.ts Tests hook analysis behavior (narration/blocks/density/exemptions/blockAll).
src/comments.ts Exposes findLongCommentBlocksInContent for reuse by diff/hook analyzers.
src/commands/registerInit.ts Adds init prompts/flags for comment scope/strictness and hook, plus reporting.
src/commands/registerCommentsHook.ts Adds hidden CLI command implementing the PostToolUse hook.
src/commands/registerChecks.ts Updates comments command flags/help and forwards new options into the check.
src/cli.ts Registers the new comments-hook command with the CLI.
src/checks/registry.ts Updates the registry description for the enhanced comments check.
src/checks/comments.ts Reworks the comments check around scope/strictness + narration/density heuristics.
src/checks/comments.test.ts Adds hermetic diff mocking and new test coverage for narration/density/block-all behavior.
src/checks/comment-heuristics.ts Introduces narration detection and density computation utilities.
src/checks/comment-heuristics.test.ts Adds unit tests for narration/density logic.
src/checks/comment-common.ts Centralizes comment exemption logic, scanned extensions, and comment-line helpers.
src/checks/comment-collect.ts Adds diff/all collection pipeline for candidates used by all comment gates.
README.md Documents new comments gate axes, flags, config, hook behavior, and remediation assets.
.claude/skills/prune-comments/SKILL.md Adds repo-local Claude skill for pruning low-value comments.
.claude/settings.json Adds repo-local Claude PostToolUse hook configuration.
.claude/rules/comments-only-when-non-obvious.md Adds repo-local Claude rule for when comments are justified.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/checks/comments.ts Outdated
Comment thread src/checks/comment-collect.ts
Comment thread src/commands/registerCommentsHook.ts
Comment thread src/commands/registerInit.ts Outdated
robdmoore and others added 9 commits July 11, 2026 14:59
Adds two diff-scoped heuristics to the comments check, on by default: session-narration detection ("let me", "as requested", restating what the next line does) and comment density (comments as a share of a changed file's added lines). Both judge only changed lines, exempting JSDoc, context:, and machine directives.

Also adds `verifyx comments-hook`, a Claude Code PostToolUse hook that scans the text an Edit/Write introduced (parsed from the tool payload, no git) and returns exit-2 back-pressure so the agent revises low-value comments in-loop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
verifyx init now merges the comments-hook PostToolUse entry into .claude/settings.json (idempotent, never clobbering existing keys; --no-comment-hook to skip) and drops a prune-comments remediation skill into .claude/skills and .agent-skills. Dogfoods both into this repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ate parity

Splits the comments check into two orthogonal axes: --scope diff (default, changed lines) vs all (whole codebase), and --block-all (fail every comment in scope) vs the default heuristics. --block-new-comments becomes an alias for --scope diff --block-all. Long-block detection is now diff-scoped by default like narration/density.

Adopts the missing claude-comment-gate signals: H2 LLM punctuation tells (em-dash/curly quotes), H3 net-increase guard (a comment trim is never flagged) and blank-line exclusion from the density denominator. The edit-time hook now reuses the canonical PUSHBACK from report.ts instead of a weaker paraphrase.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
verifyx init now writes .claude/.agent-skills to the nearest existing .claude (cwd, else the closest ancestor within 3 levels, never past the git root, else cwd), with a --claude-dir override, and reports where it landed. Claude Code loads project settings only from its launch dir, so this attaches to the likely launch root instead of clobbering a monorepo parent. Also scaffolds a comments-only-when-non-obvious rule (keep/delete criteria + examples) alongside the skills.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… behaviour

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…comments

verifyx init now asks (or takes --comment-scope diff|all and --comment-block-all) how the comments check should gate, and emits the flags into the scaffolded verify:comments script. Non-default choices are emitted even under defaults-only as a verify:comments override, since there's nowhere else to record them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t: guidance

Scopes the rule's path frontmatter to our extensions (ts/js/yml family); restores the content that was trimmed (the failure-mode preamble, the invented-shorthand and config/infra and duplicated-explanation entries) in TS/YAML; removes all context: guidance from the rule and the prune skill so agents meet the human-paging pushback at the gate rather than pre-learning the escape; no escape-hatch section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… hook path, init message

- --scope all now honours verify.config.json#comments.ignore, not just --ignore.
- Diff scope counts a comment as touched when any of its lines changed, not only its opening line (block comments edited in the body now reach narration/block-all).
- The hook normalises the payload path (absolute + Windows separators) and matches ignore globs against both absolute and cwd-relative forms.
- init's 'wrote to nearest .claude' note only prints when agent files were actually written.
- Split resolveSelections to keep registerInit.ts above the maintainability threshold after the rebase.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@robdmoore robdmoore force-pushed the feat/edit-time-comment-gate branch from c5728e9 to b87f13f Compare July 11, 2026 07:06
robdmoore and others added 2 commits July 11, 2026 15:37
…ct no-comments init preset

Adds comments.contextOverride (default true; CLI --no-context-override). When off, context: comments are judged like any other — a stricter stance and a way to drive a context: cleanup; JSDoc and machine directives stay exempt. All gate output goes context-free in that mode: the reports drop their 'prefix with context:' lines and --pushback swaps to a strict variant that offers no escape.

verifyx init gains a 3-way strictness choice (heuristics / block-all / strict) and --comment-strict: the strict preset bakes --block-all --no-context-override into verify:comments — a no-comments-at-all, JSDoc-only policy. Renames the internal allowContext to contextOverride throughout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

2 participants