Problem
tools/policy_check.sh CHECK 15 guards plugin runtime prose (plugin/**/*.md, plugin/workflows/*.json) against GitHub tracker references such as #123. Local review of the branch that introduced it found two latent false negatives. The maintainer accepted both for the initial merge. Neither affects current content: the check reports zero findings on plugin/ today.
- Glued references are exempted (detection). The check normalizes each line by removing legal constructs and then flags any remaining
#<digits>. The clause meant to exempt repo-qualified citations such as cli/cli#12258 (s@([A-Za-z0-9_/])#@\1@g) strips # after any word character. As a result, issue#123 and PR#456 are silently exempt. No plugin/ file uses that form today.
- Unreadable files pass as clean (traversal). Discovery (
find ... 2>/dev/null) and per-file reads (awk ... "$file" inside a process substitution) run without checking exit status. A file that fails to read yields an empty stream, which the caller treats as clean. The existing per-arm zero-file assertions only catch a completely empty discovery arm.
Root cause
Both halves fail open. Detection is a reject list: it strips everything that looks harmless and flags the rest, so any over-broad exemption hides real references. Traversal trusts producer output without checking that the producer succeeded. Each review round found one more unlisted edge. Patching single clauses does not close the class.
Proposed approach
- Detection: flag every
#<digits> unless it matches one of a small set of exact known-safe shapes, for example a full owner/repo#N citation, an in-page anchor ](#slug), or an inline-code span. Constructs the rules did not anticipate then produce visible findings instead of silent passes.
- Traversal: materialize the discovered file list with checked exit status, read each file with a checked read, and fail the check on any discovery or read error.
- Extend the existing predicate canary and scanner canary with fixtures for
issue#123, PR#456, and an unreadable file, so each half has a witness in both directions.
Scope
Limited to tools/policy_check.sh (CHECK 15), tests/policy/safety-tracker-ref-guard.json, and tests/policy/fixtures/tracker-ref-*.md. No plugin/ change is required.
Problem
tools/policy_check.shCHECK 15 guards plugin runtime prose (plugin/**/*.md,plugin/workflows/*.json) against GitHub tracker references such as#123. Local review of the branch that introduced it found two latent false negatives. The maintainer accepted both for the initial merge. Neither affects current content: the check reports zero findings onplugin/today.#<digits>. The clause meant to exempt repo-qualified citations such ascli/cli#12258(s@([A-Za-z0-9_/])#@\1@g) strips#after any word character. As a result,issue#123andPR#456are silently exempt. Noplugin/file uses that form today.find ... 2>/dev/null) and per-file reads (awk ... "$file"inside a process substitution) run without checking exit status. A file that fails to read yields an empty stream, which the caller treats as clean. The existing per-arm zero-file assertions only catch a completely empty discovery arm.Root cause
Both halves fail open. Detection is a reject list: it strips everything that looks harmless and flags the rest, so any over-broad exemption hides real references. Traversal trusts producer output without checking that the producer succeeded. Each review round found one more unlisted edge. Patching single clauses does not close the class.
Proposed approach
#<digits>unless it matches one of a small set of exact known-safe shapes, for example a fullowner/repo#Ncitation, an in-page anchor](#slug), or an inline-code span. Constructs the rules did not anticipate then produce visible findings instead of silent passes.issue#123,PR#456, and an unreadable file, so each half has a witness in both directions.Scope
Limited to
tools/policy_check.sh(CHECK 15),tests/policy/safety-tracker-ref-guard.json, andtests/policy/fixtures/tracker-ref-*.md. Noplugin/change is required.