Skip to content

fix(docs-hygiene): audit-noise porcelain parse mangles paths containing " -> " and leaves \\ escaped #3143

Description

@kyle-sexton

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.

Metadata

Metadata

Assignees

Labels

agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.priority: needs-triageDefault until a priority tier is assigned.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions