Repository navigation
Description
Observation only — no user-visible defect measured, nothing blocked. Recorded while working #9228 (PR #9235), which needed the exact membership-spelling set and therefore had to establish this.
What was measured
packages/drivers/driver-memory/src/memory-driver.ts:820 folds four spellings onto $nin:
case 'nin': case 'not_in': case 'notin': case 'not in':not in (space-spelled) is not in the spec's AST vocabulary. AST_OPERATOR_MAP (packages/spec/src/data/filter.zod.ts) declares exactly in, nin, not_in, notin for the membership operators, and VALID_AST_OPERATORS is derived from its keys — so:
isFilterAST(['stage', 'not in', [...]])isfalse, andparseFilterASTnever lowers the spelling;canonicalAstOperator('not in')returns the input unchanged, becauseastOperatorLoweringhas no entry for it;metadata-protocolanswersunrecognised operator "not in"— pinned inpackages/metadata-protocol/src/protocol.malformed-filter.test.ts:128, andprotocol.ts:866carries a comment naming the case explicitly.
So no door lowers a filter into this arm. It is reachable only through the driver-local { field, operator, value } condition-object path (memory-driver.ts:761), where a caller would have to hand the driver an operator string the protocol refuses.
Why it is worth a line
It is a driver accepting a spelling the shared contract rejects — the tolerant-consumer direction Prime Directive #12 rules against, in the mildest possible form (an extra case label). Two ways it can go wrong later: someone reads the switch as evidence that not in is part of the vocabulary (it is what the #9228 dispatch did, from this same arm), or someone adds 'not in' to AST_OPERATOR_MAP to "make the driver's arm reachable", widening the authoring vocabulary for no measured demand.
driver-memory is under the #5499 investment freeze, so this is deliberately filed rather than fixed: deleting a case label from a frozen driver is a decision, not a rider on an unrelated card. driver-sql's 'not in' occurrences are unrelated — those are the SQL keyword, not an authoring spelling.
Suggested disposition when someone picks it up
Either delete the arm (nothing lowers into it, and the three real spellings stay), or, if the condition-object path really does receive it from somewhere, that producer is the thing to find and fix. Whichever way, the answer should come from measuring memory-driver.ts:761's callers, not from the switch.
Activity
os-zhuang commentedon Aug 17, 2026
Triage (first-touch grading): routed
domain:drivers, type Task, and parked directlypm:on-hold— NOT queued — per the standing driver-memory investment freeze (#5499, maintainer 2026-08-05: new cards in the driver-memory / driver-mongodb family are routed by landing point but held referencing the anchor, never queued).The freeze's escalation exception (defects corrupting CI-green correctness) does not apply: the arm is unreachable through every door —
parseFilterASTnever lowersnot in, the protocol refuses it (pinned inprotocol.malformed-filter.test.ts:128) — so no test semantics depend on it. Premise re-verified onorigin/main:memory-driver.ts:820still carries the arm.Restart-when: closed #5499
Hold date: 2026-08-17. When #5499 closes (sqlite
:memory:replacement complete), this card closes with the batch or is re-graded on the then-current tree.Generated by Claude Code