A signature read that failed after one byte looked like a one-byte text
file and was skipped. The pipeline now runs under pipefail, so the file is
listed as unverified instead.
When cut, sort or uniq is missing, Step 7 says the tally is unavailable.
The count does not depend on them.
Step 1 skipped binaries while the role promised to verify the whole project,
so a credential in a spreadsheet, a PDF or an embedded database got a clean
PASS and never showed up in the report.
Step 7 now lists every file that doesn't read as text, plus any directory it
can't enter, and the pipeline stops on that list until a person confirms. On
this repo that's a few dozen files, all images and video, which is why they're
warnings and not failures. It doesn't try to extract or scan them: that needs
nested-archive recursion and size bounds, and I'd rather list a file than
half-scan it.
Detection is a first-byte signature check plus a whole-file NUL/control-byte
test, with file(1) only widening the list. If a detector fails, the file is
listed as unverified.
Filenames are untrusted, so Step 7 writes the paths to a manifest beside the
project directory, for a person to open, and keeps them out of its stdout
and its report section. Beside and not inside, so a re-run's text scans
can't read it back. The script prints the count itself as its last line. A
scan problem, a failed write, a walk that dies early or a run that never
reaches that line gives an unknown count, and the gate treats unknown as a
stop, not as zero.
Step 1 no longer skips *.min.js.
Tests in tests/skills/sanitizer-unreadable.test.js. Editing SKILL.md changes
the skill registry digest, so skill-triggers@1.json carries the new value.
Add compact prompt-defense baselines to active ECC prompt surfaces and copied CLAUDE examples. AgentShield prompt-defense findings are now zero; local tests passed 2366/2366.