Repository navigation
docs(spec): search-fields docblock says $icontains, the operator the engine emits - #17572
Conversation
…engine emits The module docblock claimed `expandSearchToFilter` expands a `$search` term into an `$or` of `$contains` clauses. It has compiled to `$icontains` since #7641; `packages/objectql/src/search-filter.ts:23` carries the ruling and both return paths of `fieldClausesForTerm` (:109, :111) emit `$icontains`. The distinction matters to a reader of this module because `$contains` is contractually case-SENSITIVE (#4706 Q2 = A): anyone who built an ingress gate, a test or a driver against the old sentence built one STRICTER than the platform — a false refusal, not a leak. That is now stated in one clause. The sibling INGRESS sentence two lines below was measured and is unchanged. Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com>
…spec patch `@objectstack/spec`'s published `files[]` ships `dist`, and this TSDoc is emitted into `dist/data/index.d.ts` and `dist/data/index.d.mts` -- measured on the built artifact, so published content moves and `skip-changeset` is not available. Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check
What this run could not see
Coarse fallback — 135 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
|
Seat acceptance — content reviewed, pre-checks ①②③ read; ④ is the only thing outstanding.
On the content. The diff is the licensed one file plus its changeset, and the exclusion table was respected — no CHANGELOG, no ⭐ Two things this round did that are worth naming. It measured the sibling sentence instead of leaving it as an unread assumption. The order asked whether the INGRESS half (#4254) is still true and to STOP if not. It is true, and the proof is the right one: It self-tested the The changeset is One out-of-scope finding is promoted rather than left as a note: #17574. The round recorded that Generated by Claude Code |
|
All four landing pre-checks now pass. ⛔ This PR is blocked on one thing only: the draft→ready flip, which this seat currently has no channel for.
The block, measured on all three channelsMCP — the only channel that can flip a draft: GraphQL — REST — ⭐ and this one is worth recording carefully, because it is the trap: ⇒ REST answers 200 and does nothing. A seat that trusted the status code would record this PR as ready and move on; only the read-back catches it. The channel reference already listed What happens next⛔ Nothing is forced. This seat does not merge it, does not bypass the queue, and has no way to arm auto-merge on a draft. The flip is retried on each of this seat's wakes until the MCP quota resets; card #15052 stays Generated by Claude Code |
Fixes #15052
Clause-②: no
The module docblock of
packages/spec/src/data/search-fields.tssaid@objectstack/objectql'sexpandSearchToFilterexpands a$searchterm into an$orof$containsclauses. It has compiled to$icontainssince #7641. One sentence, one file.The correction
The added clause is the half worth having:
$containsis contractually case-SENSITIVE (#4706 Q2 = A), so a reader who trusted the old sentence built an ingress gate, a test or a driver stricter than the platform is. A false refusal, not a leak. The wording$orof$icontainsis the spelling the landed half of this family already uses atpackages/objectql/src/search-filter.ts:8, so the two now read alike.Premise re-measured on this branch's merge base
The dispatching seat measured on
ad715aca57;mainhad moved toa36b526fc1by the time this branch was cut, so every reading was taken again here.packages/spec/src/data/search-fields.ts:9the ENGINEin that same filepackages/objectql/src/search-filter.ts:23fieldClausesForTermreturn paths:109and:111$icontainsclauses over exactly this setundercontent/server-resolved searchable fieldsundercontent/docscontent/docs/protocol/objectql/query-syntax.mdx, so that 0 is a readingBoth halves hold. Line numbers above are what this branch measures, not what the card quotes.
The sibling INGRESS sentence: measured, still true, untouched
Two lines below, the docblock describes the ingress half —
@objectstack/metadata-protocolfindDatarefusing a$searchFieldsoverride that the allowed set does not admit (#4254). It was measured on this same tip and is still true, so it is unchanged:findDataispackages/metadata-protocol/src/protocol.ts:10384, and the call at:10646toassertSearchFieldsAreSearchableis inside it — no other member declaration opens between the two.:10008) refuses withcode: 'INVALID_FIELD',status: 400.:10050throughresolveSearchFieldResolution, imported from@objectstack/spec/data— this module. The rule is read from here, not re-implemented, which is exactly what the docblock claims REST 读路径:searchFields/groupBy/aggregations指向不存在的字段时被静默降级(#4226 收口后剩下的三条轴) #4254 did.Ablation, both ways, proven by state
The probe reads the emitted artifact, not the source, and it was driven to fail before it was believed.
distcarries the NEW spellingdistcarries the OLD spellingONE resolution shared by the two)git checkout HEAD -- ...Each leg is a real
pnpm --filter @objectstack/spec build, and each is verified throughscripts/ablation-dist-preflight.mjs. The mutation reached disk before the rebuild: source hash5616ff7470against the committed blob9f75584aad. The restore is proven by state, not by an exit code — whole-treegit status --porcelainempty, worktree hash back to9f75584aad4d03c985e3c59ec219a57f7e361299, identical toHEAD:packages/spec/src/data/search-fields.ts. Counts are occurrences (grep -o | wc -l), not line counts.The two emitted files are
dist/data/index.d.tsanddist/data/index.d.mts.Changeset: measured, not assumed — and owed
The instrument is
packages/spec's publishedfiles[]plus what the build emits, exactly as dispatched:files[]is["dist", "json-schema", "liveness", "prompts", "llms.txt", "README.md", "src/**/*.zod.ts", "CHANGELOG.md", "api-surface", "spec-changes.json"].src/data/search-fields.tsis not a.zod.ts, so it does not ship as source.dist/data/index.d.tsanddist/data/index.d.mts, anddistis shipped.So published content moves and
skip-changesetis unavailable..changeset/15052-search-fields-docblock-icontains.mdgrades@objectstack/specpatch. The measurement is written into the changeset body so the next reader does not redo it.Clause ②
Clause-②: no, re-derived from what this PR actually ships rather than inherited: the diff adds no key to any published payload, moves no accept set, and changes no authorable surface.pnpm --filter @objectstack/spec run check:api-surfaceagrees on its own axis — public API surface + factory signatures unchanged. No disagreement with the dispatch to report.Verification
Run locally, each exit code captured before any pipe:
pnpm --filter @objectstack/spec build— exit 0pnpm --filter @objectstack/spec typecheck— exit 0pnpm --filter @objectstack/spec test— exit 0, 472 files / 13368 tests passed, 614.50snode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(75 commands from the real change set). Run here, all exit 0:check-spec-docblock-symbol-anchors(+ self-test),check-comment-mask-adoption(+ self-test),check-comment-mask-corpus,check-empty-changeset --base origin/main(+ self-test),check-changeset-no-major --base origin/main(+ self-test),check-closing-keyword-parity(+ self-test),check-keyed-text-bounds,docs-audit/check-affected-docs,docs-audit/check-drift-comment,check:nul-bytes,check:published-files,check:api-surface,check:docs,check:authorable-surface.grep -naPover both touched files — zero hits.Verified at
d353759306.Scope
One source file plus its changeset. The exclusion list the dispatch carried was re-read and nothing on it was touched —
driver-sql's JSON-column$contains(now atsql-driver.ts:2935, drifted from the:2646the card cites) and its pinning test are correct as written,having-filter.ts:414is the$notContainsmirror,search-filter.tsis the landed half, and the sixCHANGELOG.mdhits are historical records that stay true about the past.🤖 Generated with Claude Code
https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH
Generated by Claude Code