stx a11y takes a directory, stx typecheck and stx codemod take a glob, and only one of them tells you when it matched nothing. Give a11y the argument shape its siblings document and it prints ✓ No accessibility issues found! and exits 0 — on a file that has three SERIOUS findings.
Measured on 0.2.175, against one real file (resources/emails/subscription-confirmation.stx, a layout table in an email template):
| argument | result | exit |
|---|---|---|
stx a11y resources | Total: 3 issues in 1 files | 1 |
stx a11y resources/emails | Total: 3 issues in 1 files | 1 |
stx a11y resources/emails/subscription-confirmation.stx | ✓ No accessibility issues found! | 0 |
stx a11y 'resources/**/*.stx' | ✓ No accessibility issues found! | 0 |
stx a11y 'zzz/**/*.stx' | ✓ No accessibility issues found! | 0 |
The third row is the whole bug in one line: the exact path of a file with three findings, reported clean.
Compare the sibling commands on the same tree:
$ stx typecheck resources
No .stx files matched resources
$ stx typecheck 'resources/**/*.stx'
Checked 47 script block(s) and 275 template expression(s) in 37 file(s) — 109 error(s)typecheck takes the glob and, given a directory, says it matched nothing. a11y takes the directory and, given a glob, says everything is fine. Both halves are inverted, and the inversion is silent in the direction that costs you.
Why this is worse than a wrong finding
A false positive gets triaged the first time someone reads it. This gets triaged never. The natural way to add the checker to CI is to copy the line that already works:
- run: stx typecheck 'resources/**/*.stx'
- run: stx codemod 'resources/**/*.stx'
- run: stx a11y 'resources/**/*.stx' # green foreverThat third line passes on every commit, for the life of the project, no matter what the markup does. Nothing distinguishes it from a project that has no accessibility problems.
It cost me directly: I have been quoting "a11y: 3" for a week, re-ran it after an upgrade with a glob instead of a directory, got 0, and wrote "down from 3" into a commit message before checking. The count had not moved. The argument had.
Cause
The path looks like it is joined into a scan pattern rather than tested. A file argument becomes <file>/**/*.stx, which matches nothing; zzz/**/*.stx becomes zzz/**/*.stx/**/*.stx, which also matches nothing; both then take the empty-set branch, which prints the success banner. A directory that does not exist throws ENOENT instead, so the failure mode is not even consistent with itself.
Suggested fix
Two independent changes, and the second matters more:
- Accept a directory, a file, or a glob in all three commands — whichever the user passes.
typecheckandcodemodalready resolve globs; sharing that resolver is the smallest change. - An empty match set is not a pass.
typecheck'sNo .stx files matched <arg>is the right behaviour and should be whata11ydoes too — ideally non-zero exit, since a CI step that scanned nothing has not verified anything. The success banner should require having actually read at least one file.
Point 2 alone would have surfaced this the first time anyone pointed the command at a glob.
Environment
- stx 0.2.175 (built from source at
6e29f859a6) - bun 1.3.14, macOS 15
- app: a 38-view Stacks app, run as the e2e surface for stx