Skip to content

Commit 57d675d

Browse files
committed
wip(group 4 round 1): services- and spec-lane matcher pointers
Claude-Session: https://claude.ai/code/session_017xfMoEjKUuSh2xYB8sCozp Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1bf9b24 commit 57d675d

7 files changed

Lines changed: 33 additions & 21 deletions

File tree

‎packages/plugins/plugin-security/src/bootstrap-declared-capabilities.test.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ function makeQl(declared: any[] = []) {
3636
if (object !== 'sys_capability') return [];
3737
const where = q?.where ?? {};
3838
// [#8470] A `null` comparand is IS NULL, not `=== null`: `driver-sql`
39-
// compiles `{ field: null }` to `IS NULL`, `driver-memory`'s matcher uses
40-
// `value == condition`, and MongoDB matches null-or-missing — none of them
39+
// compiles `{ field: null }` to `IS NULL`, `driver-memory`'s query path
40+
// matches null-or-missing through mingo (its reference matcher, retired by
41+
// commit `8fec76a2b`, used `value == condition`), and MongoDB matches
42+
// null-or-missing — none of them
4143
// is strict equality against an ABSENT key. `bootstrapSystemCapabilities`
4244
// (called by several cases below) scopes its curated lookup with
4345
// `organization_id: null`, which strict `===` would make unsatisfiable

‎packages/plugins/plugin-security/src/bootstrap-system-capabilities.test.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ import { buildExistingByName } from './seed-name-lookup.js';
2626
* unrelated to ownership. Insertion order is what the double used to model,
2727
* and it models nothing.
2828
* 2. **A `null` comparand matches a null OR absent value.** `driver-sql`
29-
* compiles `{ field: null }` to `IS NULL`; `driver-memory`'s matcher uses
30-
* `value == condition`; MongoDB matches null-or-missing. Strict `===`, which
29+
* compiles `{ field: null }` to `IS NULL`; `driver-memory`'s query path
30+
* matches null-or-missing through mingo (its reference matcher, retired by
31+
* commit `8fec76a2b`, used `value == condition`); MongoDB matches
32+
* null-or-missing. Strict `===`, which
3133
* this double used, matches NONE of them and would have made
3234
* `organization_id: null` unsatisfiable here while working in production.
3335
* 4. **`$in` membership**, because the real engine has it (`security-plugin.ts`

‎packages/plugins/plugin-security/src/rls-check-stored-form.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* - every comparand of the value comparisons on that column (`$eq`, `$ne`, the
3838
* four orderings, `$in`, `$nin`, `$between`, and implicit equality), because
3939
* the read compares the stored value against the comparand in that form
40-
* (`driver-sql`'s `coerceFilterValue`, `driver-memory`'s matcher, objectql's
40+
* (`driver-sql`'s `coerceFilterValue`, `driver-memory`'s query path, objectql's
4141
* `having` walker all pair the two). Putting only the image into the form
4242
* would refuse a write the read shows whenever a policy spells its comparand
4343
* another way: `record.start_time == '09:00'` against a stored `'09:00:00'`.

‎packages/services/service-analytics/src/strategies/filter-normalizer.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,9 @@
447447
* Row-result cover: `filter-operator-coverage.test.ts` for the operator
448448
* vocabulary, `native-sql-filter-logic-conformance.test.ts`, which runs the
449449
* SHARED combinator table (`FILTER_LOGIC_CASES`, #3774) that the SQL compiler,
450-
* the in-memory matcher, `formula` and `read-scope-sql` are already held to,
450+
* `driver-memory`'s query path (its in-memory reference matcher, which ran the
451+
* table too, was retired by commit `8fec76a2b`), `formula` and `read-scope-sql`
452+
* are already held to,
451453
* `filter-normalizer-not-null-safe.test.ts` for the two squares that table
452454
* deliberately does not carry (NULL handling, boolean identities),
453455
* `filter-array-lowering.test.ts` for the array door (#5334),

‎packages/spec/src/data/filter-text-conformance.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,9 @@ export const FILTER_TEXT_CASES: readonly FilterTextCase[] = [
339339
// `$regex` and that driver answers them too. #6682\'s second half then took
340340
// the same flag off driver-memory\'s query path and off the rule its analytics
341341
// face borrows, which was the last folding face on the platform. (`formula`
342-
// and driver-memory\'s reference matcher measured case-exact both then and
343-
// now — they are what the other faces were moved onto.)
342+
// measured case-exact both then and now, and driver-memory\'s reference
343+
// matcher did until commit `8fec76a2b` retired it — they are what the other
344+
// faces were moved onto.)
344345
{
345346
name: '$contains is case-SENSITIVE — a lower-case comparand misses the upper-case row',
346347
filter: { name: { $contains: 'acme' } },

‎packages/spec/src/data/filter.zod.ts‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,10 @@ const ORDERING_COMPARAND_DESCRIPTION =
407407
* one form the platform's own date-macro path can never hand them. This is the
408408
* declaration aligning to a contract the rest of the stack already keeps, not
409409
* a new capability: every evaluation surface ALREADY compares strings
410-
* (`driver-sql` binds `>`/`>=`/`<`/`<=`, `formula`'s `matchesFilter` and
411-
* `driver-memory`'s matcher fall through to the JS operators).
410+
* (`driver-sql` binds `>`/`>=`/`<`/`<=`, `formula`'s `matchesFilter` falls
411+
* through to the JS operators, and `driver-memory`'s query path hands the
412+
* comparison to mingo, which orders strings; its reference matcher, retired by
413+
* commit `8fec76a2b`, fell through to the JS operators).
412414
*
413415
* ## Why a BARE string, and not an ISO-shaped refinement (#5685 rider ①)
414416
*
@@ -937,7 +939,7 @@ export const RangeOperatorSchema = lazySchema(() => z.object({
937939
* | `driver-sql` | ANSWERS both rows | its own `case '$icontains'`, folding through the same emitter that carries the escaping |
938940
* | `driver-sqlite-wasm` | ANSWERS both rows | INHERITED — `SqliteWasmDriver extends SqlDriver`; this package carries no text case arm of its own, on a different ENGINE |
939941
* | `driver-turso` | ANSWERS both rows, on BOTH transports | local inherits `SqlDriver`; the remote transport compiles independently and has its own arm |
940-
* | `driver-memory` — query path, reference matcher, analytics face | ANSWERS both rows | #6520; the pattern faces take {@link asciiCaseInsensitiveRegexSource}, the matcher {@link asciiCaseInsensitiveContains} |
942+
* | `driver-memory` — query path, analytics face | ANSWERS both rows | #6520; both take {@link asciiCaseInsensitiveRegexSource} (its reference matcher took {@link asciiCaseInsensitiveContains} until commit `8fec76a2b` retired it) |
941943
* | `driver-mongodb` | ANSWERS both rows | #6520; an ASCII-only `$regex`, never `$options: 'i'` |
942944
* | objectql `having` | ANSWERS both rows | #6520; {@link asciiCaseInsensitiveContains} over the aggregated row |
943945
* | `formula` `matchesFilterCondition` | ANSWERS both rows | #6520; the same helper, on the RLS write-side `check` |
@@ -1194,16 +1196,17 @@ const ASCII_CASE_DELTA = 0x20; // 'a' - 'A'
11941196
*
11951197
* ## Why this is in the spec and not four times in four packages
11961198
*
1197-
* `$icontains` has six JS evaluation faces (`driver-memory`'s query path,
1198-
* reference matcher and analytics face, `driver-mongodb`, objectql's `having`,
1199-
* `@objectstack/formula`'s `matchesFilterCondition`) plus three SQL compilers in
1199+
* `$icontains` has five JS evaluation faces (`driver-memory`'s query path and
1200+
* analytics face, `driver-mongodb`, objectql's `having`,
1201+
* `@objectstack/formula`'s `matchesFilterCondition`; a sixth, `driver-memory`'s
1202+
* reference matcher, was retired by commit `8fec76a2b`) plus three SQL compilers in
12001203
* `service-analytics`. Every one of them needs the same fold, and this repo has
12011204
* already measured what happens when such a rule is written out per package:
12021205
* *"a list written out here would agree with the spec on the day it was typed
12031206
* and never again"* (`driver-memory/src/filter-refusal.ts`, on the operator
12041207
* vocabulary) — the #3948 shape, reached through the fold instead of the word
12051208
* list. One definition means a fold that is wrong is wrong everywhere at once,
1206-
* which is the only way six faces can be held to one answer.
1209+
* which is the only way these faces can be held to one answer.
12071210
*
12081211
* ## Why not `toLowerCase()`
12091212
*
@@ -1239,7 +1242,8 @@ export function foldAsciiCase(value: string): string {
12391242
* [#6520] Does `haystack` contain `needle`, ignoring ASCII case only?
12401243
*
12411244
* The `$icontains` predicate for every face that can compare two JS strings
1242-
* directly — the reference matcher, objectql's `having`, `formula`. The fold
1245+
* directly — objectql's `having` and `formula` (and `driver-memory`'s reference
1246+
* matcher until commit `8fec76a2b` retired it). The fold
12431247
* runs on BOTH sides, which is the half that is easy to get wrong: folding only
12441248
* the comparand compares a folded needle against a raw haystack and matches just
12451249
* the rows that were already lower-case. `FILTER_TEXT_CASES`' first row (an
@@ -3108,7 +3112,7 @@ export const FilterArraySchema: z.ZodType<FilterArray, FilterArray> = z.lazy(()
31083112
* |---|---|
31093113
* | `driver-sql` (and `driver-sqlite-wasm`, which inherits its compiler) | ANSWERS — `LIKE` / `GLOB` per dialect, caller-bound wildcards |
31103114
* | `driver-turso` — local (inherits `SqlDriver`) and remote (its own compiler) | ANSWERS on both transports |
3111-
* | `driver-memory` — query path and reference matcher | ANSWERS — it widens its own `SUPPORTED_FIELD_OPERATORS` by hand, the way `driver-turso`'s remote transport has carried `$icontains` since #5702. It is the in-memory DOUBLE: an app whose tests run there and whose production runs SQL must not get a 400 for a filter that works |
3115+
* | `driver-memory` — query path (its reference matcher answered too until commit `8fec76a2b` retired it) | ANSWERS — it widens its own `SUPPORTED_FIELD_OPERATORS` by hand, the way `driver-turso`'s remote transport has carried `$icontains` since #5702. It is the in-memory DOUBLE: an app whose tests run there and whose production runs SQL must not get a 400 for a filter that works |
31123116
* | `@objectstack/formula` `matchesFilterCondition` | ANSWERS — {@link matchesLikePattern}, so a write-side `check` agrees with the read-side SQL |
31133117
* | `driver-mongodb`, `objectql` `having`, `service-analytics` | REFUSE, loudly, in the ADR-0112 `INVALID_FILTER` envelope — they derive acceptance from THIS array, which does not name the operator |
31143118
*
@@ -3139,7 +3143,7 @@ export const FilterArraySchema: z.ZodType<FilterArray, FilterArray> = z.lazy(()
31393143
* | `driver-turso` remote transport | the declared row, through the resolver `TursoDriver` wires |
31403144
* | `driver-memory` query path, `driver-mongodb` | the declared row, from `syncSchema` |
31413145
* | `service-analytics` — `where` and read-scope SQL | the declared row, from the host's `sourceFieldMeta` |
3142-
* | `driver-memory` reference matcher, objectql `having`, `@objectstack/formula` `matchesFilterCondition` | by VALUE — null, `''` and `[]` are empty (they hold no declarations) |
3146+
* | objectql `having`, `@objectstack/formula` `matchesFilterCondition` (and `driver-memory`'s reference matcher until commit `8fec76a2b` retired it) | by VALUE — null, `''` and `[]` are empty (they hold no declarations) |
31433147
* | `driver-memory` analytics (cube) face | REFUSES — `INVALID_FILTER` / 400, as it refuses `$null` |
31443148
*
31453149
* A declared-row face asked about a column it holds NO declaration for refuses

‎packages/spec/src/ui/view.zod.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -602,9 +602,10 @@ const VIEW_FILTER_TEXT_COMPARAND_OPERATOR = 'icontains' satisfies ViewFilterOper
602602
* `false` (an array is none of the six accepted comparand types —
603603
* `isAcceptedFilterComparand`, `filter-comparand-type.ts`), and the comparand
604604
* is refused with the withheld `INVALID_FILTER` / 400 envelope.
605-
* - **`driver-memory` REFUSES** the same shape in the same envelope — `match()`
606-
* runs `assertFilterConditionShape`, whose implicit-equality arm throws on an
607-
* array (`filter-refusal.ts`). That refusal first shipped in
605+
* - **`driver-memory` REFUSES** the same shape in the same envelope — its query
606+
* path's `convertToMongoQuery` runs `assertFilterConditionShape`, whose
607+
* implicit-equality arm throws on an array (`filter-refusal.ts`); the reference
608+
* matcher's `match()` ran it too until commit `8fec76a2b` retired the matcher. That refusal first shipped in
608609
* `@objectstack/driver-memory@17.4.0`; published 17.3.0 returned the row
609610
* stored as `['a']` (run in this change's review; which other rows it
610611
* selected is NOT MEASURED).

0 commit comments

Comments
 (0)