fix(guard): note each unresolved command once - #200
Merged
Merged
Conversation
The pre-tool-use guard pushed a finding per invocation with no deduplication, so a loop repeated every unresolved note once per iteration. It also added the tasks-and-apps note to any unresolved command, including printf and jq, which nothing in the project runs. decide now keeps each distinct finding once, blocks included. The tasks-and-apps note needs a program some task run, app launch or catalog entry could claim. An unresolved program word keeps the note whenever the project has tasks or apps. Closes #196 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
AbysmalBiscuit
deleted the
196-fix-guard-note-each-unresolved-command
branch
September 27, 2026 19:55
AbysmalBiscuit
added a commit
that referenced
this pull request
Sep 27, 2026
🤖 I have created a release *beep* *boop* --- ## [0.14.7](v0.14.6...v0.14.7) (2026-09-27) ### Features * **brief:** add a rules section ([#160](#160)) ([7ba41e2](7ba41e2)) * **brief:** list tasks by app and trim the brief ([#162](#162)) ([d991929](d991929)) * **command:** model permission changes ([#174](#174)) ([4aea742](4aea742)) * **config:** describe task args and variables ([#159](#159)) ([34e0076](34e0076)) * **docm:** treeless clones and per-library excludes ([#157](#157)) ([a4f4410](a4f4410)) * **forge:** support GitLab and Forgejo alongside GitHub ([#183](#183)) ([1926908](1926908)) * **harness:** claim bounded shell write sets ([#158](#158)) ([a72acf1](a72acf1)) * **hook:** parse Cursor and Antigravity payloads with pabal 0.2 ([#191](#191)) ([00e2918](00e2918)) * **hooks:** add before_worktree_remove ([#140](#140)) ([1ea3aed](1ea3aed)) * **issue:** add dashboard chart aggregation modes ([#144](#144)) ([61ad36a](61ad36a)) * **issue:** label the y-axis of dashboard charts ([#143](#143)) ([99e7b29](99e7b29)) * **issues:** create issues from enforced templates ([#185](#185)) ([3a38874](3a38874)) * **issue:** take the summary from the tracker ([#138](#138)) ([30425fb](30425fb)) * **rules:** add rules add, edit and remove ([#150](#150)) ([7052dd4](7052dd4)) * **rules:** honor repo-rules-agent.toml in query ([#151](#151)) ([e7a1d1f](e7a1d1f)) * **template:** render templates on demand ([#165](#165)) ([2da3c36](2da3c36)) * **templates:** add variable descriptions ([#152](#152)) ([918f594](918f594)) ### Bug Fixes * **command:** end the fresh-path exemption on placement ([#125](#125)) ([40ae328](40ae328)) * **common:** keep live blocks from climbing over output ([#141](#141)) ([2e2b919](2e2b919)) * **git:** fail fast when ssh needs a prompt ([#142](#142)) ([8fe7ae3](8fe7ae3)) * **guard:** note each unresolved command once ([#200](#200)) ([2bcd2fa](2bcd2fa)) * **guard:** redirect only commands a task covers ([#198](#198)) ([f6c0488](f6c0488)) * **hooks:** keep enforcement on past a broken layer ([#190](#190)) ([8846a35](8846a35)) * **issue:** allow setup --slug without an issue id ([#127](#127)) ([7c28ba7](7c28ba7)) * **issue:** dashboard spinners, x labels and status colors ([#149](#149)) ([b35e2ed](b35e2ed)) * **issue:** hold worktrees past their merged PR ([#189](#189)) ([a27a28b](a27a28b)) * **issue:** make status, info, end and MCP agree ([#193](#193)) ([cd9b46a](cd9b46a)) * **issue:** report ambiguous branch PRs in review finish ([#192](#192)) ([ff2cf62](ff2cf62)) * **locks:** free every root on release --all ([#199](#199)) ([d55ba01](d55ba01)) * **tasks:** refuse a blank required arg ([#173](#173)) ([d1b32b3](d1b32b3)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR (human written)
Closes #196
Agent summary
The pre-tool-use guard repeated its "could not be fully resolved" notes once per loop iteration, and added the tasks-and-apps note to commands nothing in the project runs. A 4-iteration loop with five segments came back with 20 notes. Most of them named
printf,jqornode, so the agent could not act on them.Fix
decidekeeps each distinct finding once per hook call. Blocks go through the same path, socargo buildrepeated in a loop returns one deny reason instead of one per iteration.run, an applaunch, or a catalog dev server such asvite. Both sides are unwrapped the way the matcher does it, so adoppler run -- cargo buildtask still counts ascargo. When the program word itself is unresolved, the note stays whenever the project has tasks or apps.That same loop now yields 2 notes: one for
cargo build "$(date)"and one for the[harness.commands]rulenode "$y"might hit.A side effect:
vite "$x"in a project with no tasks or apps now gets the note. The guard denies a resolvedvitethere too, so the note is accurate.Tests
Three end-to-end tests in
tests/harness_guard.rssend a hook payload through thedevkit hook pre-tool-usebinary:printf/jqtest failed before the fix because aprintfnote came back.cargo build "$x",nitro "$x",vite "$x","$tool" build) passes both before and after. It checks that the fix does not drop notes it should keep.Not fixed here
The guard redirects a filtered test run to a task:
cargo nextest run --test harness_guardtotest, andcargo test --test harness_guardtotest-doc, which runs only doctests. A filtered run is not the task. That belongs in its own issue.🤖 Generated with Claude Opus 5.5 (claude-opus-5-5) via Claude Code