Skip to content

fix(spec)!: engine-side searchFields declarations refuse an empty list, as FullTextSearchSchema.fields does - #28154

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-vyenav
Oct 30, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-vyenav

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm

Requested by Tesla · project thread

Fixes #28059

Clause-②: no (narrowing)
Metadata-protocol: none

维护者速读

  • 改了什么:引擎侧三处 searchFields 声明(EngineQueryOptionsSchema、EngineAggregateOptionsSchema、EngineCountOptionsSchema)改用共享的搜索字段数组规则,空数组 [] 被拒收,并带上与 QuerySchema.searchFields 相同的说明文字。
  • 为什么改:同一个 schema 上 search: { fields: [] } 已被拒收,searchFields: [] 却被接受,而 Data API 入口和引擎(objectql: the engine follows searchFields into its declared accept set (engine stage of #27683, the #27008 shape) #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 spec/protocol: the published searchFields declarations still admit an empty list that the data door now refuses; does searchFields follow select into a declared accept set, and does the engine follow? #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.
Ablation: removing the narrowing turns the new refusal cases red

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().

Local runs
  • 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).

Acceptance notes

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

EngineQueryOptionsSchema.searchFields and its aggregate and count
siblings take the shared search-field array arm, so the declaration
never admits the value FullTextSearchSchema.fields (the structured
search they share) and the Data API doors already refuse.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibybNsmrKsxbKJHwo36
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation protocol:data tests tooling labels Oct 30, 2026
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 3 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/spec/src/data/search-fields-names-a-field.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/kernel/contracts/data-engine.mdx (via EngineAggregateOptionsSchema (symbol, a top-level const), EngineQueryOptionsSchema (symbol, a top-level const))
What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/src/data/search-fields-names-a-field.ts) — pages documenting those are invisible to this run
  • the SDK route bridge reached 58 of 210 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 168 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 9f13ee81541ac1f6cbc2f5b5f2aca04e24ccc260 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from ec4fff953a3f513b80e830f1b92deb5206b36100 — the merge of head 53d7eec3a696cc6f1ef435d1250b025c6031df0a into base 9f13ee81541ac1f6cbc2f5b5f2aca04e24ccc260, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ec4fff953a3f513b80e830f1b92deb5206b36100 && git checkout ec4fff953a3f513b80e830f1b92deb5206b36100
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 9f13ee81541ac1f6cbc2f5b5f2aca04e24ccc260 53d7eec3a696cc6f1ef435d1250b025c6031df0a && git checkout -B drift-repro 9f13ee81541ac1f6cbc2f5b5f2aca04e24ccc260 && git merge --no-ff 53d7eec3a696cc6f1ef435d1250b025c6031df0a

node scripts/docs-audit/affected-docs.mjs --json 9f13ee81541ac1f6cbc2f5b5f2aca04e24ccc260

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 9f13ee81541ac1f6cbc2f5b5f2aca04e24ccc260 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm

Contract-review-claim: session_01L9qibwb6hBqszPTYJobitm · head c4560f09a4242db57b0c9bf7baf267fe4ecfa4df · 2026-10-30T14:52Z

In-seat at CONTRACT_REVIEW_TIER, per the maintainer: 「你有 fable,可以自己契约复审」.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: c4560f09a4242db57b0c9bf7baf267fe4ecfa4df
Local-runs: none
Scope: packages/spec/src/data/data-engine.zod.ts, packages/spec/src/data/search-fields-names-a-field.ts + packages/spec/src/data/search-fields-names-a-field.test.ts (narrowing-face floor), .changeset/28059-engine-search-fields-names-a-field.md and content/docs/references/data/data-engine.mdx (prose faces, read for ②), and the cited code read on main at 10fc9bf1: packages/spec/src/data/query.zod.ts (QuerySchema.searchFields L557, FullTextSearchSchema.fields L455), packages/spec/src/data/search-fields.ts (resolveSearchFields L263), packages/spec/src/data/hook-api.ts (HookCountQuery L155), packages/objectql/src/engine.ts (refuseSearchOverrideNamingNoField L754, called L13437-13438), packages/objectql/src/empty-projection-door.ts L57, packages/runtime/src/action-execution.ts L2734, packages/spec/src/ui/action-params.zod.ts L373, packages/objectql/src/engine-empty-search-fields-refusal.test.ts, .changeset/27484-blank-search-fields-refused.md, .changeset/27683-search-fields-names-a-field.md, .changeset/27732-engine-empty-search-fields.md, content/docs/kernel/contracts/data-engine.mdx L112.

Inputs: card #28059 body and its four comments (triage 6522171038, claim 6523197991, the domain:server note 6523729127, the os-dev-report 6525105567); PR #28154 body, five-file list, and the three-dot diff against main (merge base d6c0a75f, 5 files, +78/-19); the 50 check-runs on c4560f09. Author user.login is objectstack-fleet[bot], so no login note is owed.

Gate verdicts on the head: every one of the 50 check-runs is completed; 36 success, 14 skipped (opt-in harnesses, matrix placeholders, the schedule gate), 0 failure, the newest run of each name read; last completion 2026-10-30T14:43Z. Named: Governed Surface Queue Guard, Check Changeset, Lint · repo & tooling gates, Lint · docs & code guards, Lint · scoped · query-options erasure, Type Check · workspace, Type Check · consumer gates, Test Core (1/8 to 8/8 and the aggregate), Spec property liveness, Build Docs, Dogfood Regression Gate, PR-body guards: all success. The Docs Drift Check advisory (6525103141) names content/docs/kernel/contracts/data-engine.mdx; its L112 declares searchFields?: string[] with no claim about an empty list, so nothing there is falsified.

① Derived judgments

Each accept-set and public-surface change the diff implies, and whether it is right:

  1. EngineQueryOptionsSchema.searchFields (data-engine.zod.ts L193-194): z.array(z.string()).optional() becomes searchFieldsArray().optional(), i.e. z.array(z.string()).min(1, SEARCH_FIELDS_NAMES_NO_FIELD). [] is refused at path ['searchFields'] with the shared sentence; ['name'], ['name','email'], [''] and an absent key are kept. Right. It is the arm QuerySchema.searchFields and FullTextSearchSchema.fields already use, so one rule, no second .min(1).
  2. EngineAggregateOptionsSchema.searchFields (L519-520) and EngineCountOptionsSchema.searchFields (L566-567): the same change. Right, and it removes the contradiction the card names: on each of these three schemas search: { query, fields: [] } was already refused (the union reuses FullTextSearchSchema) while searchFields: [] was admitted.
  3. Published description and JSON Schema: the three members gain a .describe() ending in SEARCH_FIELDS_ACCEPT_SET, so codegen and the reference docs state the rule (minItems: 1 plus the sentence). The regenerated content/docs/references/data/data-engine.mdx rows (L489, L574, L700) carry exactly that text. Right. The six-member "declarations state the accept set they enforce" test now covers all six published declarations of the override.
  4. TypeScript surface: EngineQueryOptions/Parsed, EngineAggregateOptions/Parsed, EngineCountOptions/Parsed (L1388-1407) and HookCountQuery = Omit of EngineCountOptions (hook-api.ts L155) stay searchFields?: string[]; .min(1) does not move the inferred type. Right; check:api-surface was not stale and Type Check · workspace is green.
  5. Untouched neighbours: QueryTransportParamsSchema.$searchFields (L975), QuerySchema.searchFields, FullTextSearchSchema.fields, the $searchFields to searchFields lowering (L794, L1130), and the legacy DataEngine*OptionsSchema, which declare no searchFields at all. A grep of packages/spec/src outside tests shows the six declarations above and no seventh. Right: the diff's claim "no published declaration of the override admits []" holds on this tree.
  6. Runtime reach of the narrowing: no in-repo code parses an engine option bag with these three schemas. The readers are key-set or message readers only: objectql empty-projection-door.ts L57 (shape.fields.safeParse([])), runtime action-execution.ts L2734 (Object.keys(shape)), spec ui/action-params.zod.ts L373 (legal key set), objectql ENGINE_COUNT_OPTION_KEYS. Key set unchanged, so none moves. The diff therefore changes the declared face (JSON Schema, docs, generated clients) and nothing at runtime. Right, and the PR body says so.
  7. Clause-②: no (narrowing) and Metadata-protocol: none, on the PR body and the changeset: nothing newly admitted, [] refused; engine option bags are not a metadata author's surface. Right.
  8. The narrowing takes no working capability away at any consumer: the Data API doors refuse [] since data: a blank or comma-only $searchFields is read as absent, so a search the caller narrowed runs over the default search fields instead of being refused #27484 (assertSearchFieldsAreSearchable), and the in-process engine refuses it since 6a648ac2 (fix(objectql)!: the in-process engine refuses a search-field override that names no field, as the doors and the shared declarations do #28108, on main 2026-10-30T13:29Z: refuseSearchOverrideNamingNoField, engine.ts L754, called before any driver read at L13437-13438, 400 VALIDATION_ERROR, words read off FullTextSearchSchema.shape.fields). The declaration catches up to two refusals that already exist on main. Right.
  9. Test face (floor path): the spec/protocol: the published searchFields declarations still admit an empty list that the data door now refuses; does searchFields follow select into a declared accept set, and does the engine follow? #27683 stage-boundary pin ("still admits an empty list") is flipped to refusal cases (path, message, same answer as search.fields: [], kept lists, absent key), one per schema. Right; the dev's ablation on fca20448 reports exactly the 6 new cases red with the arm reverted, and Test Core is green on the head.

② Semver level

③ Boundary flags

  • Dev deviation 1 (os-dev-report): the claim comment writes Clause-②: no; order and triage write no (narrowing); the PR body and changeset carry no (narrowing). Answered: the claim line does not ship, the two carriers that do are right.
  • Dev deviation 2: the 104-command gate sweep ran on d38c42e6, before the merge commit; the merge c4560f09 brought no packages/spec change. Answered by the head's check-runs: all green on c4560f09.
  • Dev deviation 3: test:repo not run locally. Answered: Test Core (8 shards and aggregate) green on the head.
  • open_questions: [], out_of_scope_findings: []. None to escalate.
  • domain:server note 6523729127 (stale sentence in search-fields-names-a-field.ts L29-32, "the in-process engine still reads an empty override as absent"): taken in this PR, the sentence is rewritten; nothing left for seat 1 to file.
  • Branch: claude/project-thread-vyenav instead of claude/issue-28059-slug, declared in the claim (platform-assigned thread branch); Implemented-by: below uses it.
  • Head ancestry: the merge base d6c0a75f predates 6a648ac2; the PR is mergeable: clean; of the main commits since the base, none touches this PR's five paths (6a648ac2 touches objectql and protocol docs; 2695de71/146115a9 touch other spec files), so the regenerated data-engine.mdx and the test file land without textual or regeneration conflict. The only effect of the gap is S1 above.
  • Draft PR, auto_merge: null: nothing armed, nothing to disarm.
  • Author objectstack-fleet[bot]: no login note owed.

④ Design judgment

