Uh oh!
There was an error while loading. Please reload this page.
fix(metadata-protocol): route searchAll through the engine's $search expansion so the ⌘K palette recalls what the executor recalls - #8787
Conversation
…rchall-companion-recall
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also reference the affected code. These are read-only:
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#7643
What was wrong
searchAll(which servesGET /api/v1/search) resolved its own searchable set and compiled its own AND-of-OR, instead of going through the engine's ADR-0061$searchexpansion that servesPOST /api/v1/data/:object/query {search}. Two producers, and the palette's was a strict subset of the executor's.Re-measured on current
mainbefore implementing — the card confirmed this at76d74ecbandmainhas moved a long way since. The premise holds, but every line number in the card is stale:searchAllis now atprotocol.ts:8520-8700, not~7177-7411.Mechanism — one producer, not two callers of one helper
The dispatch assumed routing
searchAllthroughresolveSearchFields/expandSearchToFilter. Half of that is impossible and the other half turned out to be the weaker form:expandSearchToFilterlives in@objectstack/objectql, which depends on@objectstack/metadata-protocol. Importing it would close a package cycle.searchAllhandsengine.findthe query TEXT (search: q, a declaredfindoption) per object and the engine expands it. That leaves one producer of search clauses rather than two agreeing by maintenance.No per-object assumption blocked this. The concern that a cross-object sweep could not satisfy a per-object helper does not arise: the sweep was already a loop of per-object
engine.findcalls, so the per-object expansion fits exactly where the old per-object filter sat. Only the cross-object half stays local (which objects are swept, caps, ranking, title/snippet).resolveSearchFieldResolution(from@objectstack/spec/data, already imported here for the #4254 ingress gate) is still consulted — but for the skip guard and the snippet source fields, not to build a filter.What a caller observes changing
Three widenings and one narrowing, all detailed in the changeset:
hnkj/huaningkejinow return the CJK row thatPOST /data/showcase_account/query {search}already returned.searchableFields, else the auto-default — not the field-levelsearchable: trueflag, which$searchhas never read.searchableFields' own spec description already named global search as one of its three consumers; this makes that true.formulafields are excluded.id— so every keystroke ran{id: {$icontains: term}}against system/junction/log tables. That is $search 自动字段集:nameField/name/title 被无条件前置,绕过 SEARCH_AUTO_EXCLUDED_FIELDS——搜索会打到主键 #4483's defect, which the executor had fixed and this path had not. Such objects are now skipped.Unchanged: object sweep and opt-outs, caps, ordering, RLS/RBAC, response shape. The
$searchexecutor path is untouched — pinned, not merely asserted (below).Folding in #7850 rows 2-3
Row 3 (
"case-insensitive substring matching via $contains") was already corrected onmainby #7641's landing — the card's own root-cause paragraph naming it as stale is itself now stale. Row 2 ("case-insensitive LIKE") was still present and is corrected here:LIKEnames no operator in this vocabulary and, since #6518's LIKE→GLOB change, not even the SQL the compilers emit.Left alone as instructed: #7850 row 1 (
search-conformance.ledger.ts:23, spec seat — #7850 stays open for it) andobjectql/src/search-filter.ts:18, which is correct as a declaration under #4706 Q2 = A.Verification
Union re-run after the final commit, at
663d95e1b.New suite
packages/objectql/src/global-search-palette-recall.test.ts(13 cases) — it lives inobjectqlbecause that is the only package where both real implementations meet. The load-bearing assertion is parity, not "the palette finds pinyin": a palette widened by narrowing the executor would satisfy the latter and is a failure. Each probe compares both paths against each other AND against a written expectation, and the per-object filter both paths hand the driver is compared tree-to-tree.Reverse verification, direction predicted before running: revert
protocol.ts, rebuild, expect 5 red / 8 green. Measured 6 red / 7 green — the extra red was theid-scan finding above, which is how that fourth axis was found. The first ablation attempt came back all-green and was invalid: this suite resolves@objectstack/metadata-protocolthrough its builtdist/, so the ablation only bites after a rebuild. Both legs were re-run withscripts/ablation-dist-preflight.mjsproving the mutation reached the artifact (--absenton the way out, present on the way back), and the restore was byte-identical (git statusclean against the commit).@objectstack/metadata-protocol— 90 files / 1352 tests pass@objectstack/objectql— 207 files / 3642 tests pass@objectstack/rest— 116 files / 1921 tests pass ·@objectstack/runtime— 157 files / 2391 tests pass (downstream consumers, prefix filter)scripts/pm/dispatch-gates.mjsagainst the real changed files: all 13 derived families pass, pluscheck:nul-bytescheck:type-check-debt --re-measure(the ratchet) initially caught a +1 in my own new test —Array.prototype.atis outside this package's tsclib. Fixed rather than raised; ledger flat at 1968, none above recordedorigin/mainmerged immediately before opening. Stayed clear of PR #8770's regions (canonicalizeMetaRequestTypeat:211, its call sites, thesaveMetaItemdoor) — no conflict.Out of scope, filed not fixed
#8786 —
renderTitlein this same function reads only the deprecateddisplayNameField, never the canonicalnameField, andprovisionPrimarystamps only the latter. Titling, not recall; left alone deliberately.Generated by Claude Code