What is wrong
Two sibling scripts in the claude-config:audit-instructions skill disagree about the path form a scan row may carry, so findings are discarded between them.
scripts/instruction-scan.sh emits candidate rows as file:line:check-id, using whatever path form the caller handed it. Naming a repo-owned surface relatively is the ordinary invocation, and SKILL.md documents the call as instruction-scan.sh <file>... with no requirement that the path be absolute.
scripts/emit-findings.sh relativizes each row's path with relativize_in_repo(), which tests the path against three absolute anchors (repo_root_pwd, repo_root, repo_root_alt) and returns the empty string when none of them prefixes it. A path that is already repo-relative — exactly the form Location requires — matches no absolute anchor, so it returns empty and the row is declined as outside-repo-root.
Reproduction
In a git checkout containing withfm.md (a file with ordinary YAML frontmatter and a CRITICAL: directive in its body):
$ bash instruction-scan.sh --body-only withfm.md
withfm.md:6:I28-a
$ bash emit-findings.sh --from scan.txt --out out.md --branch b
$ grep -E '^\| [0-9]|Declined|Emitted' out.md
Scan rows read: 1. Emitted: 0.
Declined candidates: I28-a count=1 reason=outside-repo-root (Location must be repo-relative; human report only)
The identical file named by absolute path emits normally:
Scan rows read: 1. Emitted: 1.
| 1 | IMPORTANT | high | withfm.md:6 | ... |
Note that the emitted Location in the working case is withfm.md:6 — the very form that was rejected as not repo-relative when supplied directly.
Why it matters
The scanner's own natural output is silently unusable by its consumer. Every finding from a relatively-named target is dropped from the machine-readable relay and survives only in the human report, and the stated decline reason ("Location must be repo-relative") is the opposite of the truth for these rows.
plugins/ai-slop/skills/audit/scripts/emit-findings.sh does not have this gap: its relativize() returns the path unchanged when no anchor matches, rather than declining the row.
Suggested direction
Treat a path that is not absolute as already repo-relative and admit it as-is.
One caveat worth handling in the same change: admitting relative paths is what makes traversal expressible here. The anchor test is lexical, so .. segments are not currently considered — <repo>/../outside.md prefix-matches an anchor and would relativize to ../outside.md, which the fix pass would then resolve outside the working tree. A path holding a .. segment should be refused outright, which is the fail-closed direction and preserves the fence's stated purpose.
Context
#3242 reworked path anchoring in both emit-findings.sh producers to resolve repo-root spelling differences. The relative-path case was not part of that change. There is no test covering a relative scan-row path in scripts/emit-findings.test.sh today.
What is wrong
Two sibling scripts in the
claude-config:audit-instructionsskill disagree about the path form a scan row may carry, so findings are discarded between them.scripts/instruction-scan.shemits candidate rows asfile:line:check-id, using whatever path form the caller handed it. Naming a repo-owned surface relatively is the ordinary invocation, andSKILL.mddocuments the call asinstruction-scan.sh <file>...with no requirement that the path be absolute.scripts/emit-findings.shrelativizes each row's path withrelativize_in_repo(), which tests the path against three absolute anchors (repo_root_pwd,repo_root,repo_root_alt) and returns the empty string when none of them prefixes it. A path that is already repo-relative — exactly the formLocationrequires — matches no absolute anchor, so it returns empty and the row is declined asoutside-repo-root.Reproduction
In a git checkout containing
withfm.md(a file with ordinary YAML frontmatter and aCRITICAL:directive in its body):The identical file named by absolute path emits normally:
Note that the emitted
Locationin the working case iswithfm.md:6— the very form that was rejected as not repo-relative when supplied directly.Why it matters
The scanner's own natural output is silently unusable by its consumer. Every finding from a relatively-named target is dropped from the machine-readable relay and survives only in the human report, and the stated decline reason ("Location must be repo-relative") is the opposite of the truth for these rows.
plugins/ai-slop/skills/audit/scripts/emit-findings.shdoes not have this gap: itsrelativize()returns the path unchanged when no anchor matches, rather than declining the row.Suggested direction
Treat a path that is not absolute as already repo-relative and admit it as-is.
One caveat worth handling in the same change: admitting relative paths is what makes traversal expressible here. The anchor test is lexical, so
..segments are not currently considered —<repo>/../outside.mdprefix-matches an anchor and would relativize to../outside.md, which the fix pass would then resolve outside the working tree. A path holding a..segment should be refused outright, which is the fail-closed direction and preserves the fence's stated purpose.Context
#3242 reworked path anchoring in both
emit-findings.shproducers to resolve repo-root spelling differences. The relative-path case was not part of that change. There is no test covering a relative scan-row path inscripts/emit-findings.test.shtoday.