You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
finding: check-where-matcher-conformance cannot grade an INVERTED survivor filter — the control probe drops it, so a delete double's combinator blindness stays ungraded #8662
Filed while working #8615 (PR #8661), which extended check-where-matcher-conformance's
discovery to single-parameter .filter() callbacks that capture their where from an
enclosing scope.
The gap
That extension proposed 64 new structural candidates. The behavioural control probe seated
62 and dropped 2. The 2 it dropped share one shape — an inverted survivor filter inside
a delete double:
The control probe admits a candidate only when f(ROW, MATCH) === true and f(ROW, MISS) === false. An inverted predicate answers false/true, so it is dropped as
OUT_OF_SCOPE — correctly, by the gate's own definition: it is not a row-selecting
predicate.
But it carries the identical failure shape (b) the gate exists to catch, one negation away.
A $or handed to one of these is read as an ordinary field name, row.$or is undefined, .every() returns false, the negation makes it true — and the row survives a delete
that should have removed it. The suite then asserts on a table that was never modified,
with nothing erroring. Same silence, opposite sign.
Teaching the control probe to recognise a negated predicate means inferring intent from
syntax — deciding that a leading ! means "invert my expectations". That is precisely the
naming-and-shape reasoning the gate's header rules out ("membership is decided by behaviour,
not by a name"), and a probe that guesses wrong in this direction grades a non-matcher as a
matcher, which is worse than not grading it.
The two known instances were fixed on their merits in #8661 (they now refuse an
unrecognised $-key), and the limit is pinned there as a self-test fixture
(FIXTURE_CAPTURED_NEGATED) so it stays a known limit rather than drifting into an
accidental one. What remains open is that the gate still cannot grade this spelling: a
new inverted survivor filter written tomorrow is invisible to it, exactly as the single-param
capture was before #8615.
both are DORMANT — no suite currently hands either one a $or/$and (verified: the
refusals changed no test outcome across 11,257 tests)
structural candidates the probe currently drops for this reason: 2 of 64
Options, not investigated further
Give the battery a second admission mode: a candidate that answers the control probe
exactly inverted (false/true) is seated as an INVERTED matcher and graded against a
negated battery. Keeps the criterion behavioural — inversion is measured, not read off a ! token.
Option 1 looks structurally right and is the same move #8615 made one level down, but the
false-positive load of a second admission mode is unmeasured and that measurement is the
work here, not the coding.
Refs: #8615 (the discovery extension that surfaced this), #8661 (the PR), #8494 (the gate), #8582 / #7620 (the original sweeps).
Filed while working #8615 (PR #8661), which extended
check-where-matcher-conformance'sdiscovery to single-parameter
.filter()callbacks that capture theirwherefrom anenclosing scope.
The gap
That extension proposed 64 new structural candidates. The behavioural control probe seated
62 and dropped 2. The 2 it dropped share one shape — an inverted survivor filter inside
a
deletedouble:The control probe admits a candidate only when
f(ROW, MATCH) === trueandf(ROW, MISS) === false. An inverted predicate answersfalse/true, so it is dropped asOUT_OF_SCOPE — correctly, by the gate's own definition: it is not a row-selecting
predicate.
But it carries the identical failure shape (b) the gate exists to catch, one negation away.
A
$orhanded to one of these is read as an ordinary field name,row.$orisundefined,.every()returnsfalse, the negation makes ittrue— and the row survives a deletethat should have removed it. The suite then asserts on a table that was never modified,
with nothing erroring. Same silence, opposite sign.
Why this was not "fixed" in #8661
Teaching the control probe to recognise a negated predicate means inferring intent from
syntax — deciding that a leading
!means "invert my expectations". That is precisely thenaming-and-shape reasoning the gate's header rules out ("membership is decided by behaviour,
not by a name"), and a probe that guesses wrong in this direction grades a non-matcher as a
matcher, which is worse than not grading it.
The two known instances were fixed on their merits in #8661 (they now refuse an
unrecognised
$-key), and the limit is pinned there as a self-test fixture(
FIXTURE_CAPTURED_NEGATED) so it stays a known limit rather than drifting into anaccidental one. What remains open is that the gate still cannot grade this spelling: a
new inverted survivor filter written tomorrow is invisible to it, exactly as the single-param
capture was before #8615.
Measured state
mainat filing: 2, both fixed in test(where-matcher): discover single-param filter callbacks that capture their where #8661packages/plugins/plugin-email/src/attachment-reclaim.test.tspackages/plugins/plugin-webhooks/src/auto-enqueuer.test.ts$or/$and(verified: therefusals changed no test outcome across 11,257 tests)
Options, not investigated further
exactly inverted (
false/true) is seated as an INVERTED matcher and graded against anegated battery. Keeps the criterion behavioural — inversion is measured, not read off a
!token.it is the same "a gate that cannot see a class of instance" argument check-where-matcher-conformance's discovery heuristic misses single-param inline filter closures — 16 files carry the same shape-(b) blind spot, undetected #8615 was filed on.
Option 1 looks structurally right and is the same move #8615 made one level down, but the
false-positive load of a second admission mode is unmeasured and that measurement is the
work here, not the coding.
Refs: #8615 (the discovery extension that surfaced this), #8661 (the PR), #8494 (the gate),
#8582 / #7620 (the original sweeps).