Skip to content

feat(toolkit): verify-branch-state skill + /verify + warn-mode hook (DOJ-4872) — v1.31.0#44

Open
lapc506 wants to merge 6 commits into
mainfrom
andres/doj-4872-toolkit-verify-branch-state-skill-v1.31.0
Open

feat(toolkit): verify-branch-state skill + /verify + warn-mode hook (DOJ-4872) — v1.31.0#44
lapc506 wants to merge 6 commits into
mainfrom
andres/doj-4872-toolkit-verify-branch-state-skill-v1.31.0

Conversation

@lapc506
Copy link
Copy Markdown
Collaborator

@lapc506 lapc506 commented Jun 3, 2026

Summary

Plugin-layer (Level 1) extension of the working-tree-vs-ref discipline rule. This release operationalizes memory feedback_working_tree_is_not_truth at the toolkit layer so the rule travels with the plugin to every repo it's installed in.

Incident origin (2026-06-03). A re-audit subagent correctly flagged usePathwayViewModel.ts as deleted on develop during DOJ-4849 triage. The orchestrator "corrected" the subagent by running ls src/hooks/path/usePathwayViewModel.ts against a local main checkout that another session had switched to a different branch. The bare-FS read returned a stale projection; authoritative "FRESH — proceed as briefed" comments went to DOJ-4851/4863/4864 and had to be retracted publicly. Root cause: working tree was treated as truth instead of one projection.

