Skip to content

Commit 43cbe14

Browse files
os-billclaude
andauthored
docs(spec): state what the $search expansion actually emits (#17740)
Fixes #17574 ## What the sentence claimed, and what the engine emits `packages/spec/src/data/search-fields.ts`'s module docblock — the ENGINE bullet — told the reader that `expandSearchToFilter` expands a `$search` term into a `$or` of `$icontains` clauses **"over exactly this set"**. Re-measured on this branch's base (`431c757120`), both halves the card names hold: | claim | measurement on the base | |:--|:--| | the `$or` is closed over the resolved set | false — `search-filter.ts:148` pushes a clause on `SEARCH_COMPANION_FIELD` (`__search`), and `search-companion.ts` declares that column `hidden` + `system` + `searchable: false`, so `resolveSearchFields` never returns it and no `$searchFields` override can name it | | every clause is `$icontains` | false — that one pushed clause is `$contains` (8 `$icontains` occurrences in the engine file, 6 bare `$contains`) | The operator split is **deliberate**, not drift. `packages/objectql/src/search-filter.ts` carries an explicit instruction at the site: `Do not "align" the two.` The docblock now quotes it verbatim, so the next reader does not "repair" a case-sensitive operator that is exact by construction (the companion is already lowercase on both sides). ## What changed One comment. `packages/spec/src/data/search-fields.ts`: - `"over exactly this set"` becomes `"over this set"` — the totality claim goes; - a following sentence states that the `$or` is **not** closed over the set and its clauses are **not** all `$icontains`, names the deployment-gated `__search` companion as the extra clause, and explains why that clause is `$contains` **by design**, citing the engine's own fence. ⛔ No behaviour change. `packages/objectql/src/search-filter.ts` is untouched — it is evidence, not subject. The engine, the companion column and the operator split are all correct. - **Clause-②: no** — this PR puts no new key on any published payload. ## Verification All commands run in a dedicated worktree at head `2023a06165`; heavy runs serialised through `scripts/pm/os-verify-lock.sh`. | check | result | |:--|:--| | `pnpm --filter @objectstack/spec build` | `VERDICT command-exit 0` | | `pnpm --filter @objectstack/spec typecheck && … test` | `VERDICT command-exit 0` — 473 test files, 13435 tests passed | | `pnpm --filter @objectstack/spec check:generated` | exit 0 — all 15 generated artifacts up to date (the module docblock is not extracted into `content/docs/references/`, so `check:docs` stays green) | | `pnpm exec eslint . --no-inline-config --format json` | exit 0 — **full population, no narrowing**: 6636 files linted, 0 errors, 0 warnings, read at head `2023a06165` | | derived gate families (`scripts/pm/dispatch-gates.mjs`) | 75 derived, **74 measured green**, 1 NOT MEASURED | | `pnpm check:nul-bytes` + a control-character self-scan of the touched file | exit 0 / no hits | `dispatch-gates --ran` reconciles 75 derived against 75 recorded with their exit codes. Three first exited `3` (each gate's own **PREREQUISITE NOT MET — nothing measured** code, not a finding); building `@objectstack/formula`, `@objectstack/lint` and `@objectstack/objectql` turned two of them into real green measurements (`check:doc-formula-expressions`, `check:lean-entry-closure`). The remaining one, `check:dual-build-cjs-loads`, needs ~87 packages built — a whole-farm build, **declared to CI** rather than run here. Every zero above was taken with a lit control in the same command shape. The one that mattered: flattening the docblock to match the sentence across line breaks needs the block-comment leader `*` stripped first, and the phrase carries backticks — a control written without them read `0` against a file that plainly contains the phrase, so the instrument was corrected before any conclusion was drawn. ## 验收备注 Neither item below is filed; each is classified against the three filing classes with its successor named. 1. **The enum-label `$in` path is a third operator in the same `$or`, and it stays an open question.** Measured, not assumed: `fieldClausesForTerm` (`search-filter.ts:102-108`) returns `[{ [field]: { $in: values } }]` when a `select` option label matches, so the expansion also carries clauses that are neither `$icontains` nor `$contains`. This is **not filed** — the card declares the exhaustiveness of this docblock family an OPEN question, ⛔ not a decided one, and the wording here deliberately does not close it: the totality claim is gone and the new sentence says only that the clauses are *not all* `$icontains`, which is true whether or not the family should eventually enumerate `$in`. Successor: the open question returned to the PM with this round's report. 2. **Changeset filename convention.** This PR's changeset is `issue-17574-search-fields-docblock.md`, the issue-scoped name the dispatch mandated. The 20+ existing entries in `.changeset/` spell it `NNNNN-slug.md` (the bare card number, then the slug) with no `issue-` prefix. Not one of the three filing classes (no defect, no contract violated, no metadata trap) and no gate reads changeset filenames — searched `scripts/` and `.github/workflows/`; `check-changeset-fixed.mjs` and `check-changeset-no-major.mjs` read package names and bump levels, never the filename. Successor: the PM, which owns this naming rule. --- _Generated by [Claude Code](https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent e9efc40 commit 43cbe14

2 files changed

Lines changed: 22 additions & 2 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
Correct the `search-fields.ts` module docblock's ENGINE bullet: the `$search` expansion is not closed over the resolved set, and its clauses are not all `$icontains`.
6+
7+
The bullet claimed `expandSearchToFilter` expands a `$search` term into a `$or` of `$icontains` clauses "over exactly this set". Since the pinyin-recall companion column landed, an object whose deployment provisioned the hidden `__search` companion gets one additional clause per latin term on that companion — a field `resolveSearchFields` never returns and no `$searchFields` override can name, so it sits outside the set the sentence called exact. That one clause is `$contains`, deliberately: the companion is already lowercase on both sides, so a case-sensitive operator over two folded values is exact rather than a case bug, and the engine carries an explicit instruction at the site not to align the two operators. The docblock now states both facts and cites that instruction, so a reader does not "repair" the deliberate split.
8+
9+
Documentation only — no behaviour, schema or exported surface changes.

‎packages/spec/src/data/search-fields.ts‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,21 @@
66
* ONE resolution shared by the two layers that must agree on it:
77
*
88
* - the ENGINE (`@objectstack/objectql` `expandSearchToFilter`), which expands
9-
* a `$search` term into a `$or` of `$icontains` clauses over exactly this set
9+
* a `$search` term into a `$or` of `$icontains` clauses over this set
1010
* — `$icontains` since #7641, NOT `$contains`, which is contractually
1111
* case-SENSITIVE (#4706 Q2 = A): a gate, test or driver written to the old
12-
* sentence is STRICTER than the platform — a false refusal, not a leak;
12+
* sentence is STRICTER than the platform — a false refusal, not a leak.
13+
* ⛔ That `$or` is NOT closed over this set, and its clauses are NOT all
14+
* `$icontains`. Since #2486, when the deployment provisioned the hidden
15+
* `__search` companion column, each latin term ORs one ADDITIONAL clause on
16+
* that companion — a field `resolveSearchFields` never returns and no
17+
* `$searchFields` override can name, so it is outside this set by
18+
* construction. That one clause is `$contains` BY DESIGN: the companion is
19+
* already lowercase on BOTH sides (the column by construction, the term by
20+
* `.toLowerCase()`), so a case-SENSITIVE operator over two folded values is
21+
* exact, not a case bug. The engine says so at the site
22+
* (`objectql/src/search-filter.ts`): `Do not "align" the two.` ⛔ So do not
23+
* reconcile the two operators — not here, not there;
1324
* - the INGRESS gate (`@objectstack/metadata-protocol` `findData`), which
1425
* refuses a `$searchFields` override naming a field this set does not admit
1526
* (#4254), instead of letting the engine drop it silently.

0 commit comments

Comments
 (0)