Commit 41a3c8d
Fixes #20822
Clause-②: no
#20822 group 4, the card's last group: the comments and docblocks
outside `driver-memory` that still named its retired reference matcher
(`memory-matcher.ts`, retired by commit `8fec76a2b`) as a live surface.
This is the carry group 1's ACCEPT put on the card's last group PR.
Claim: the PM's `Claim:` comment 5948997842 (branch
`claude/issue-20822-retired-matcher-pointers`). Cross-lane declarations:
spec seat post (5949027331) and services seat post (5949038856).
**The seat confirms `Fixes` at ACCEPT.** Hypothesis H1 (the site list is
complete outside `driver-memory`) is falsified: 28 more sites outside
the claim's file surface still name the matcher as live (25 comments and
docblocks, one JSON ledger note, and 2 string literals in code). They
are not edited here. They are listed under "Sites outside the claim's
surface" below, and the route is the open question in the
`os-dev-report` on #20822.
Base `11905a4f8b`; `origin/main` `db0cf2231b` merged once (merge
`ff241ad71a`, no conflict, no file in this diff). Head `ff241ad71a`. Net
diff against `main`: 10 files, +68 / -35. Not governed.
## What changes
Comment and docblock prose only. A sentence that named the matcher as a
live surface now names what carries the semantics today, measured per
site, or says the matcher is retired. Historical sentences stay.
| Site | Reading at base | Action |
|---|---|---|
| spec `filter-logic-conformance.ts:15` | live: the backend table's
"In-memory matcher / `memory-matcher`" row | now "In-memory query path /
`driver-memory` `normalizeFilterCondition`, then mingo", with the
retirement in the same row (H3) |
| spec `filter-comparand-shape.ts:127` | live: "the matcher's own
answers ... are sealed behind this refusal" | past tense, plus the
retirement |
| spec `filter-comparand-shape.ts:142` and `:144` | live: "compares
through JS coercion", "the matcher is not repaired" | past tense, plus
the retirement |
| service-analytics `objectql-strategy.ts:1687` | live:
"`driver-memory`'s matcher ... pin" `{$not: {}}` | now `driver-memory`'s
query path (`memory-driver-document-not.test.ts` pins it) |
| service-analytics `objectql-strategy.ts:2055` (the unlock read it at
`:2014`) | live: `memory-matcher.ts` "does" read `$regex` | past tense,
until `$regex` and then the matcher were retired |
| service-analytics `filter-normalizer-not-null-safe.test.ts:50` | live:
points at the deleted `memory-matcher-not-null-safe.test.ts` | now
`memory-driver-document-not.test.ts`, which holds its cells |
| service-analytics `objectql-contains-canonical-operator.test.ts:31`,
`:103`-`:110`, `:118`, `:305` | live: the mirror evaluates "the way
`memory-matcher.ts` does", and "`driver-memory`'s `$regex` arm is
deliberate and serves a real producer" | past tense; the producer's move
to `$contains` is pointed at in `filter-refusal.ts`. `:118` and `:305`
are in the same file but not in the unlock's list |
| service-storage `attachment-read-visibility.test.ts:13` | live:
"Mirrors `memory-matcher.ts` and `formula`'s `matches-filter.ts`" | now
mirrors `formula`'s `matches-filter.ts`; the matcher is past tense |
| service-storage `attachment-read-visibility.test.ts:326` | live:
points at the deleted `memory-matcher-or-semantics.test.ts` | now
`memory-driver-filter-logic-conformance.test.ts`, which holds its cases
|
| plugin-security `claim-seed-ownership.ts:91` | live, and wrong before
the retirement: the `id IN (...)` scan attributed to `memory-matcher.ts`
| now mingo's `$in`, which `InMemoryDriver` hands the list to (measured
below) |
| formula `matches-filter-not-null-safe.test.ts:17` | live: points at
the deleted `memory-matcher-not-null-safe.test.ts` | now
`memory-driver-document-not.test.ts` |
| formula `matches-filter-not-null-safe.test.ts:120` | live: the matcher
"answers the opposite" | the query path answers the same as this face
(`memory-driver-document-not.test.ts` pins `['1']`); the matcher
answered the opposite until PR #13356 and is retired |
| `docs/design/predicate-compilation-convergence.md:44`, `:56`, `:358` |
census rows anchored at `3711e0b763` | past tense plus the retirement,
as PR #21336 did for the F7 row |
Read and left as they are, because each is already historical or not a
claim about a live matcher: spec `filter-logic-conformance.ts:184`,
`:211` (a measurement table dated by its commits), `:244`, `:480`;
`:492` names `memory-matcher-no-value-negated-operators.test.ts`, which
still exists under that name and holds the live path's cells; `:503` and
`:509` are string literals in the past tense;
`filter-comparand-shape.ts:122`-`:124` (the reason for the 2026-08-31
ruling); formula `matches-filter-icontains.test.ts:91` ("what the
reference matcher was moved onto"); the design doc's `:510` (the D6
decision row) and `:570` (a commit-table row).
## Measurements
**H3, what `driver-memory` evaluates a filter with today.**
`InMemoryDriver.find`, `count`, `updateMany`, `deleteMany` and the
others call `convertToMongoQuery` (`memory-driver.ts:1421`). It runs
`assertFilterConditionShape` (`filter-refusal.ts`), then
`normalizeFilterCondition` (`memory-driver.ts:1600`), and hands the
result to mingo's `Query`.
`memory-driver-filter-logic-conformance.test.ts` runs
`FILTER_LOGIC_CASES` through `InMemoryDriver.find`, and
`check:driver-conformance` holds it. So the spec table's in-memory row
names the query path.
**`claim-seed-ownership.ts`'s `id IN (...)` sentence.**
`normalizeFieldOperators`' `$in` arm (`memory-driver.ts:1862`) passes
`$in` through. mingo 7.2.4's `$in` predicate
(`operators/_predicates.js`) is built once per query and called once per
document; each call runs `intersection([values, list])`
(`util/_internal.js`), which fills a hash map from the whole list. So
the sentence's "linear scan of the id list PER ROW" holds, through
mingo, and the attribution to the matcher was wrong.
**Code-token guard (PR #21357's two readings), base `11905a4f8b` against
the working tree at head, TypeScript 6.0.3.** Reading 1 is the parser's
leaf nodes from a `forEachChild` walk, so comments are trivia and JSDoc
is never visited; a leaf that is not a token is re-scanned with trivia
skipped. Reading 2 is the token stream from a `getChildren` walk, with
JSDoc nodes skipped. Identifiers and string, template and numeric
literals are compared in full.
- Real run over all 8 touched `.ts` files: 26,645 base tokens (reading
2), **0 files with a token change** (exit 0).
- Comment control ("invents no second one" to "invents NO second one",
`objectql-strategy.ts`): 0 files changed (exit 0).
- Positive control, an identifier (`filterNodeToCondition` to
`filterNodeToConditionX`, `objectql-strategy.ts`): DIFFER on both
readings (exit 1).
- Positive control, a string literal (a `FILTER_LOGIC_CASES` `name`
gains an `X`, `filter-logic-conformance.ts`): DIFFER on both readings
(exit 1).
- Positive control, a numeric literal (`MAX_BULK_PER_ROW_HOOK_ROWS / 2`
to `/ 3`, `claim-seed-ownership.ts`): DIFFER on both readings (exit 1).
Each mutation went through `scripts/ablation-replace.mjs` in wrap mode
(anchor 1 to 0). Each restore was proven: blob equal to `HEAD` and `git
diff HEAD` empty.
**`dist` reach (H4), three legs plus a determinism leg.** The five
packages' `dist` files were hashed after each build. Every build exited
0 and ran under the shared verify lock.
All four legs ran at `3ba971f1b6`; the later commits change no file in
the five packages.
- Leg 1: a turbo build of the five packages and their closure (20 tasks,
all five cache misses).
- Leg 2: the 8 changed files of the five packages back at their base
blobs (8 of 8 proven equal), then each package's own `build`.
- Leg 3: the 8 files restored (8 of 8 equal to their `HEAD` blob, `git
diff HEAD` empty), then the same five builds.
- Leg 4: `@objectstack/spec`'s own `build` again. It equals leg 3 in all
230 files, so that build path is deterministic.
| Package | Changed | Added non-test lines found verbatim in `dist` |
Leg 2 against leg 3 | Changeset |
|---|---|---|---|---|
| `@objectstack/spec` | 2 src files | 1 of 8: the table row, in
`data/index.d.ts` and `data/index.d.mts` | 34 files differ:
`data/index.d.ts` / `.d.mts`, 30 source maps (line offsets), 2
build-input hashes | `patch` |
| `@objectstack/service-analytics` | 1 src + 2 test files | 5 of 5, in
`index.js` / `index.cjs` (one also in `index.d.ts` / `index.d.cts`) | 6
of 6 differ | `patch` |
| `@objectstack/plugin-security` | 1 src file | 0 of 4 | only
`index.js.map` and `index.mjs.map` differ: line offsets, because the
docblock grew by two lines; the maps carry no `sourcesContent` | none |
| `@objectstack/formula` | 1 test file | none | 0 differ | none |
| `@objectstack/service-storage` | 1 test file | none | 0 differ | none
|
`.changeset/20822-retired-matcher-pointers.md` therefore declares
`patch` for `@objectstack/spec` and `@objectstack/service-analytics`,
comment text only, with `Clause-②: no`. Each changeset sentence maps to
a diff line: the spec table row at `filter-logic-conformance.ts:15`, and
the two `ObjectQLStrategy` comments at `objectql-strategy.ts:1687` and
`:2055`.
## Gates and tests (head `ff241ad71a`)
- **Derived gates:** `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands` at `ff241ad71a` (10 paths against
merge base `db0cf2231`) derived 89 commands. All 89 ran, each exit code
captured before any pipe. 87 exited 0 on the first run.
`check:dual-build-cjs-loads` and `check:i18n` exited 3 (PREREQUISITE NOT
MET: unbuilt workspace packages), not a measurement. Both exited 0 after
a whole-workspace build (`turbo run build --filter=!@objectstack/docs`,
72 tasks, VERDICT command-exit 0). `--ran` reports "89 derived, 89 run,
0 NOT-MEASURED, 0 UNRUN" and exits 0.
- **Tests, under the verify lock, `vitest run --maxWorkers=2`:**
- spec `--project local`: 598 files, 17,529 passed, 1 todo;
- spec `--project repo`: 48 files, 849 passed;
- formula: 43 files, 1,257 passed;
- service-analytics: 167 files, 3,786 passed, 83 skipped;
- service-storage: 41 files, 629 passed;
- plugin-security: 159 files, 3,479 passed, 23 skipped.
- **Typecheck:** `pnpm --filter ... typecheck` exits 0 for spec (with
`check:scripts-typecheck` and `check:test-typecheck`), formula,
service-analytics, service-storage and plugin-security. Formula,
service-storage and plugin-security also run `check:test-typecheck`, and
service-analytics' `tsc --listFiles` program holds 164 of its
`__tests__` files, both touched ones included.
- **Lint, as a proven narrowing:** `eslint --no-inline-config --format
json` over the 8 touched `.ts` files plus
`service-analytics/dist/index.js` as a control gives 9 results, 0 errors
and 1 warning: the control's ignore notice. None of the 8 is reported
ignored, and each resolves under `--print-config`. `eslint.config.mjs`
never enables type-aware linting (its lines 327-328 say so), so a
comment edit cannot move the verdict on an untouched file. The repo-wide
`pnpm lint` is CI's run.
- **Bytes:** `pnpm check:nul-bytes` exits 0. A control-byte scan over
the 10 changed files finds none.
## Sites outside the claim's surface (round 0; superseded by patch round
1 below)
Read at base `11905a4f8b` with every spelling: `memory-matcher`,
`reference matcher`, `in-memory matcher`, `memory matcher`, `match()`,
the `memory-matcher-*` test-file names, and "`driver-memory`'s matcher".
`driver-memory`, `CHANGELOG.md` and `content/docs/releases/**` are
excluded. Each of these still names the matcher as a live surface:
- `service-analytics` `read-scope-not-null-safe.test.ts:43`: points at
the deleted `memory-matcher-not-null-safe.test.ts`. It is on group 1's
list and inside the ACCEPT's "service-analytics test docblocks", but not
in the unlock's list or the claim.
- `driver-mongodb` `mongodb-filter.ts:1151` ("it is the oracle both
drivers agree with").
- `driver-turso` `remote-transport-boolean-identity.test.ts:43` and
`remote-transport-not-operator.test.ts:40`.
- `formula` `matches-filter.ts:729` (`asciiCaseInsensitiveContains` is
"the same one `driver-memory`'s matcher ... call[s]").
- `objectql`:
- `having-filter.ts:23`, `:26` and `:2064`;
- `having-filter.test.ts:8` and `:60`;
- `number-comparand-declared-type-door.ts:46` ("the memory matcher
compares"; which face it means is ambiguous);
- `validation/record-validator.ts:533` ("five hand-rolled shape tests",
one of them the matcher);
- `tsconfig.test.json:22` and `test-typecheck-debt.json:3` (a JSON
string).
- `plugin-security`:
- `bootstrap-declared-capabilities.test.ts:39` and
`bootstrap-system-capabilities.test.ts:29`;
- `rls-check-stored-form.ts:40`, written after the retirement, so it
probably means the query path.
- `service-analytics` `strategies/filter-normalizer.ts:450` ("the
in-memory matcher ... already held to" the table).
- `spec`:
- `filter.zod.ts:411`, `:940` and `:3111` (live implementation-status
tables), `:1198`, `:1242` (the exported `asciiCaseInsensitiveContains`
docblock) and `:3142` (the `$empty` table);
- `filter-text-conformance.ts:342` ("both then and now");
- `ui/view.zod.ts:605` ("`match()` runs `assertFilterConditionShape`").
- **String literals**, outside this group's form:
- spec `filter.zod.ts:470`, the author-facing refusal for a `null`
ordering comparand. Measured on the published schema door:
`FieldOperatorsSchema.safeParse({ $gt: null })` answers "... its
reference matcher compares through JS coercion ...", in the present
tense.
- spec `filter-operator-vocabulary.test.ts:86`, an assertion message
that prescribes editing the reference matcher.
The governed
`.claude/skills/pm-dispatch/references/compile-surfaces.md:16` stays on
the seat post's protocol observation, as the ACCEPT placed it. 34 more
hits outside the surface are historical (past tense, dated measurements,
or string literals in the past tense). The `os-dev-report` on #20822
lists them.
## Patch round 1 (head `54c8e70e88`)
Section added by the `domain:engine#1` seat, from the dev's patch-round
report (5952834398 on #20822).
- **The seat's answer to round 0's open question:** A, minus the two
string literals (claim amendment 5950842658). The round corrects the 26
comment, docblock and ledger-note sites listed there, under the same
rule.
- `read-scope-not-null-safe.test.ts:43` comes first, in its own commit
`68ca26224f`. It is the site inside group 1's ACCEPT carry that the
seat's unlock had dropped, so **every site that ACCEPT carried is now
corrected, and `Fixes #20822` stands.**
- The added surfaces are declared on the spec (5950854566) and services
(5950863357) seat posts.
- **Not edited:**
- the two string literals `filter.zod.ts:470` (the author-facing
null-ordering refusal) and `filter-operator-vocabulary.test.ts:86` (an
assertion message). They are #21397's (spec lane), so this PR stays
comment-only;
- `filter.zod.ts:3106` ("that driver's matcher", generic staging
reasoning with an ambiguous referent);
- the governed `compile-surfaces.md`.
- **Commits:**
- `1118eebbcd` merges `origin/main` `56238d890d` once, with no conflict.
#21372's hunks moved no listed line;
- then `68ca26224f`, `1bf9b24f26`, `57d675df10`, and `54c8e70e88` (the
changeset).
The net diff against `main` is 28 files, +152/−81, not governed.
- **Measured per site:** each rewritten sentence names what carries the
semantics today, or says commit `8fec76a2b` retired the matcher. The
probes behind the sentences that state a behaviour:
- mingo's string ordering for `filter.zod.ts:411`;
- mingo over the declared-number table for
`number-comparand-declared-type-door.ts:46`;
- `InMemoryDriver`'s null-or-missing match for the two `plugin-security`
bootstrap tests;
- the callers of `asciiCaseInsensitiveContains`.
Historical sentences are untouched.
- **Code-token guard** (both readings, base = merge base `56238d890`, so
it covers the whole PR):
- all 24 touched `.ts` files: **0 files changed**;
- the two JSON files through `ts.parseJsonText`, with
`test-typecheck-debt.json`'s `_note` masked: 0 changed. That `_note` is
the text this round edits by design; an `entries` value control still
DIFFERS under the mask;
- controls (identifier, string, numeric, and JSON value) each DIFFER.
- **`dist` reach** (three legs; the legs agree byte for byte in 276 of
276 files):
| package | rewritten lines in `dist` | entry |
|---|---|---|
| `@objectstack/spec` | 12 of 21: 9 in the filter declaration chunk and
3 in the data bundles; `filter.zod.ts` and `view.zod.ts` also ship as
source | `patch`, extended |
| `@objectstack/formula` | 3 of 3 | `patch`, added |
| `@objectstack/objectql` | 3 of 19 | `patch`, added |
| `@objectstack/service-analytics` | its round-0 entry stands; this
round's line reaches only the source maps | unchanged |
| `driver-mongodb`, `plugin-security` | maps only, or nothing | none |
| `driver-turso` | test files only | none |
- **Tests and typecheck** at `54c8e70e88`:
- the suites of `spec`, `formula`, `objectql`, `driver-turso`,
`driver-mongodb`, `plugin-security` and `service-analytics` are green.
`driver-mongodb`'s real-mongod suites are not measured here: there is no
`mongod`;
- every touched package's typecheck exits 0;
- gates: 95 derived, 95 run, 0 not measured.
## Acceptance notes
- **Build path, not this diff.** Leg 1 (turbo) and leg 3 (each package's
own `build`) are both at the same text. They differ in 14
`@objectstack/spec` declaration files (`api`, `automation`, `contracts`,
`marketplace`, `system` and two `node-executor.zod` chunks, `.d.ts` /
`.d.mts`). Leg 3 equals leg 4 byte for byte, so each path is
deterministic and the rewrite's effect was read on legs 2 and 3, which
share a path. The difference between the paths is not explained here.
- **`main` moved after the merge.** Seven more commits landed after
`db0cf2231b` (to `69a12a0952` when this was written); none touches a
file here. The derivation's only stale input among them is
`scripts/sdui-manifest.record.json`. CI judges the merge ref.
- **Contract review** is owed at tier: the path limb is
`packages/spec/src/**`, non-test. The seat runs it.
---
_Generated by [Claude
Code](https://claude.ai/code/session_017xfMoEjKUuSh2xYB8sCozp)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent fa7b565 commit 41a3c8d
28 files changed
Lines changed: 152 additions & 81 deletions
File tree
- .changeset
- docs/design
- packages
- drivers
- driver-mongodb/src
- driver-turso/src
- formula/src
- objectql
- src
- validation
- plugins/plugin-security/src
- services
- service-analytics/src
- __tests__
- strategies
- service-storage/src
- spec/src
- data
- ui
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
| 44 | + | |
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
56 | | - | |
| 56 | + | |
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
| |||
355 | 355 | | |
356 | 356 | | |
357 | 357 | | |
358 | | - | |
| 358 | + | |
359 | 359 | | |
360 | 360 | | |
361 | 361 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1148 | 1148 | | |
1149 | 1149 | | |
1150 | 1150 | | |
1151 | | - | |
1152 | | - | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
1153 | 1155 | | |
1154 | 1156 | | |
1155 | 1157 | | |
| |||
Lines changed: 5 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
44 | | - | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
45 | 48 | | |
46 | 49 | | |
47 | 50 | | |
| |||
Lines changed: 3 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
41 | 43 | | |
42 | 44 | | |
43 | 45 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
19 | 21 | | |
20 | 22 | | |
21 | 23 | | |
| |||
116 | 118 | | |
117 | 119 | | |
118 | 120 | | |
119 | | - | |
120 | | - | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
121 | 125 | | |
122 | 126 | | |
123 | 127 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
726 | 726 | | |
727 | 727 | | |
728 | 728 | | |
729 | | - | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
730 | 732 | | |
731 | 733 | | |
732 | 734 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
| |||
57 | 58 | | |
58 | 59 | | |
59 | 60 | | |
60 | | - | |
| 61 | + | |
61 | 62 | | |
62 | 63 | | |
63 | 64 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
24 | | - | |
| 23 | + | |
| 24 | + | |
25 | 25 | | |
26 | | - | |
27 | | - | |
| 26 | + | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| |||
2061 | 2061 | | |
2062 | 2062 | | |
2063 | 2063 | | |
2064 | | - | |
| 2064 | + | |
| 2065 | + | |
| 2066 | + | |
2065 | 2067 | | |
2066 | 2068 | | |
2067 | 2069 | | |
| |||
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
47 | | - | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
48 | 49 | | |
49 | 50 | | |
50 | 51 | | |
| |||
0 commit comments