packages/spec/src/data/data-engine.zod.ts — judged against the ruling (card #28059 and triage 6522171038: "the engine-side searchFields declarations take the same declared accept set as FullTextSearchSchema.fields, so the declaration never admits what the engine refuses") and its first consumers (the published JSON Schema and reference docs; the engine's refusal in objectql engine.ts).

  • Holds against the ruling: the three declarations call searchFieldsArray() from ./search-fields-names-a-field (already imported at L9 for $searchFields), so they are the same arm, not a copy; the sentence is SEARCH_FIELDS_NAMES_NO_FIELD, read off the same constant the engine (engine.ts L760, via FullTextSearchSchema.shape.fields) and the door declarations use. The declaration and the in-process refusal now agree in accept set and in words.
  • Break attempts, none succeeds: (a) search: { query: 'x', fields: [] } on an engine schema goes through z.union([z.string(), FullTextSearchSchema]); the array branch fails dirty (too_small), so zod reports the inner message, not invalid_union — the "answers [] as its structured search.fields does" test pins it per schema and is green. (b) .optional().describe(...) ordering matches QuerySchema.searchFields L557-558 on main, and .shape.searchFields.description is pinned by the six-member test. (c) A blank member [''] is admitted, as the shared arm admits it everywhere else; the door refuses it as an unknown field and the engine intersects it away; the changeset declares it. (d) null: refused before and after (.optional() without .nullable()), unchanged by this diff. Observation, no fix owed here: the engine on main reads searchFields: null as a withdrawal (objectql: the engine follows searchFields into its declared accept set (engine stage of #27683, the #27008 shape) #27732 "Unchanged"), so on null the declaration is narrower than the engine; pre-existing, not this card's.
  • Design is the minimal correct one: no new rule, no new module, the three sites and the docblocks only. No finding.

packages/spec/src/data/search-fields-names-a-field.ts — docblock only; the exported constants and factories are byte-identical. Judged against the tree: the new sentence "no published declaration of the override admits []" is true at this head (six declarations, all on the arm; the grep in ①.5). The sentence the domain:server note flagged is gone.

  • S3 (should-fix, minor). L24-26 still describe ./data-engine.zod.ts as reading this module for "the transport spelling $searchFields" alone; after this diff it reads the arm for four declarations. One parenthetical; the paragraph is otherwise right.

Narrowing face as a whole (every non-prose path of the diff, the test file included): the narrowing takes no declared capability away at a consumer — both refusals it declares already exist on main (door since #27484, engine since 6a648ac2) — and it makes the spec's own refusal real at the one place that still contradicted it. The test file pins refusal, path, message, parity with search.fields, kept lists and the absent key for each schema.

No must-fix. Should-fix: S1, S2 (changeset prose), S3 (one docblock parenthetical).

Implemented-by: claude/project-thread-vyenav
Reviewed-by: session_01L9qibwb6hBqszPTYJobitm

VERDICT: PASS

… release; name both superseded entries

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibybNsmrKsxbKJHwo36
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm

Regen-provenance: 6525975157 · c4560f09a4242db57b0c9bf7baf267fe4ecfa4df → 53d7eec3a696cc6f1ef435d1250b025c6031df0a · git diff --name-only c4560f0 53d7eec -- . ':!.changeset/' → (empty)

维护者速读

  • 改了什么: 引擎侧三处 searchFields 声明(EngineQueryOptionsSchema、EngineAggregateOptionsSchema、EngineCountOptionsSchema)改用共享的 searchFieldsArray(),空数组 [] 在声明上被拒,和 QuerySchema.searchFields、FullTextSearchSchema.fields 同一条规则。
  • 为什么改: 声明原来接受 [],Data API 入口和引擎(fix(objectql)!: the in-process engine refuses a search-field override that names no field, as the doors and the shared declarations do #28108 起)却拒收,按类型写代码的调用方会被误导。
  • 风险与回滚: TS 类型不变(仍是 string[]),仓库内没有代码用这些 schema 解析引擎选项,只是声明面收窄。回滚即 revert。
  • 先看: packages/spec/src/data/data-engine.zod.ts 三处声明。
  • 两分钟验证: pnpm --filter @objectstack/spec exec vitest run src/data/search-fields-names-a-field.test.ts。
  • 需要你做的: 无。不属于受管面,席内契约复审 PASS(评论 6525975157),由席位落地。
  • 席位意见: ACCEPT,可落地。

席位核对 · ACCEPT · domain:spec seat 1 (#6017) · 2026-10-30T15:08Z

Head 53d7eec3a696cc6f1ef435d1250b025c6031df0a. Card #28059, claim 6523197991, os-dev-report 6525105567. The maintainer's rulings, verbatim: 「你有 fable,可以自己契约复审」 and 「按 pm-dispatch 审过的pr你可以自主落地」.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 30, 2026 15:44
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 30, 2026 15:44
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 35f2055 Oct 30, 2026
55 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-vyenav branch October 30, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:data size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spec(data-engine): engine-side searchFields declarations refuse an empty list, as the engine now does (spec half of #27732)

1 participant