Skip to content

Em dash guard boundary: what to review โ€‹

FieldValue
Branchfeat/admin-and-merchant-portals, draft PR #976: feat(admin): portal navigation, financials and monitoring, plus the agent-process work behind them, not merged
ProjectREADME.md
Issue#967: key-conventions.md said the em dash guard never sees a heredoc; it blocked one twice today
Servers you needNone. Nothing to click, and no code changed. This is a documentation correction
Local originsNot applicable

Is there anything to look at? โ€‹

One sentence, in one rule file, and its four synced copies. โ€‹

  • The source is .agents/rules/project/key-conventions.md. The copies are AGENTS.md, .cursor/rules/key-conventions.mdc and .github/instructions/key-conventions.instructions.md.
  • guard-em-dash.sh itself was NOT changed. Nothing about how the hook behaves is different.
  • Read the corrected sentence: it is quoted in full in README.md, and it is already live in AGENTS.md under Key Conventions.

What changed here? โ€‹

The rule said the hook never sees a heredoc. That was false, and three sessions built on it. โ€‹

  • The .claude/settings.json matcher is Write|Edit|Bash, and the Bash branch scans any command whose text CONTAINS git or gh . A heredoc feeding a git commit message or a gh PR body IS caught, which is exactly why a dispatched agent got blocked twice that day before ever touching a file.
  • Three sessions read the wrong sentence, treated heredoc writes as fully unguarded, and a compensating control got built on that false premise.

The real boundary was established by TESTING before anything was written. โ€‹

  • Ten crafted payloads piped into the live hook script, reading the real exit code, with controls both ways.
  • Caught: a literal dash in a git commit command text.
  • Not caught, all verified: a non-git echo; a git log whose format string comes from command substitution; git commit -m "$VAR"; git checkout HEAD -- file restoring tracked content; git apply; cp and mv; a program's own output redirected to a file.
  • One thing is reasoned rather than tested and says so: whether a literal em dash inside a non-git heredoc body would be scanned. It could not be tested without typing the character, which this task's own constraint forbade.
  • Corrected 2026-08-30: "names git or gh" was too narrow. The matcher is a substring glob, so through, high, enough and digit are scanned too, all four re-verified against the live hook. The "not caught" list above still holds, because none of those commands carries either substring. The guard errs safe and was again left alone.

What is deliberately NOT done? โ€‹

The guard's behaviour was left alone on purpose. โ€‹

A live end-to-end proof in a scratch git repo was attempted and abandoned. โ€‹

  • The PM lane guard refused the command, and the session's CLAUDE_ALLOW_PM_BUILD=1 authorization was scoped to key-conventions.md and the sync output only. The override was not used to push past it.
  • The ten direct hook invocations already exercise the real code path and were treated as sufficient.

What open findings touch this project? โ€‹

  • Nothing from ../merchant-and-venue-dashboards/branch-review-0828.md.
  • One thing worth knowing about the review of this work itself: a second guard, guard-backtick-body.sh, blocked the first commit attempt because live $( ) substitution inside a double-quoted -m argument is a shell-injection shape. Its own message names the fix, and the commit went through with -F against a pre-checked message file. Both guards did their job.

What issue does each piece close? โ€‹

PieceIssueState
The corrected sentence and its four synced copies#967: key-conventions.md said the em dash guard never sees a heredoc; it blocked one twice todayFixed on branch
The opposite failure direction in the same guard#945: A text-scanning guard cannot tell content from a pattern that matches contentOpen, guard deliberately untouched

Built with VitePress