⛔ Ungraded and unrouted — domain:*, priority and type are triage's. Filed by the domain:devx execution PM seat (#6023), session session_012GKcPZbMoGq7WPzKLfRBTU, out of the at-tier contract review of PR #17036 (card #16119). Left unassigned.
⚠️ This is a RUNTIME defect, not a linter one. #16119's linter rules detect the authoring mistake correctly. What is filed here is what the runtime does with it, which is the opposite of what every document in the tree says.
The reading
An RLS predicate naming a column the object does not declare, in a negation-carrying position, does not narrow and does not deny — it widens the policy to every row inside the tenant wall.
Shapes measured: nope != "x" · !(nope == 1) · !(nope in ['a']) · is_private == false || nope != "x".
Mechanism — two independent code sites, both confirmed by this seat on origin/main
1. The field-existence safety net does not catch these shapes. packages/plugins/plugin-security/src/security-plugin.ts, the RLS collection path:
const targetField = this.extractTargetField(p.using);
if (!targetField) return true; // ⇐ policy KEPT
…
dropped++; return false; // ⇐ only reached when a field WAS extracted
if (layer1 == null && dropped > 0) layer1 = { ...RLS_DENY_FILTER };
extractTargetField (:7418) matches an =-only shape — the file says so itself at :5808 («via extractTargetField's =-only shape match»). ⇒ For a != / ! / not in predicate it returns null, the policy is kept, dropped never increments, and the deny sentinel never arms. The comment two lines above calls this arm "Field-existence safety … a deny contribution (fail-closed)" — ⚠️ true for the = shape it recognises, and ⛔ not true for these.
2. The matcher rules that a missing value SATISFIES a negation. packages/drivers/driver-memory/src/memory-matcher.ts:
function noValueSatisfiesNegation(op: string): boolean {
return op === '$ne' || op === '$nin' || op === '$notContains';
}
That is the #13166 ruling, stated deliberately and shared with driver-mongodb. ⇒ A phantom column lowers to {nope:{$ne:"x"}}, no row has that column, so every row satisfies it.
Measured end to end (contract reviewer, driver-memory dist, 3 seeded rows)
| filter |
rows returned |
{nope:{$ne:"x"}} |
3 / 3 |
{$not:{nope:1}} |
3 / 3 |
{$or:[{is_private:false},{nope:{$ne:"x"}}]} |
3 / 3 |
{is_private:false} — control |
1 / 3 |
{nope:false} — phantom positive control |
0 / 3 |
The two controls are what make the 3/3 a reading: the same harness narrows correctly on a real column and returns nothing on a phantom column in a positive position.
⛔ Scope — stated narrowly, because overstating this would be worse than not filing it
Why it matters, and why it was invisible
Three separate places in the tree state the opposite consequence, and #16119's own card is one of them:
⇒ ⭐ The escalation clause fired, but on the half nobody was watching. ⚠️ Grading is triage's and this seat asserts none — but the clause's own text should be read against these measurements rather than re-derived.
Re-check
git show origin/main:packages/plugins/plugin-security/src/security-plugin.ts | grep -n "extractTargetField's \`=\`-only\|if (!targetField) return true"
git show origin/main:packages/drivers/driver-memory/src/memory-matcher.ts | grep -n "noValueSatisfiesNegation"
Both return hits on the current tree. Positive control: RLS_DENY_FILTER also matches in the same file, so a zero above would be a broken pattern rather than a removed mechanism. Duplicate check: the 100 most recently created issues carry no card of this shape (control: 2 of them mention RLS, so the scan was not silently empty) — ⚠️ a bounded window, not the whole backlog.
Related
#16119 / PR #17036 (the linter that detects the authoring mistake; its prose is being corrected) · #13166 (the include-direction ruling that makes a missing value satisfy a negation) · #16518 (a reserved current_user key the compiler never binds — the adjacent, fail-closed seam)
Generated by Claude Code
Generated by Claude Code
⛔ Ungraded and unrouted —
domain:*, priority and type are triage's. Filed by thedomain:devxexecution PM seat (#6023), sessionsession_012GKcPZbMoGq7WPzKLfRBTU, out of the at-tier contract review of PR #17036 (card #16119). Left unassigned.The reading
An RLS predicate naming a column the object does not declare, in a negation-carrying position, does not narrow and does not deny — it widens the policy to every row inside the tenant wall.
Shapes measured:
nope != "x"·!(nope == 1)·!(nope in ['a'])·is_private == false || nope != "x".Mechanism — two independent code sites, both confirmed by this seat on
origin/main1. The field-existence safety net does not catch these shapes.
packages/plugins/plugin-security/src/security-plugin.ts, the RLS collection path:extractTargetField(:7418) matches an=-only shape — the file says so itself at:5808(«viaextractTargetField's=-only shape match»). ⇒ For a!=/!/not inpredicate it returnsnull, the policy is kept,droppednever increments, and the deny sentinel never arms. The comment two lines above calls this arm "Field-existence safety … a deny contribution (fail-closed)" —=shape it recognises, and ⛔ not true for these.2. The matcher rules that a missing value SATISFIES a negation.
packages/drivers/driver-memory/src/memory-matcher.ts:That is the #13166 ruling, stated deliberately and shared with
driver-mongodb. ⇒ A phantom column lowers to{nope:{$ne:"x"}}, no row has that column, so every row satisfies it.Measured end to end (contract reviewer, driver-memory
dist, 3 seeded rows){nope:{$ne:"x"}}{$not:{nope:1}}{$or:[{is_private:false},{nope:{$ne:"x"}}]}{is_private:false}— control{nope:false}— phantom positive controlThe two controls are what make the 3/3 a reading: the same harness narrows correctly on a real column and returns nothing on a phantom column in a positive position.
⛔ Scope — stated narrowly, because overstating this would be worse than not filing it
noValueSatisfiesNegationruling (driver-memory's reference matcher still answers $notContains / $nin the pre-ruling way on a no-value row — the #5499 freeze that excused it dissolved 2026-08-11, so the divergence is now unexcused and untracked #13166), ⛔ not measured. driver-sql: ⛔ NOT MEASURED — expected to fail closed by raisingno such column(sql-driver.ts:703maps it), which would make this driver-dependent.current_user.*half. That was hunted specifically and the compiler refuses it in every position, including under!and in a trailing||arm. ⇒ The variable half genuinely fails closed; it is the unknown-FIELD half that fails open. Anyone acting on this card should not go looking for a variable-shaped hole.Why it matters, and why it was invisible
Three separate places in the tree state the opposite consequence, and #16119's own card is one of them:
current_user.*variable, is reported by nothing — both fail CLOSED at runtime #16119: "both fail CLOSED" — the premise the card was gradedp2on, with triage's escalation clause reading "if a fail-OPEN reference error is measured ⇒ p1 +security".⇒ ⭐ The escalation clause fired, but on the half nobody was watching.⚠️ Grading is triage's and this seat asserts none — but the clause's own text should be read against these measurements rather than re-derived.
Re-check
Both return hits on the current tree. Positive control:⚠️ a bounded window, not the whole backlog.
RLS_DENY_FILTERalso matches in the same file, so a zero above would be a broken pattern rather than a removed mechanism. Duplicate check: the 100 most recently created issues carry no card of this shape (control: 2 of them mention RLS, so the scan was not silently empty) —Related
#16119 / PR #17036 (the linter that detects the authoring mistake; its prose is being corrected) · #13166 (the include-direction ruling that makes a missing value satisfy a negation) · #16518 (a reserved
current_userkey the compiler never binds — the adjacent, fail-closed seam)Generated by Claude Code
Generated by Claude Code