Summary
Two defects in audit-noise's git status --porcelain parse, found while fixing the sibling code-tidying/audit-comment-residue parse in #3126 / #3140. Deferred out of that PR because it is a different plugin, needing its own version bump and CHANGELOG.
Observed in docs-hygiene@0.18.3.
plugins/docs-hygiene/skills/audit-noise/scripts/detect.sh L119–133.
1. Rename split is ungated, so an ordinary path containing " -> " is mangled
local_path="${line:3}"
if [[ "$local_path" == *" -> "* ]]; then
local_path="${local_path##* -> }"
fi
The split fires on any record whose path contains " -> ", not only on a rename. A file literally named notes -> draft.md is reduced to draft.md, which names no file, so it drops out of the audit silently — the same false-negative class as #3126.
The fix that landed in audit-comment-residue (#3140) gates on the status letter in either column, which is both narrower and complete:
if [[ "${line:0:1}" == [RC] || "${line:1:1}" == [RC] ]]; then
Note the two parsers currently fail in opposite directions on renames, so neither is a straight copy of the other: audit-noise over-splits (ungated), while audit-comment-residue pre-#3140 under-split (index column only). Both are now wrong in different ways relative to the gated-on-both-columns form.
2. \\ is not unescaped
local_path="${local_path//\\\"/\"}"
\" → " is handled; \\ → \ is not. Git C-quotes a path for an embedded backslash too, so a filename such as back\-slash.md stays as the escaped back\\-slash.md and resolves to nothing. audit-comment-residue now does both, in that order:
local_path="${local_path//\\\"/\"}"
local_path="${local_path//\\\\/\\}"
Order matters — \" first, then \\ — verified against both\".md-style interleaved escapes.
Shared residual
Neither parser decodes git's octal escapes for control and non-ASCII bytes, so those paths still miss on both sides. #3140 records that limitation at its parse site rather than leaving it implicit. Converging both skills on git status --porcelain -z would close the whole class outright — NUL-delimited, unquoted paths — at the cost of handling renames as two separate fields instead of old -> new. Worth considering as the real fix rather than porting the string-parse a third time.
Suggested approach
Port the gated split and the two-step unescape from plugins/code-tidying/skills/audit-comment-residue/scripts/detect.sh (post-#3140), or converge both on -z.
Regression fixtures need a path containing a literal " -> " and a path containing a backslash — a plain path passes either implementation. detect.test.sh case 10 in #3140 is a working model for testing the mirrored SKILL.md parser by extracting and executing it, which audit-noise's SKILL.md line will need too if it shares the parse.
Summary
Two defects in
audit-noise'sgit status --porcelainparse, found while fixing the siblingcode-tidying/audit-comment-residueparse in #3126 / #3140. Deferred out of that PR because it is a different plugin, needing its own version bump and CHANGELOG.Observed in
docs-hygiene@0.18.3.plugins/docs-hygiene/skills/audit-noise/scripts/detect.shL119–133.1. Rename split is ungated, so an ordinary path containing
" -> "is mangledThe split fires on any record whose path contains
" -> ", not only on a rename. A file literally namednotes -> draft.mdis reduced todraft.md, which names no file, so it drops out of the audit silently — the same false-negative class as #3126.The fix that landed in
audit-comment-residue(#3140) gates on the status letter in either column, which is both narrower and complete:Note the two parsers currently fail in opposite directions on renames, so neither is a straight copy of the other:
audit-noiseover-splits (ungated), whileaudit-comment-residuepre-#3140 under-split (index column only). Both are now wrong in different ways relative to the gated-on-both-columns form.2.
\\is not unescapedlocal_path="${local_path//\\\"/\"}"\"→"is handled;\\→\is not. Git C-quotes a path for an embedded backslash too, so a filename such asback\-slash.mdstays as the escapedback\\-slash.mdand resolves to nothing.audit-comment-residuenow does both, in that order:Order matters —
\"first, then\\— verified againstboth\".md-style interleaved escapes.Shared residual
Neither parser decodes git's octal escapes for control and non-ASCII bytes, so those paths still miss on both sides. #3140 records that limitation at its parse site rather than leaving it implicit. Converging both skills on
git status --porcelain -zwould close the whole class outright — NUL-delimited, unquoted paths — at the cost of handling renames as two separate fields instead ofold -> new. Worth considering as the real fix rather than porting the string-parse a third time.Suggested approach
Port the gated split and the two-step unescape from
plugins/code-tidying/skills/audit-comment-residue/scripts/detect.sh(post-#3140), or converge both on-z.Regression fixtures need a path containing a literal
" -> "and a path containing a backslash — a plain path passes either implementation.detect.test.shcase 10 in #3140 is a working model for testing the mirroredSKILL.mdparser by extracting and executing it, whichaudit-noise'sSKILL.mdline will need too if it shares the parse.