Skip to content

ci: three gates could pass without checking anything, and only one had a way to notice #556

Description

What happened

Session 221 hit three gates that report success while checking nothing, in one session, by
accident. None of them was found by running it — all three are silent by construction, because the
tree they scan is clean, and "found nothing" and "looked at nothing" produce identical output.

  1. lint-tests.ps1 -Paths a b c linted only a. pwsh -File binds the first token to -Paths
    and drops the rest unless a ValueFromRemainingArguments sibling catches them. Six scripts were
    missing it. .llm/context.md documented that exact multi-file invocation. Measured: -Paths
    with all 1,118 test files reported 0 advisories where the same files report 72.
    Fixed in Order every comparison; fix three silent gates #555, enforced by a new PWS005.
  2. A pre-filter in test-shell-portability.sh disabled all six sections it was added to.
    $( ) strips trailing newlines, so the last candidate never matched the membership test — and
    the probe sorted last for every token. Caught only by injecting a violation per section and
    diffing against the unmodified script. Fixed in Order every comparison; fix three silent gates #555, with a self-check in the helper.
  3. A --fix in the new comparison-direction linter corrupted an interpolated string. This one
    was caught, but only because the result did not compile. Had it compiled, nothing would have
    said so.

Why this is its own ticket

Each fix is local, and the class is not. The property that matters is: can this gate go red? For
a scanner over a clean corpus, a green run is not evidence that it can. Three of our gates could not,
and we have on the order of sixty.

Prior art in this repository is the same shape and was written down at the time:
test-shell-portability.sh already carried a comment saying each replaced pattern "was verified to
select exactly the same lines as the grep it replaces, over the real corpus PLUS a synthetic line
per pattern -- the corpus contains no violations, so agreement on it alone would only prove the
absence of false positives, not that the checks still fire." That is exactly the discipline that was
then not applied to the next change to the same file.

Ask

  1. Inventory the gates whose corpus is clean by construction — every linter in lint:repo and
    validate:tests that scans the tree and reports violations. For each, does a self-test inject a
    violation and assert it is reported, or does it only assert a clean run passes?
  2. Add the missing red halves. The pattern already exists in several self-tests
    (test-lint-csharp-naming.ps1, test-lint-comparison-direction.js, the new PWS005 probe):
    write a fixture that violates, assert non-zero exit and the file/line in the message.
  3. Consider a meta-check: a linter registered in lint:repo with no corresponding self-test that
    can make it fail is itself reportable. test-run-repo-lint.js already asserts "no linter in
    scripts/ has been left unreachable"; "no linter has been left unfalsifiable" is the same idea
    one level up.

Not blocking anything — all three known instances are fixed. This is about the ones nobody has
tripped over yet.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions