Repository navigation
Commit 35f2055
fix(spec)!: engine-side searchFields declarations refuse an empty list, as FullTextSearchSchema.fields does (#28154)
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoDByYUjCh5NqsyFHj21fAy6)_
Fixes #28059
Clause-②: no (narrowing)
Metadata-protocol: none
## 维护者速读
- 改了什么:引擎侧三处 `searchFields`
声明(`EngineQueryOptionsSchema`、`EngineAggregateOptionsSchema`、`EngineCountOptionsSchema`)改用共享的搜索字段数组规则,空数组
`[]` 被拒收,并带上与 `QuerySchema.searchFields` 相同的说明文字。
- 为什么改:同一个 schema 上 `search: { fields: [] }` 已被拒收,`searchFields: []`
却被接受,而 Data API 入口和引擎(#27732 进行中)都拒收它;按发布的类型或 JSON Schema 写代码的嵌入方和 AI
会被误导。
- 风险与回滚:只收窄声明,TypeScript 类型不变(仍是 `string[] | undefined`);引擎运行时不用这三个
schema 解析选项,所以直接调用引擎的行为本 PR 不变。回滚即 revert 本 PR。
-
先看:`packages/spec/src/data/data-engine.zod.ts`(三处声明)、`packages/spec/src/data/search-fields-names-a-field.test.ts`(原「仍接受空数组」的阶段边界测试翻转为拒收测试)、`.changeset/28059-engine-search-fields-names-a-field.md`(BREAKING
说明与 ADR-0087 处置)。
- 两分钟验证:`pnpm --filter @objectstack/spec exec vitest run
src/data/search-fields-names-a-field.test.ts`,预期全部通过,其中包括
“EngineQueryOptionsSchema.searchFields refuses an empty list with the
accept-set sentence”。
- 需要你做的:无。席内契约复审 PASS(评论 6525975157),由席位落地。
## What changes
- `EngineQueryOptionsSchema.searchFields`,
`EngineAggregateOptionsSchema.searchFields` and
`EngineCountOptionsSchema.searchFields` change from
`z.array(z.string()).optional()` to `searchFieldsArray().optional()`,
the array arm `QuerySchema.searchFields` and
`FullTextSearchSchema.fields` already use
(`./search-fields-names-a-field.ts`, imported by this file already). An
empty list is refused at `searchFields` with the shared sentence. A list
with a blank member is still admitted, as the shared arm admits it. One
accept set, no fresh `.min(1)`.
- Each of the three now carries a `.describe()` ending in the shared
`SEARCH_FIELDS_ACCEPT_SET`, so the published JSON Schema and the
reference docs state the rule.
`content/docs/references/data/data-engine.mdx` is regenerated (3 lines).
- The module docblock of `search-fields-names-a-field.ts` drops "the
engine-side declarations do not take it yet".
- Changeset `28059-engine-search-fields-names-a-field.md`:
`@objectstack/spec` patch (`Metadata-protocol: none`), `fix(spec)!`,
both declaration lines, ADR-0087 disposition `not-required
(no-migration-prescription)`, and a "Supersedes" note for the unreleased
#27683 entry's bullet that said these declarations still admit `[]`.
**Engine behaviour on `main`.** The in-process engine does not parse its
options with these schemas, but since #28108 (`6a648ac2`, #27732, merged
before this PR and shipping in the same release) it refuses
`searchFields: []` and `search.fields: []` itself with `400
VALIDATION_ERROR` before any driver read. This branch's merge base
predates that commit, so on this branch's own tree the engine still
reads `[]` as absent; after the merge the declaration, the Data API
doors and the engine refuse the same value. (Seat correction: the
earlier sentence said the engine refusal was still in flight.)
## Tests
`packages/spec/src/data/search-fields-names-a-field.test.ts`:
- The stage-boundary block "the engine-side searchFields declarations
are the next stage" (which asserted `[]` is still admitted) is replaced
by "the engine-side searchFields declarations":
- `%s.searchFields refuses an empty list with the accept-set sentence`,
for each of the three schemas: `success: false`, issue `path` equal to
`['searchFields']`, message equal to `SEARCH_FIELDS_NAMES_NO_FIELD`.
- `%s.searchFields answers [] as its structured search.fields does`: the
bare and structured spellings on the same schema give the same message.
- `keeps %s unchanged` (one name, two names, a blank member) and `still
admits no searchFields at all`, for each schema.
- "the declarations state the accept set they enforce" gains the three
engine members.
<details><summary>Ablation: removing the narrowing turns the new refusal
cases red</summary>
On committed head `fca20448`, all three declarations were reverted to
`z.array(z.string()).optional()` (3 anchors replaced, 0 fixed spellings
left, counted with `grep -c`). `vitest run
src/data/search-fields-names-a-field.test.ts`: 6 failed | 51 passed
(57), exactly the 3 refusal and 3 same-answer cases. The file was
restored with `git checkout HEAD --`, and `git diff HEAD` was empty. The
describe-sentence cases stayed green because the mutation kept the
`.describe()`.
</details>
<details><summary>Local runs</summary>
- `pnpm --filter @objectstack/spec typecheck`: exit 0. `pnpm --filter
@objectstack/spec exec vitest run` on `c4560f09`: Test Files 843 passed
(843), Tests 23976 passed, 1 todo.
- `pnpm --filter @objectstack/spec check:generated`: 1 of 14 stale
(`content/docs/references/**`) before `--fix`; after `--fix` up to date.
`check:api-surface` was not stale: the types did not change.
- Full dogfood (owed by the `(narrowing)` arm), `pnpm --filter
@objectstack/dogfood test` under the verify lock on `c4560f09`: lock
VERDICT command-exit 0; Test Files 358 passed | 3 skipped (361), Tests
2883 passed | 20 skipped (2903).
</details>
## Acceptance notes
- The claim writes `Clause-②: no`. The order and triage `6522171038`
write `no (narrowing)`, and this is a narrowing, so this body and the
changeset carry `no (narrowing)`.
- A whitespace-only or blank member (`['']`) is still admitted by all
three declarations, as by `QuerySchema.searchFields`. The doors refuse a
blank member as an unknown field. This PR leaves that alone, as #27683
did.
- No in-repo caller parses an engine option bag holding `searchFields:
[]` with these schemas (`git grep` of `searchFields: []` outside the
spec test: only door-level tests in rest and objectql, which go through
`findData`, not these schemas).
## Verification
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 104 commands. All 104 ran with stdin
from /dev/null, exit codes captured before any pipe: 104 exited 0. 7
first refused with exit 3 (PREREQUISITE NOT MET: no workspace build, and
one self-test needing pinned commit `621a4876`); after the package build
and fetching that commit, all 7 exited 0.
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--ran FILE`: "104 derived famil(ies) accounted for — 104 run, 0
NOT-MEASURED".
- The gate sweep was taken on `d38c42e6`; the merge with `origin/main`
(`c4560f09`) brought in 9 commits, none touching `packages/spec`.
- CI on this PR: not yet read; the seat reads the check-runs.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L9qibybNsmrKsxbKJHwo36)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 139bc18 commit 35f2055
5 files changed
Lines changed: 78 additions & 19 deletions
File tree
- .changeset
- content/docs/references/data
- packages/spec/src/data
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
486 | 486 | | |
487 | 487 | | |
488 | 488 | | |
489 | | - | |
| 489 | + | |
490 | 490 | | |
491 | 491 | | |
492 | 492 | | |
| |||
571 | 571 | | |
572 | 572 | | |
573 | 573 | | |
574 | | - | |
| 574 | + | |
575 | 575 | | |
576 | 576 | | |
577 | 577 | | |
| |||
697 | 697 | | |
698 | 698 | | |
699 | 699 | | |
700 | | - | |
| 700 | + | |
701 | 701 | | |
702 | 702 | | |
703 | 703 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
185 | 185 | | |
186 | 186 | | |
187 | 187 | | |
188 | | - | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
189 | 192 | | |
190 | | - | |
| 193 | + | |
| 194 | + | |
191 | 195 | | |
192 | 196 | | |
193 | 197 | | |
| |||
509 | 513 | | |
510 | 514 | | |
511 | 515 | | |
512 | | - | |
| 516 | + | |
| 517 | + | |
513 | 518 | | |
514 | | - | |
| 519 | + | |
| 520 | + | |
515 | 521 | | |
516 | 522 | | |
517 | 523 | | |
| |||
554 | 560 | | |
555 | 561 | | |
556 | 562 | | |
557 | | - | |
| 563 | + | |
| 564 | + | |
558 | 565 | | |
559 | | - | |
| 566 | + | |
| 567 | + | |
560 | 568 | | |
561 | 569 | | |
562 | 570 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
7 | 9 | | |
8 | 10 | | |
9 | 11 | | |
| |||
133 | 135 | | |
134 | 136 | | |
135 | 137 | | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
136 | 141 | | |
137 | 142 | | |
138 | 143 | | |
139 | 144 | | |
140 | 145 | | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
145 | 153 | | |
146 | 154 | | |
147 | 155 | | |
148 | | - | |
149 | | - | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
150 | 180 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
31 | | - | |
32 | | - | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| |||
0 commit comments