Defense in depth. Earlier today, DOJ-4868 shipped the repo-layer (Level 2) enforcement via .claude/hooks/ + root CLAUDE.md in dojo-os (PR #2604). DOJ-4872 ships the plugin-layer (Level 1) here: skill + slash command + warn-mode PreToolUse hook. Without it, agents using make-no-mistakes-toolkit in any other repo have zero guidance about the rule.

Linear: DOJ-4872
Sibling: DOJ-4868 (dojo-os, Level 2)
Memory: feedback_working_tree_is_not_truth
Release: v1.30.0 → v1.31.0

What ships

4 new artifacts:

  1. skills/verify-branch-state/SKILL.md — auto-loading skill, tuned description triggers on "verify against develop", "does X exist on <branch>", "what's on origin/…", "did this land on main", "re-validate the subagent", "before I claim", "post-merge state". Body covers the rule statement, canonical ref-explicit commands (git fetch + git show / ls-tree / grep / diff against origin/<ref>), anti-patterns (ls, grep -rn src/, find, git status), pre-flight checklist, multi-worktree context, and the 2026-06-03 origin incident.

  2. commands/verify.md — slash command /verify <ref> <path-or-pattern>. Runs git fetch origin <ref> --quiet then git ls-tree origin/<ref> -- <path> for paths or git grep <pattern> origin/<ref> -- src/ for patterns. Emits a single verdict line citing the ref's short SHA in the shape origin/<ref> @ <sha7> — <path-or-pattern> <PRESENT|NOT PRESENT|N MATCHES> so the claim can be re-checked later. Handles ref-not-found, shell metacharacters in patterns, and squash-merge cache staleness (always re-fetches).

  3. hooks/pre-tool-use-claim-verification.sh — warn-mode PreToolUse hook, repo-agnostic, no per-repo manifest required. Detects bare-FS verification ops (ls, grep -rn src/, find src/, cat src/, head src/) and, when combined with intent keywords in the recent context envelope (or CLAUDE_HOOK_CONTEXT for smoke tests), prints a stderr warning with the local checkout's HEAD ref + short SHA, a suggested ref-explicit replacement specific to the detected op, and pointers to the skill + slash command. Always exit 0. Defensive set +e. Uses cd -P + pwd -P from day 1 (DOJ-4868 PR #2604 lesson). Trailing-newline-safe while read. Honors CLAUDE_DISABLE_PLUGIN_HOOKS=1. Shellcheck clean.

  4. CHANGELOG.md [1.31.0] - 2026-06-03 — Added / Changed / Why sections + reference link added at bottom.

4 edits:

  1. hooks/hooks.json — registers the new hook under the Bash PreToolUse matcher with a 3-second timeout, alongside the existing pre-bash.sh dispatcher.
  2. .claude-plugin/marketplace.json — top-level + plugin version 1.30.0 → 1.31.0; plugin description pair-mentions the new skill; component counts updated to 30 commands / 11 skills / 2 agents.
  3. .claude-plugin/plugin.jsonversion 1.30.0 → 1.31.0.
  4. package.jsonversion 1.30.0 → 1.31.0.
  5. README.md**Version:** header bumped; new "Also start here: verify-branch-state + /verify" peer subsection sits between the domain-driven-advisor "Start here" block and "What's Inside"; Commands table 29 → 30 (adds /verify); Skills table 10 → 11 (adds verify-branch-state).

Cohesive-PR exception (9 files)

9 files instead of the soft ≤8 target. The 4 new artifacts + 4 release-cut edits sum to 8; the 9th is hooks/hooks.json, which is required to make the new hook non-dead code. The whole set is a single cohesive surface (working-tree-vs-ref discipline) plus the standard release-cut shape mirroring v1.30.0's commit shape. Documented per CLAUDE.md rule 7 cohesive-PR exception.

Per-AC ship status

AC Requirement Status
AC1 Skill with frontmatter + tuned auto-trigger description shipped
AC2 Slash command /verify <ref> <path-or-pattern> cites ref SHA shipped
AC3 Hook: set +e, cd -P + pwd -P, exit 0 always, shellcheck clean shipped
AC4 Versions 1.31.0 agree across 4 manifests verified via jq
AC5 CHANGELOG entry under [1.31.0] - 2026-06-03 + reference link shipped
AC6 README "Start here" peer subsection shipped
AC7 Hook smoke tests pass see below
AC8 Skill cites memory feedback_working_tree_is_not_truth shipped
AC9 Cohesive PR ≤8 files 9 files; exception documented
AC10 Tag release v1.31.0 post-merge, manual

Smoke test outputs (AC7)

$ bash hooks/pre-tool-use-claim-verification.sh "ls src/foo.tsx"

[verify-branch-state] WARN: working-tree read used for a branch-level claim.

  Local HEAD: andres/doj-4872-toolkit-verify-branch-state-skill-v1.31.0 @ c513198
  Command:    ls src/foo.tsx

  This reads the working-tree projection, not the ref. The local checkout
  may have drifted (other sessions, worktrees, hooks). The ref is the truth.

  Suggested ref-explicit replacement:
    git fetch origin <branch> --quiet && git ls-tree origin/<branch> -- src/foo.tsx

  Or use the slash command (cites the ref's SHA for you):
    /make-no-mistakes:verify <branch> <path-or-pattern>

  See: skills/verify-branch-state/SKILL.md
  Memory: feedback_working_tree_is_not_truth (origin 2026-06-03)

  (warn-mode only — your command will still run)

$ bash hooks/pre-tool-use-claim-verification.sh "echo hello"
(silent — exit 0)

$ bash hooks/pre-tool-use-claim-verification.sh 'grep -rn "Symbol" src/'
[verify-branch-state] WARN: working-tree read used for a branch-level claim.
  Command:    grep -rn "Symbol" src/
  Suggested: git fetch origin <branch> --quiet && git grep "Symbol" origin/<branch> -- src/
  ...

$ bash hooks/pre-tool-use-claim-verification.sh 'find src/ -name "*.tsx"'
[verify-branch-state] WARN: ...
  Suggested: git fetch origin <branch> --quiet && git ls-tree -r origin/<branch> -- <path> | grep <pattern>

$ echo '{"tool_name":"Bash","tool_input":{"command":"ls src/foo.tsx"}}' | bash hooks/pre-tool-use-claim-verification.sh
(silent — no intent keyword in context envelope; bare ls alone does not trigger)

$ CLAUDE_HOOK_CONTEXT="does X exist on develop" bash -c 'echo "{...}" | bash hooks/pre-tool-use-claim-verification.sh'
[verify-branch-state] WARN: ... (intent ctx present → triggers)

$ shellcheck hooks/pre-tool-use-claim-verification.sh
(0 issues)

$ jq -r '.version' .claude-plugin/marketplace.json       # 1.31.0
$ jq -r '.plugins[0].version' .claude-plugin/marketplace.json   # 1.31.0
$ jq -r '.version' .claude-plugin/plugin.json            # 1.31.0
$ jq -r '.version' package.json                          # 1.31.0
$ grep '^\*\*Version:' README.md                         # **Version: 1.31.0**

Post-merge actions (deferred to maintainer)

These are explicitly out of this PR's scope and will be performed after merge by @lapc506:

  • Tag the release: git tag -a v1.31.0 -m "v1.31.0" + git push origin v1.31.0 (AC10)
  • Flip Linear DOJ-4872 → Done
  • Post a thread reply to the v1.30.0 announcement in #doj-repo-health (Slack thread)

Test plan

  • All four version manifests agree at 1.31.0 (jq -r '.version' … × 4)
  • Hook smoke tests: warn on ls, silent on echo, warn on grep -rn, warn on find
  • Hook stdin-mode: silent without intent ctx, warn with intent ctx
  • shellcheck hooks/pre-tool-use-claim-verification.sh → 0 issues
  • Hook honors CLAUDE_DISABLE_PLUGIN_HOOKS=1 (early exit 0)
  • cd -P + pwd -P used for hook self-location (day 1, per DOJ-4868 PR #2604)
  • Skill description field tuned for auto-trigger on the canonical intent phrases
  • Slash command emits verdict line in citation-ready format
  • CHANGELOG reference link added at bottom ([1.31.0]: …/releases/tag/v1.31.0)
  • Marketplace plugin description pair-mentions the new skill
  • README "Start here" peer subsection drafted to match the domain-driven-advisor style

Created by Claude Code on behalf of @lapc506.

…e hook (DOJ-4872) — v1.31.0

Ships the plugin-layer (Level 1) extension of the working-tree-vs-ref
discipline rule. DOJ-4868 shipped the repo-layer (Level 2) enforcement in
dojo-os; this release makes the same rule travel with the toolkit to every
repo it is installed in.

New artifacts:

- skills/verify-branch-state/SKILL.md — auto-loading skill, tuned description
  triggers on "verify against develop", "does X exist on <branch>", "what's
  on origin/...", "did this land on main", "re-validate the subagent". Body
  covers the rule, canonical ref-explicit commands (git fetch + git show /
  ls-tree / grep / diff against origin/<ref>), anti-patterns (ls, grep -rn
  src/, find, git status), pre-flight checklist, multi-worktree context, and
  the 2026-06-03 DOJ-4851/4863/4864 origin incident. Cites memory
  feedback_working_tree_is_not_truth.

- commands/verify.md — slash command /verify <ref> <path-or-pattern>. Runs
  git fetch origin <ref> --quiet then git ls-tree origin/<ref> -- <path>
  for paths or git grep <pattern> origin/<ref> -- src/ for patterns. Emits
  a single verdict line citing the ref's short SHA in the shape
  "origin/<ref> @ <sha7> — <path-or-pattern> <PRESENT|NOT PRESENT|N MATCHES>"
  so the claim can be re-checked. Handles ref-not-found, shell
  metacharacters in patterns, and squash-merge cache staleness (always
  re-fetches).

- hooks/pre-tool-use-claim-verification.sh — warn-mode PreToolUse hook,
  repo-agnostic, no per-repo manifest. Detects bare-FS verification ops
  combined with intent keywords; prints stderr warning with local HEAD ref
  + SHA, a suggested ref-explicit replacement, and pointers to the skill +
  slash command. Always exit 0. Defensive set +e. Uses cd -P + pwd -P from
  day 1 (DOJ-4868 PR #2604 lesson). Trailing-newline-safe while read.
  Honors CLAUDE_DISABLE_PLUGIN_HOOKS=1. Shellcheck clean. Wired into
  hooks/hooks.json under the Bash PreToolUse matcher with a 3s timeout.

Version bump 1.30.0 -> 1.31.0 across .claude-plugin/marketplace.json
(top-level + plugin version) + .claude-plugin/plugin.json + package.json +
README.md Version header. CHANGELOG entry under [1.31.0] - 2026-06-03 with
Added / Changed / Why sections + reference link at bottom. README "Start
here" grows a peer entry point ("Also start here: verify-branch-state +
/verify") between the domain-driven-advisor section and "What's Inside".
Commands table 29 -> 30 (adds /verify); Skills table 10 -> 11 (adds
verify-branch-state). Marketplace plugin description pair-mentions the new
skill.

Smoke tests pass:
- bash hooks/pre-tool-use-claim-verification.sh "ls src/foo.tsx" -> warn
- bash hooks/pre-tool-use-claim-verification.sh "echo hello" -> silent
- shellcheck hooks/pre-tool-use-claim-verification.sh -> 0 issues
- jq -r .version on all four manifests -> 1.31.0 (agree)

AC9 note (cohesive-PR exception): 9 files instead of the soft ≤8 target
because the hooks.json registration is required to make the new hook
non-dead. The new skill + command + hook are a single cohesive surface
(working-tree-vs-ref discipline) and the version+CHANGELOG+README updates
are the standard release-cut shape, mirroring the v1.30.0 commit shape.

Related: DOJ-4868 (dojo-os Level-2 sibling), v1.30.0 release (today),
memory feedback_working_tree_is_not_truth.

Created by Claude Code on behalf of @lapc506.
@lapc506
Copy link
Copy Markdown
Collaborator Author

lapc506 commented Jun 3, 2026

@dojo-code-reviewer review

Copy link
Copy Markdown

@dojo-code-reviewer dojo-code-reviewer Bot left a comment

Choose a reason for hiding this comment

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

✅ Approved

Approved — 0 blockers, 2 P2, 2 P3. Confidence: 3/5.

🟡 P2 — Major

  • commands/verify.md:42 — 🟡 P2 (major) — The slash command currently assumes the user always passes a branch name that needs to be prefixed with 'origin/'. However, if a user passes a remote-tracking branch like 'origin/develop', a tag like 'v1.31.0', or a commit SHA, this leads to failures like 'origin/origin/develop' or 'origin/v1.31.0' during fetch, rev-parse, and ls-tree/grep. Additionally, the hardcoded '-C "$REPO"' directory switches can fail if the environment hasn't defined the '$REPO' variable. Normalize the reference explicitly first to handle all formats seamlessly, and execute directly within the current workspace.

  • hooks/pre-tool-use-claim-verification.sh:116 — 🟡 P2 (major) — The regex matches bare-filesystem operations followed by a space, which means it will fail to detect verification commands that appear at the end of a line or command string without a trailing space (for example, 'ls' alone or the end of a chain like 'cd src && ls'). Use '([[:space:]]|$)' to ensure the hook reliably triggers in these scenarios.

  if printf '%s' "$cmd" | grep -qE '(^|[;&|][[:space:]]*)(ls|find|cat|head)([[:space:]]|$)'; then

🔵 P3 — Minor

  • hooks/pre-tool-use-claim-verification.sh:162 — 🔵 P3 (minor) — To ensure that the suggested replacement helper is chosen correctly when 'ls' is used at the end of a command string without trailing space, replace 'ls[[:space:]]' with 'ls([[:space:]]|$)'.
if printf '%s' "$COMMAND" | grep -qE '(^|[;&|][[:space:]]*)ls([[:space:]]|$)'; then
  • hooks/pre-tool-use-claim-verification.sh:181 — 🔵 P3 (minor) — To ensure that the suggested replacement helper is chosen correctly when 'find' is used at the end of a command string without trailing space, replace 'find[[:space:]]' with 'find([[:space:]]|$)'.
elif printf '%s' "$COMMAND" | grep -qE '(^|[;&|][[:space:]]*)find([[:space:]]|$)'; then

Total findings: 2 compliance, 2 business context (4 total)


ℹ️ Inline anchoring failed for the comments below; they are listed here instead.

  • commands/verify.md:42 — 🟡 P2 (major) — The slash command currently assumes the user always passes a branch name that needs to be prefixed with 'origin/'. However, if a user passes a remote-tracking branch like 'origin/develop', a tag like 'v1.31.0', or a commit SHA, this leads to failures like 'origin/origin/develop' or 'origin/v1.31.0' during fetch, rev-parse, and ls-tree/grep. Additionally, the hardcoded '-C "$REPO"' directory switches can fail if the environment hasn't defined the '$REPO' variable. Normalize the reference explicitly first to handle all formats seamlessly, and execute directly within the current workspace.
  • hooks/pre-tool-use-claim-verification.sh:116 — 🟡 P2 (major) — The regex matches bare-filesystem operations followed by a space, which means it will fail to detect verification commands that appear at the end of a line or command string without a trailing space (for example, 'ls' alone or the end of a chain like 'cd src && ls'). Use '([[:space:]]|$)' to ensure the hook reliably triggers in these scenarios.
  if printf '%s' "$cmd" | grep -qE '(^|[;&|][[:space:]]*)(ls|find|cat|head)([[:space:]]|$)'; then
  • hooks/pre-tool-use-claim-verification.sh:162 — 🔵 P3 (minor) — To ensure that the suggested replacement helper is chosen correctly when 'ls' is used at the end of a command string without trailing space, replace 'ls[[:space:]]' with 'ls([[:space:]]|$)'.
if printf '%s' "$COMMAND" | grep -qE '(^|[;&|][[:space:]]*)ls([[:space:]]|$)'; then
  • hooks/pre-tool-use-claim-verification.sh:181 — 🔵 P3 (minor) — To ensure that the suggested replacement helper is chosen correctly when 'find' is used at the end of a command string without trailing space, replace 'find[[:space:]]' with 'find([[:space:]]|$)'.
elif printf '%s' "$COMMAND" | grep -qE '(^|[;&|][[:space:]]*)find([[:space:]]|$)'; then

Bot review at 3/5 confidence flagged 2 P2 + 2 P3. All four addressed:

P2 — commands/verify.md ref normalization
  - The behavior section assumed every <ref> arg was a bare branch name
    and unconditionally prefixed `origin/`, breaking `origin/develop`
    (→ `origin/origin/develop`), tags (`v1.31.0` → `origin/v1.31.0`),
    and SHAs. Added a normalization step at the top of the pipeline:
      * `refs/tags/<tag>` for tag inputs (fetched via `git fetch origin
        tag <tag> --quiet`)
      * bare SHA for already-local commits (skips fetch entirely;
        commits are immutable)
      * `origin/<branch>` left as-is when user passes `origin/...`
      * `origin/<branch>` only synthesized for bare branch input
  - Dropped the `-C "$REPO"` indirection — the slash command's cwd is
    the repo root, no need for the hardcoded variable that would fail
    when unset.
  - Updated the verdict-line shape to `<resolved-ref> @ <sha7>` so the
    citation reflects whatever normalization produced (tag refs, SHAs,
    branch refs all render correctly). Added tag + SHA examples.
  - Expanded the Edge cases section: `origin/<branch>` input, tag input,
    commit SHA input, ref not found.

P2 — hooks/pre-tool-use-claim-verification.sh line 116
  - The bare-FS detector regex `(ls|find|cat|head)[[:space:]]` failed
    to match the command-as-last-token cases like a bare `ls` invocation
    or `cd src && ls` (no trailing whitespace). Switched the trailing
    class to `([[:space:]]|$)` so end-of-string also matches.

P3 — hooks/pre-tool-use-claim-verification.sh line 162
  - Same fix in the suggester branch for `ls`: `ls[[:space:]]` →
    `ls([[:space:]]|$)` so the ls-specific replacement text is emitted
    even when the command ends in `ls`.

P3 — hooks/pre-tool-use-claim-verification.sh line 181
  - Same fix in the suggester branch for `find`: `find[[:space:]]` →
    `find([[:space:]]|$)`.

Verification:
  - shellcheck hooks/pre-tool-use-claim-verification.sh → 0 issues
  - bash hooks/pre-tool-use-claim-verification.sh "ls"           → warn (new)
  - bash hooks/pre-tool-use-claim-verification.sh "cd src && ls" → warn (new)
  - bash hooks/pre-tool-use-claim-verification.sh "ls src/foo"   → warn (regression)
  - bash hooks/pre-tool-use-claim-verification.sh "echo hello"   → silent (regression)
  - bash hooks/pre-tool-use-claim-verification.sh "find"         → warn (new)

Created by Claude Code on behalf of @lapc506.
@lapc506
Copy link
Copy Markdown
Collaborator Author

lapc506 commented Jun 3, 2026

@dojo-code-reviewer review

Addressed all 4 findings from prior review (3/5 confidence):

  • P2 commands/verify.md:42 — Added ref normalization step at the top of the Behavior pipeline. origin/<branch>, tags (refs/tags/<tag>), and commit SHAs are now resolved explicitly; bare branch names are the only case that synthesizes origin/<branch>. Dropped -C "$REPO" indirection — slash command's cwd is the repo. Verdict line shape updated to <resolved-ref> @ <sha7> with tag + SHA examples.
  • P2 hooks/pre-tool-use-claim-verification.sh:116 — Detector regex trailing class [[:space:]]([[:space:]]|$). Bare ls, cd src && ls, find (no trailing space) now trigger correctly.
  • P3 hooks/pre-tool-use-claim-verification.sh:162 — Same fix in the suggester's ls branch.
  • P3 hooks/pre-tool-use-claim-verification.sh:181 — Same fix in the suggester's find branch.

Smoke tests + shellcheck still green. Fix commit: 31f10c9.

Copy link
Copy Markdown

@dojo-code-reviewer dojo-code-reviewer Bot left a comment

Choose a reason for hiding this comment

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

✅ Approved

Approved — 0 blockers, 2 P3. Confidence: 4/5.

🔵 P3 — Minor

  • hooks/pre-tool-use-claim-verification.sh:145 — 🔵 P3 (minor) — Simplify and make the path argument extraction for ls commands more robust. The current sed regular expression assumes the flags always have a trailing space, which fails to strip flags if they are at the end of the command (e.g., ls -la), resulting in path_arg being extracted as -la. Using awk to loop through the tokens and extract the first non-option token after ls is cleaner, shorter, and correctly handles trailing options or extra whitespace.
  path_arg="$(printf '%s' "$COMMAND" \
    | awk '{for(i=1;i<=NF;i++) if ($i == "ls") {for(j=i+1;j<=NF;j++) if ($j !~ /^-/) {print $j; exit}}}')"
  • hooks/pre-tool-use-claim-verification.sh:158 — 🔵 P3 (minor) — Fix the grep pattern extraction when multiple option flags are specified separately. In the current implementation, if a user runs grep -i -r "Symbol" src/, the awk block matches -i and immediately extracts the next token $(i+1) (which is -r) as the pattern. By utilizing a nested loop in awk that skips any subsequent option tokens starting with -, you can correctly isolate the actual search pattern.
    pattern_arg="$(printf '%s' "$COMMAND" \
      | awk '{for(i=1;i<=NF;i++) if ($i ~ /^-[rRnliN]+$/) {for(j=i+1;j<=NF;j++) if ($j !~ /^-/) {print $j; exit}}}' \
      | tr -d '\"')"

Total findings: 2 business context (2 total)


ℹ️ Inline anchoring failed for the comments below; they are listed here instead.

  • hooks/pre-tool-use-claim-verification.sh:145 — 🔵 P3 (minor) — Simplify and make the path argument extraction for ls commands more robust. The current sed regular expression assumes the flags always have a trailing space, which fails to strip flags if they are at the end of the command (e.g., ls -la), resulting in path_arg being extracted as -la. Using awk to loop through the tokens and extract the first non-option token after ls is cleaner, shorter, and correctly handles trailing options or extra whitespace.
  path_arg="$(printf '%s' "$COMMAND" \
    | awk '{for(i=1;i<=NF;i++) if ($i == "ls") {for(j=i+1;j<=NF;j++) if ($j !~ /^-/) {print $j; exit}}}')"
  • hooks/pre-tool-use-claim-verification.sh:158 — 🔵 P3 (minor) — Fix the grep pattern extraction when multiple option flags are specified separately. In the current implementation, if a user runs grep -i -r "Symbol" src/, the awk block matches -i and immediately extracts the next token $(i+1) (which is -r) as the pattern. By utilizing a nested loop in awk that skips any subsequent option tokens starting with -, you can correctly isolate the actual search pattern.
    pattern_arg="$(printf '%s' "$COMMAND" \
      | awk '{for(i=1;i<=NF;i++) if ($i ~ /^-[rRnliN]+$/) {for(j=i+1;j<=NF;j++) if ($j !~ /^-/) {print $j; exit}}}' \
      | tr -d '\"')"

…n hook (DOJ-4872)

Round-2 bot review at 4/5 confidence flagged 2 P3 polish items on the
suggester's argument extraction. Both addressed; suggestions applied
verbatim with explanatory comments.

P3 — hooks/pre-tool-use-claim-verification.sh:145 (ls path extraction)
  - Old: sed prefix-strip + awk first-token, which fails on commands
    like `ls -la` (no path arg, trailing flags) — sed regex `-flags`
    requires a trailing space, so the flags leak through and `-la` ends
    up as the "path arg" in the suggested replacement.
  - New: awk-only nested loop that locates the literal `ls` token,
    then walks forward skipping any token starting with `-`, and
    emits the first non-flag token. Empty when only flags are present
    (correct), so the suggester falls through to the `<path>` placeholder.

P3 — hooks/pre-tool-use-claim-verification.sh:158 (grep pattern extraction)
  - Old: awk fallback matched the first `-FLAGS` token and emitted the
    immediately following token, which on `grep -i -r "Symbol" src/`
    is `-r` — wrong.
  - New: nested awk loop that, after finding the flag token, walks
    forward skipping additional flag tokens before emitting the first
    non-flag one. Correctly isolates `Symbol` for `grep -i -r "Symbol"`,
    still correct for the single-flag-block form `grep -rn "Symbol"`.

Verification:
  - shellcheck → 0 issues
  - "ls -la"                 → suggester emits <path> placeholder (was: `-la`)
  - "ls src/foo.tsx"         → suggester emits `src/foo.tsx` (regression)
  - "grep -i -r \"Symbol\" src/" → emits "Symbol" (was: `-r`)
  - "grep -rn \"Symbol\" src/"   → emits "Symbol" (regression)
  - "echo hello"             → silent (regression)

Created by Claude Code on behalf of @lapc506.
@lapc506
Copy link
Copy Markdown
Collaborator Author

lapc506 commented Jun 3, 2026

@dojo-code-reviewer review

Round-2 feedback (4/5) addressed — both P3 items applied verbatim with explanatory comments. Fix commit: $(git rev-parse --short HEAD).

  • P3 ls path extraction: awk-only nested loop replaces sed prefix-strip, fixes ls -la leaking -la as the path arg.
  • P3 grep pattern extraction: nested awk loop skips additional flag tokens, fixes grep -i -r "Symbol" src/ mis-extracting -r as the pattern.

Smoke tests + shellcheck green.

Copy link
Copy Markdown

@dojo-code-reviewer dojo-code-reviewer Bot left a comment

Choose a reason for hiding this comment

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

✅ Approved

Approved — 0 blockers, 1 P3. Confidence: 4/5.

🔵 P3 — Minor

  • hooks/pre-tool-use-claim-verification.sh:185 — 🔵 P3 (minor) — Strip single quotes as well as double quotes in the fallback pattern extractor to handle single-quoted search patterns (e.g. grep -rn 'Symbol').
      | tr -d "\"'")"

Total findings: 1 business context (1 total)


ℹ️ Inline anchoring failed for the comments below; they are listed here instead.

  • hooks/pre-tool-use-claim-verification.sh:185 — 🔵 P3 (minor) — Strip single quotes as well as double quotes in the fallback pattern extractor to handle single-quoted search patterns (e.g. grep -rn 'Symbol').
      | tr -d "\"'")"

…n hook (DOJ-4872)

Round-3 bot review at 4/5 confidence flagged 1 P3: the pattern extractor
only handled double-quoted forms, so `grep -rn 'Symbol' src/` would fall
through to the awk fallback and (until the awk fallback also stripped
single quotes) emit `'Symbol'` with the quotes attached.

Applied:

- Added a second extractor branch that mirrors the double-quote form but
  for single-quoted patterns. Tries double-quote first (cheapest grep),
  then single-quote, then the multi-flag awk fallback.
- Extended `tr -d` in the awk fallback to strip both `"` and `'`, so the
  unquoted-token output is clean regardless of which quote style the
  original command used.

Verification:
  - shellcheck → 0 issues
  - "grep -rn 'Symbol' src/"      → "Symbol"  (was: 'Symbol')
  - "grep -rn \"Symbol\" src/"      → "Symbol"  (regression)
  - "grep -i -r 'Symbol' src/"    → "Symbol"  (new, multi-flag + single quote)
  - "grep -i -r \"Symbol\" src/"    → "Symbol"  (regression)
  - "ls src/foo.tsx"              → src/foo.tsx (regression)
  - "echo hello"                  → silent     (regression)

Created by Claude Code on behalf of @lapc506.
@lapc506
Copy link
Copy Markdown
Collaborator Author

lapc506 commented Jun 3, 2026

@dojo-code-reviewer review

Round-3 feedback (4/5, 1 P3) addressed:

  • P3 single-quoted grep patterns: added a single-quote extractor branch parallel to the existing double-quote branch, and extended the awk-fallback tr -d to strip both " and '. grep -rn 'Symbol' src/, grep -i -r 'Symbol' src/, and the double-quoted equivalents all extract Symbol cleanly now.

Smoke tests + shellcheck green. Fix commit: $(git rev-parse --short HEAD).

Copy link
Copy Markdown

@dojo-code-reviewer dojo-code-reviewer Bot left a comment

Choose a reason for hiding this comment

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

✅ Approved

Approved — 0 blockers, 1 P2, 3 P3. Confidence: 3/5.

🟡 P2 — Major

  • hooks/pre-tool-use-claim-verification.sh:81 — 🟡 P2 (major) — The fallback regex "[^\"]*" stops at the first backslash (which JSON uses to escape internal double quotes), resulting in truncated command extraction when the executed bash command contains quotes (e.g. grep -rn \"Symbol\" src/). This causes subsequent command matching and warning suggestions to fail.

Using an escape-aware JSON string regex resolves this.

    | grep -oE '"command"[[:space:]]*:[[:space:]]*"([^"\\]|\\.)*"' \

🔵 P3 — Minor

  • hooks/pre-tool-use-claim-verification.sh:164 — 🔵 P3 (minor) — Redundant backslashes inside a single-quoted string are treated as literal backslashes by some shells and grep implementations, which can cause pattern extraction to fail or behave inconsistently depending on the platform's grep engine (e.g. macOS BSD grep vs GNU grep). Removing the backslashes before the double quotes inside single quotes improves cross-platform reliability.

Please also apply the same cleanup to the double quote backslashes on line 166.

    | grep -oE 'grep[[:space:]]+-[rRnliN]+[[:space:]]+"[^"]+"' \
  • commands/verify.md:112 — 🔵 P3 (minor) — Hardcoding -- src/ restricts pattern verification to the src/ directory. If the toolkit is installed in a repository that uses a different directory structure (e.g., lib/, app/, packages/, or root-level files), git grep will fail with a fatal pathspec error. Removing the -- src/ suffix or falling back to the repo root if src/ is absent makes the command truly generic and repo-agnostic.

  • commands/verify.md:45 — 🔵 P3 (minor) — Remote-only tags will fail to resolve. If a tag (e.g., v1.31.0) exists on the remote but has not been fetched locally yet, git rev-parse will fail, pushing the ref to the else block which resolves it to the nonexistent branch origin/v1.31.0. Pre-fetching tags or querying git ls-remote first would prevent this failure mode.


Total findings: 1 compliance, 3 business context (4 total)


ℹ️ Inline anchoring failed for the comments below; they are listed here instead.

  • hooks/pre-tool-use-claim-verification.sh:81 — 🟡 P2 (major) — The fallback regex "[^\"]*" stops at the first backslash (which JSON uses to escape internal double quotes), resulting in truncated command extraction when the executed bash command contains quotes (e.g. grep -rn \"Symbol\" src/). This causes subsequent command matching and warning suggestions to fail.

Using an escape-aware JSON string regex resolves this.

    | grep -oE '"command"[[:space:]]*:[[:space:]]*"([^"\\]|\\.)*"' \
  • hooks/pre-tool-use-claim-verification.sh:164 — 🔵 P3 (minor) — Redundant backslashes inside a single-quoted string are treated as literal backslashes by some shells and grep implementations, which can cause pattern extraction to fail or behave inconsistently depending on the platform's grep engine (e.g. macOS BSD grep vs GNU grep). Removing the backslashes before the double quotes inside single quotes improves cross-platform reliability.

Please also apply the same cleanup to the double quote backslashes on line 166.

    | grep -oE 'grep[[:space:]]+-[rRnliN]+[[:space:]]+"[^"]+"' \
  • commands/verify.md:112 — 🔵 P3 (minor) — Hardcoding -- src/ restricts pattern verification to the src/ directory. If the toolkit is installed in a repository that uses a different directory structure (e.g., lib/, app/, packages/, or root-level files), git grep will fail with a fatal pathspec error. Removing the -- src/ suffix or falling back to the repo root if src/ is absent makes the command truly generic and repo-agnostic.
  • commands/verify.md:45 — 🔵 P3 (minor) — Remote-only tags will fail to resolve. If a tag (e.g., v1.31.0) exists on the remote but has not been fetched locally yet, git rev-parse will fail, pushing the ref to the else block which resolves it to the nonexistent branch origin/v1.31.0. Pre-fetching tags or querying git ls-remote first would prevent this failure mode.

…y (DOJ-4872)

Round-4 bot review at 3/5 confidence flagged 1 P2 + 3 P3. All four addressed.

P2 — hooks/pre-tool-use-claim-verification.sh JSON command extractor
  - The jq-less fallback regex `"[^"]*"` stops at the first inner quote.
    For a bash command like `grep -rn \"Symbol\" src/`, the JSON envelope
    embeds it as `"command": "grep -rn \\\"Symbol\\\" src/"`, and the
    naive regex truncates at the first `\"`. Subsequent detector / suggester
    logic then sees a partial command and emits the wrong replacement.
  - Switched to the escape-aware JSON-string body
    `([^"\\]|\\.)*` which accepts any non-quote-non-backslash byte OR a
    backslash followed by any byte. Verified with an envelope containing
    `grep -rn \"Symbol\" src/` — the full command extracts cleanly and
    the suggester emits the right line.

P3 — hooks/pre-tool-use-claim-verification.sh cross-platform quote handling
  - The bot flagged that the explicit single-quoted-pattern grep extractor
    (added in round 3) used embedded-quote shell escaping that can drift
    between GNU and BSD grep. Simplified by removing the explicit single-
    quoted branch entirely: the awk fallback already strips both `"` and
    `'` from the extracted token, so it covers both quote styles without
    embedded escapes. Net code reduction; same behavior across the four
    smoke-tested variants (single/double quoted, single/multi flag).

P3 — commands/verify.md repo-agnostic grep path
  - The behavior section hardcoded `-- src/` as the path filter, which
    would fail with a `fatal: pathspec` error in toolkit consumers that
    have a different layout (`lib/`, `app/`, `packages/`, flat). Added a
    detect-or-fallback step: if `src/` exists on the resolved ref, use
    it as the path filter; otherwise pass no path filter and grep the
    whole tree.

P3 — commands/verify.md remote-only tag resolution
  - The normalization step probed `git rev-parse --verify refs/tags/<tag>`
    which only sees LOCAL tags. A remote-only tag (e.g. `v1.31.0` just
    pushed by a teammate but not yet fetched locally) would fall through
    to the bare-branch branch and resolve to a nonexistent
    `origin/v1.31.0`. Added a `git ls-remote --tags --exit-code origin
    refs/tags/<tag>` probe between the local-tag and SHA branches; on hit,
    runs `git fetch origin tag <tag> --quiet` before resolving. Comment
    documents the failure mode.

Verification:
  - shellcheck → 0 issues
  - JSON envelope with escaped quotes:
      `{"tool_input":{"command":"grep -rn \\\"Symbol\\\" src/"}}` →
      Command: `grep -rn "Symbol" src/`  (was: `grep -rn `)
      Suggested: `git grep "Symbol" origin/<branch> -- src/` (was: garbled)
  - "grep -rn 'Symbol' src/"       → Suggested: "Symbol"  (regression)
  - "grep -rn \"Symbol\" src/"       → Suggested: "Symbol"  (regression)
  - "grep -i -r \"Symbol\" src/"     → Suggested: "Symbol"  (regression)
  - "ls src/foo.tsx"               → Suggested: src/foo.tsx (regression)
  - "echo hello"                   → silent             (regression)

Created by Claude Code on behalf of @lapc506.
@lapc506
Copy link
Copy Markdown
Collaborator Author

lapc506 commented Jun 3, 2026

@dojo-code-reviewer review

Round-4 feedback (3/5, 1 P2 + 3 P3) addressed:

  • P2 hook JSON command-extractor: switched the jq-less fallback regex from "[^"]*" to the escape-aware "([^"\\\\]|\\\\.)*" so envelopes containing grep -rn \"Symbol\" src/ extract the full command instead of truncating at the first inner quote. Verified end-to-end.
  • P3 cross-platform grep quote-handling: removed the explicit single-quoted-pattern extractor branch (which used embedded-quote shell escaping fragile across GNU/BSD grep); the awk fallback already strips both " and ' so it covers both styles cleanly. Net code reduction.
  • P3 commands/verify.md repo-agnostic grep: dropped hardcoded -- src/. Detect src/ on the resolved ref; if absent, pass no path filter so the command works in repos with lib/, app/, packages/, or flat layouts.
  • P3 commands/verify.md remote-only tag: added a git ls-remote --tags --exit-code probe between the local-tag and SHA branches; on hit, fetches the tag before resolving so remote-only tags don't fall through to a nonexistent origin/<tag>.

Smoke tests + shellcheck green. Fix commit: $(git rev-parse --short HEAD).

Copy link
Copy Markdown

@dojo-code-reviewer dojo-code-reviewer Bot left a comment

Choose a reason for hiding this comment

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

✅ Approved

Approved — 0 blockers, 4 P2. Confidence: 2/5.

🟡 P2 — Major

  • commands/verify.md:44 — 🟡 P2 (major) — The ARG variable is used in later steps (e.g., "$ARG") but is never defined or assigned. This will cause $ARG to resolve to an empty string, breaking file path and pattern verification when Claude follows these instructions. Assigning ARG="$2" next to RAW_REF ensures proper parameter mapping.
   RAW_REF="$1"
   ARG="$2"
  • commands/verify.md:54 — 🟡 P2 (major) — Running git fetch origin "tag $RAW_REF" (with quotes grouping the tag keyword and the tag name together) passes them as a single argument to Git. This will cause the fetch operation to fail with a "does not appear to be a git repository" error. Separating them as distinct arguments ensures the remote-only tag is fetched successfully.
     git fetch origin tag "$RAW_REF" --quiet
  • hooks/pre-tool-use-claim-verification.sh:99 — 🟡 P2 (major) — The unanchored pattern grep[[:space:]]+-[rRnliN]+ matches any occurrence of grep followed by flags, which includes legitimate Git commands like git grep -n. This causes the hook to generate false-positive warnings even when users are running the exact ref-explicit git grep commands recommended by this very skill. Anchoring grep to the start of the command or a separator prevents these false positives.
  if printf '%s' "$cmd" | grep -qE '(^|[;&|][[:space:]]*)grep[[:space:]]+-[rRnliN]+'; then
  • hooks/pre-tool-use-claim-verification.sh:145 — 🟡 P2 (major) — The unanchored pattern grep[[:space:]]+-[rRnliN]+ matches git grep here as well, causing false positives in the suggestion logic. Anchoring grep to the start of the command or a separator keeps the matching logic consistent with the detector.
elif printf '%s' "$COMMAND" | grep -qE '(^|[;&|][[:space:]]*)grep[[:space:]]+-[rRnliN]+'; then

Total findings: 4 compliance (4 total)


ℹ️ Inline anchoring failed for the comments below; they are listed here instead.

  • commands/verify.md:44 — 🟡 P2 (major) — The ARG variable is used in later steps (e.g., "$ARG") but is never defined or assigned. This will cause $ARG to resolve to an empty string, breaking file path and pattern verification when Claude follows these instructions. Assigning ARG="$2" next to RAW_REF ensures proper parameter mapping.
   RAW_REF="$1"
   ARG="$2"
  • commands/verify.md:54 — 🟡 P2 (major) — Running git fetch origin "tag $RAW_REF" (with quotes grouping the tag keyword and the tag name together) passes them as a single argument to Git. This will cause the fetch operation to fail with a "does not appear to be a git repository" error. Separating them as distinct arguments ensures the remote-only tag is fetched successfully.
     git fetch origin tag "$RAW_REF" --quiet
  • hooks/pre-tool-use-claim-verification.sh:99 — 🟡 P2 (major) — The unanchored pattern grep[[:space:]]+-[rRnliN]+ matches any occurrence of grep followed by flags, which includes legitimate Git commands like git grep -n. This causes the hook to generate false-positive warnings even when users are running the exact ref-explicit git grep commands recommended by this very skill. Anchoring grep to the start of the command or a separator prevents these false positives.
  if printf '%s' "$cmd" | grep -qE '(^|[;&|][[:space:]]*)grep[[:space:]]+-[rRnliN]+'; then
  • hooks/pre-tool-use-claim-verification.sh:145 — 🟡 P2 (major) — The unanchored pattern grep[[:space:]]+-[rRnliN]+ matches git grep here as well, causing false positives in the suggestion logic. Anchoring grep to the start of the command or a separator keeps the matching logic consistent with the detector.
elif printf '%s' "$COMMAND" | grep -qE '(^|[;&|][[:space:]]*)grep[[:space:]]+-[rRnliN]+'; then

…OJ-4872)

Round-5 bot review at 2/5 confidence flagged 4 P2. All four are real
correctness bugs (no nits this round); applied verbatim.

P2 — hooks/pre-tool-use-claim-verification.sh detector grep false-positive
  - The unanchored pattern `grep[[:space:]]+-[rRnliN]+` matched any
    grep-followed-by-flags substring, including the EXACT ref-explicit
    replacement this hook recommends: `git grep -n "Symbol" origin/develop
    -- src/`. Result: the hook warned against its own suggested fix,
    creating a self-reinforcing false-positive loop. Anchored with
    `(^|[;&|][[:space:]]*)` so `grep` must be at the start of the command
    or after a separator, never inside `git grep`.

P2 — hooks/pre-tool-use-claim-verification.sh suggester grep false-positive
  - Same unanchored pattern in the suggester branch caused the
    `git grep` suggester to fire on legitimate `git grep` invocations
    that fell through to the suggester (they shouldn't get there at all
    if the detector is right, but defense-in-depth). Applied the same
    `(^|[;&|][[:space:]]*)` anchor.

P2 — commands/verify.md ARG undefined
  - The behavior section referenced `$ARG` in step 5 but never assigned
    it. Following the example verbatim would leave `$ARG` empty and break
    every verification. Added `ARG="$2"` next to `RAW_REF="$1"` at the
    top of step 1.

P2 — commands/verify.md tag-fetch arg gluing
  - `git fetch origin "tag $RAW_REF" --quiet` quotes the `tag` keyword
    together with the tag name as a single arg, which git parses as a
    refspec name → "does not appear to be a git repository" or "fatal:
    couldn't find remote ref" depending on git version. Switched to
    separate `tag` + `"$RAW_REF"` args, and refactored step 3 to use a
    case-statement dispatcher over `$FETCH_KIND` ("tag" | "branch" | "")
    so the tag-vs-branch fetch shapes stay distinct.

Verification:
  - shellcheck → 0 issues
  - "grep -rn \"Symbol\" src/"            → warn (regression)
  - "git grep -n \"Symbol\" origin/develop -- src/" → silent (was: WARN — the hook
                                                              was attacking its
                                                              own recommended fix)
  - "cd src && grep -rn \"Symbol\" ."     → warn (chain-after-separator works)
  - "echo hello"                        → silent (regression)

Created by Claude Code on behalf of @lapc506.
@lapc506
Copy link
Copy Markdown
Collaborator Author

lapc506 commented Jun 3, 2026

@dojo-code-reviewer review

Round-5 feedback (2/5, 4 P2) addressed — all four were real correctness bugs:

  • P2 hook detector: anchored grep -FLAGS so git grep -n no longer false-positives. Critical fix — the hook was attacking its own ref-explicit recommendation, creating a self-defeating warning loop.
  • P2 hook suggester: same anchor applied in the suggester branch.
  • P2 commands/verify.md ARG undefined: added ARG="$2" next to RAW_REF="$1". Without it, following the example verbatim would leave $ARG empty and break every verification.
  • P2 commands/verify.md tag-fetch arg gluing: switched git fetch origin "tag $RAW_REF" to separate tag + "$RAW_REF" args, and refactored step 3 to a case-statement dispatcher over $FETCH_KIND ("tag" | "branch" | "") so the tag vs branch fetch shapes stay distinct.

Smoke tests + shellcheck green. Fix commit: $(git rev-parse --short HEAD).

Copy link
Copy Markdown

@dojo-code-reviewer dojo-code-reviewer Bot left a comment

Choose a reason for hiding this comment

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

✅ Approved

Approved — no findings. Confidence: 5/5.

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