Discovered while addressing Greptile's review on PR #2490 (issue #2344).
lint-skill.sh's Check 1 (cross-fence variable usage) has a reference-checking exemption (currently around the [ ! "$line" == *'read '* ]-style condition guarding the error(...) call) meant to allow patterns like VAR=$(cat file) — genuinely re-deriving a value from a persisted file rather than relying on stale shell state from an earlier bash block.
read is included in that same exemption list, but as a blanket substring check on the whole line, not tied to whether the specific variable being referenced was actually the destination of that line's read. So a line that both (a) binds some unrelated variable via read and (b) separately references a different, genuinely-stale variable from an earlier block — e.g. a here-string interpolation — gets fully exempted, silently accepting a real cross-fence bug.
Repro (pre-existing on origin/main, independent of PR #2490's fix):
Block 1:
Block 2:
$FOO here is a genuine cross-fence leak (block 2 relies on block 1's shell state, which does not persist across separate ```bash fences) but lint-skill.sh reports 0 errors, because the line contains the substring read (from read -r BAR), which trips the blanket exemption meant for cat/read-from-file patterns — even though this read's own destination is BAR, not FOO.
Root cause: the exemption is a per-line substring match (*'read '*) rather than checking whether the specific referenced variable is the one actually bound by that line's read/cat.
Not fixed as part of #2344/PR #2490 — that PR's scope was the assignment-registration side (recognizing read as a binding mechanism so genuine same-block rebindings aren't flagged); this is a separate, pre-existing false-negative in the reference-checking side, discovered via Greptile's review while verifying the #2344 fix didn't introduce it.
Discovered while addressing Greptile's review on PR #2490 (issue #2344).
lint-skill.sh's Check 1 (cross-fence variable usage) has a reference-checking exemption (currently around the[ ! "$line" == *'read '* ]-style condition guarding theerror(...)call) meant to allow patterns likeVAR=$(cat file)— genuinely re-deriving a value from a persisted file rather than relying on stale shell state from an earlier bash block.readis included in that same exemption list, but as a blanket substring check on the whole line, not tied to whether the specific variable being referenced was actually the destination of that line'sread. So a line that both (a) binds some unrelated variable viareadand (b) separately references a different, genuinely-stale variable from an earlier block — e.g. a here-string interpolation — gets fully exempted, silently accepting a real cross-fence bug.Repro (pre-existing on
origin/main, independent of PR #2490's fix):Block 1:
Block 2:
$FOOhere is a genuine cross-fence leak (block 2 relies on block 1's shell state, which does not persist across separate```bashfences) butlint-skill.shreports 0 errors, because the line contains the substringread(fromread -r BAR), which trips the blanket exemption meant forcat/read-from-file patterns — even though thisread's own destination isBAR, notFOO.Root cause: the exemption is a per-line substring match (
*'read '*) rather than checking whether the specific referenced variable is the one actually bound by that line'sread/cat.Not fixed as part of #2344/PR #2490 — that PR's scope was the assignment-registration side (recognizing
readas a binding mechanism so genuine same-block rebindings aren't flagged); this is a separate, pre-existing false-negative in the reference-checking side, discovered via Greptile's review while verifying the #2344 fix didn't introduce it.