test(objectql): pin the $searchFields=__search 400 that four docblocks cite - #8191
Merged
Merged
Conversation
…cks cite
Four docblocks state that a `$searchFields` override naming the hidden
`__search` companion is refused with a 400 ("is hidden") — this suite's own
header, `stripSearchCompanion`'s, and `stripSearchCompanionFromRead`'s twice
(the pre-existing sentence and the #7876 ruling block). No test asserted it.
The behaviour was only reachable by COMPOSING two separately-pinned facts:
`resolveSearchFields` excludes hidden fields, and the ingress gate refuses a
known-but-unsearchable name with 400 INVALID_FIELD (pinned on `estimate`, not
on `__search`). A composition is not a pin.
Since #7876 (ruled 2026-08-12, direction C) the 400 is load-bearing AS A
CONTRAST: the projection door's silence is documented as correct precisely
because the authoring door refuses. Measured both regression directions —
flipping `hidden` off on the provisioned column, and letting hidden names
clear the gate itself — the new case is the ONLY test in the repo that goes
red; the 130 neighbouring gate pins stay green.
Refs #8080
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014C8pAprWdmtecFsEprZax4
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckNo hand-written docs reference the 0 changed package(s). ✅ |
os-zhuang
marked this pull request as ready for review
August 12, 2026 19:37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #8080
Four docblocks in this tree state that a
$searchFieldsoverride naming the hidden__searchcompanion is refused with a 400 ("is hidden"). No test asserted it. This adds the pin — one case, test-only.The gap this closes
The behaviour was real and reachable, but only by composing two separately-pinned facts:
resolveSearchFieldsexcludes hidden fields (packages/spec/src/data/search-fields.ts), pinned bysearch-companion.test.ts;assertSearchFieldsAreSearchablerefuses a known-but-unsearchable name with400 INVALID_FIELD(packages/metadata-protocol/src/protocol.ts), pinned byquery-expression-conformance.test.ts— onestimate, not on__search.A composition is not a pin. Since #7876 (ruled 2026-08-12, direction C) this 400 is load-bearing as a contrast: the projection door's silence is documented as correct precisely because the authoring door refuses. A change letting hidden columns clear the searchability gate would have left all four docblocks false with every suite green.
Does the assertion reach the real gate? Measured, not assumed
The card's own warning was that a pin passing for the wrong reason is worse than no pin. Two independent regression directions were driven, each predicted red before running, each observed red:
hidden: falseon the provisioned companion column (search-companion.ts)hiddenflag itself — the card's exact feared regressionassertSearchFieldsAreSearchable,metadata-protocolrebuiltdist, not some nearer refusalThe second run is the sharper one. Under it
query-expression-conformance.test.tsstayed 130/130 green — itsestimateandidgate pins cannot see a hidden-column regression. The new case was the only thing in the repo that went red, which is the blind spot #8080 describes, demonstrated.The first run also shows the contrast directly: with the gate failing open, the returned record body still had no
__searchkey. The projection door stayed silent while the authoring door let the override through — exactly the pair #7876 ruled on.Inside the test the same guarantee is carried by a control: the same door, the same parameter, a legitimate field name, asserted to resolve. A rejection assertion alone would pass just as happily against a call that never reached the gate.
Placement
The card pointed at
search-companion-read-projection-conformance.test.ts, and that is where it landed — but as a siblingdescribe, not a row inside the existingdescribe.eachmatrix. Two reasons, both in the test's docblock:engine.finddirectly; this refusal lives at the REST ingress and needs a protocol in front of the engine. Adding one to the matrix'sbeforeEachwould rebuild every door row's harness for one case sharing none of their assertions.OS_SEARCH_PINYIN_ENABLED=falsethe column is not in the registry field map, so the gate refuses it as unknown — still a 400, but on the typo tier, not the "is hidden" reason the four docblocks quote. Pinning the cited prose means pinning the declared state.The surrounding matrix is otherwise untouched.
Verification
pnpm --filter @objectstack/objectql test— 191 files, 3391 tests, all passpnpm --filter @objectstack/objectql typecheck— cleanpnpm check:query-options-erasure— ratchet holds, no files addedpnpm check:type-check-debt --re-measure— 33 entries re-measured, none above its recorded number (no baseline raised,--lowernot run)pnpm check:nul-bytes,pnpm check:durability-log-level,pnpm check:engine-double-contract,scripts/check-engine-split-ratio.mjs— all passTest-only, releases nothing ⇒
skip-changeset, not an empty-frontmatter changeset.Generated by Claude Code