Repository navigation
fix(spec)!: HttpFindQueryParamsSchema declares the count and select values the list door accepts - #26901
Conversation
…alues the list door accepts count reads the door's accept set from QueryTransportParamsSchema.shape.count and parses 'false' as false; select must name at least one field. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzh5dnFHGxFUBugn12b
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 147 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin f0c8193ab35427261ae9d04b15418382ac87f445 && git checkout f0c8193ab35427261ae9d04b15418382ac87f445
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a51ba639c165861a8c4ac51015e554911960bf24 c3c1f10aea1b96bdcd353a861bbcb74b7fa37d02 && git checkout -B drift-repro a51ba639c165861a8c4ac51015e554911960bf24 && git merge --no-ff c3c1f10aea1b96bdcd353a861bbcb74b7fa37d02
node scripts/docs-audit/affected-docs.mjs --json a51ba639c165861a8c4ac51015e554911960bf24 |
Contract reviewServed-tier: Inputs read: card #26817 body + comments 6449665015 (triage), 6450457073 (claim), 6452436506 (os-dev-report); PR #26811 diff; PR #26901 body, file list (4 paths), the one comment 6452440544 (docs-drift bot), net diff at ① Derived judgments
② Semver level
③ Boundary flags
Gate reading of record, 2026-10-27T20:34Z: 47 check-runs on Written 2026-10-27T20:35Z. Implemented-by: VERDICT: PASS |
维护者速读 (席位终稿)
席位意见:接受。契约复核 PASS(6452937369)。同一规则的两个兄弟声明(请求体侧的 席位核对 · ACCEPT ·
|
Requested by Yibo Wang · project thread
Fixes #26817
Clause-②: no (narrowing)
Metadata-protocol: none
Skills-docs: none —
skills/**teaches only the boolean count (skills/objectui/guides/data-integration.md:90,$count: true) and never a blankselect; the generated reference pagecontent/docs/references/api/protocol.mdxis regenerated in this diff.BREAKING (accept-set narrowing of a published declaration,
patch):HttpFindQueryParamsSchemarefuses acountother than true/false and aselectnaming no field, which it admitted. The list door already refused both with a 400 (since #26811). ADR-0087 disposition in the changeset:not-required (no-migration-prescription).维护者速读
GET /data/:object查询参数的公开声明HttpFindQueryParamsSchema收窄:count只收true/false(字符串'false'读作 false),select必须至少点名一个字段,空串、纯空格、只有逗号的值都被拒。'false'甚至被读成 true;按声明生成的客户端或 AI 作者会写出运行时被拒的请求。packages/spec/src/api/protocol.zod.ts里该块的两行声明。packages/spec/src/api/protocol.zod.ts(HttpFindQueryParamsSchema的select、count两行)、packages/spec/src/api/protocol.test.ts(新增用例)、.changeset/26817-http-find-query-params-count-select.md。pnpm --filter @objectstack/spec exec vitest run src/api/protocol.test.ts,预期 215 个用例全绿,其中reads count="false" as false、refuses count="maybe"、refuses select=","都在。What changes
countreads the door's accept set from the one declaration the door parses,QueryTransportParamsSchema.shape.count(whichfindData'scountFlagValuechecks): the boolean, or the strings'true'/'false'. The nullable arm is unwrapped (a querystring carries nonull), and the value is lowered to the boolean it means, so'false'parses asfalse. It replacesz.coerce.boolean(), which read'false'astrueand admitted'maybe','1'and a blank value.selectmust name at least one field:z.string().regex(/[^\s,]/). This is the door's own rule measured inprojectionFieldsValue: it splits on commas, trims each member, drops empty members and refuses only when nothing is left. So a blank, whitespace-only or comma-only value is refused, andname,,emailorname , emailstay accepted, as at the door.\sis the settrim()strips. A regex is a string format check, not a.refine(), so it is published as a JSON Schemapatternand adds nodropped-refinementsrow..describe()texts state the new accept sets; the reference page regenerates from them.Tests
packages/spec/src/api/protocol.test.ts:count'true'/'false'/true/falseparse totrue/false;'maybe','1','0','','TRUE',1,nullrefused;select'',' ',',',' , ,', tab refused;name,name,email,name , email,name,,emailaccepted unchanged.Acceptance notes
HttpFindQueryParamsSchema. Regenerated:content/docs/references/api/protocol.mdx(gen:docs, in this diff). Unchanged by construction (key-level, keys unchanged):authorable-surface,api-surface,declaration-map,export-origins,json-schema.manifest,dropped-refinements.baseline.json;check:generatedand the build are green. Prose only:packages/client/src/index.ts:371,packages/client/src/client.test.ts:1969,packages/runtime/src/domains/data.ts:410,packages/spec/src/data/query.zod.ts:215,ui/packages/app-shell/src/console/organizations/manage/orgEnvironments.ts:64, CHANGELOG entries. Test reader:packages/metadata-protocol/src/protocol.page-window-declared.test.ts(top/skip only), green.countat all, and none sends a non-boolean count string (git grepoverpackages,examples,apps).ObjectStackClient.data.findandScopedEnvironmentClient.data.find(packages/client/src/index.ts:7060,:7946) sendselectasselect.join(',')wheneverselectis truthy, soselect: []sends?select=. Not changed here: the door answers it with a 400 namingselect, and dropping it client-side would turn an empty projection into "every column", the widening fix(metadata-protocol)!: the Data API refuses an empty projection and a count flag that is neither true nor false #26811 closed. Reported to the seat for a ruling.GetDataRequestSchema.select(z.array(z.string())) is on the by-id door (getData), notfindData, and admits[]thatgetDatarefuses.QueryTransportParamsSchema.select/$select(and the canonicalfields) sit on the samefindDatadoor and admit a blank string or[], but they also feedQueryWithTransportSchemaand thePOST /data/:object/querybody declaration, outside this card's file surface. Both are reported to the seat, not folded.no (narrowing): only a published accept set shrinks, nothing is widened, no key moves.Metadata-protocol: none: this is a querystring transport declaration, not metadata an author stores; no metadata type, key or stored shape changes.Verification
Final head:
c3c1f10ae(merge oforigin/main5787df4).Spec tests and typecheck
pnpm --filter @objectstack/spec testthentypecheck(lock VERDICT command-exit 0 for both; the chain's third leg needed a full build): Test Files 735 passed (735), Tests 22061 passed, 1 todo. After the full build:metadata-protocolprotocol.page-window-declared.test.ts+protocol.empty-projection-unknown-count.test.ts: 2 files, 532 tests passed. Fullpnpm build: Tasks 116 successful, 116 total.Derived gates (103) at c3c1f10
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 103 families, each run with the exit code captured before any pipe; all 103 exit 0 after the full build.--ran: "103 derived famil(ies) accounted for — 103 run, 0 NOT-MEASURED". Local-only:check:dev-prereqsexit 0,check:skill-frame-freshnessexit 0. Before the build, on 794bcd8, 97 exit 0 and 6 exit 3 (unbuilt dist).Full dogfood at c3c1f10
pnpm --filter @objectstack/dogfood testunder the lock: Test Files 1 failed, 326 passed, 3 skipped (330); Tests 2 failed, 2681 passed, 20 skipped (2703). Both failures arepackaged-action-disabled-dispatch-live.dogfood.test.ts(acceptance[0] and acceptance[5]/[2]), a file added by #26829 at 18:17Z today. It reads nocountorselect, andHttpFindQueryParamsSchemahas no runtime reader. The same file re-run alone on the same head and dist: 1 file, 8 tests passed. Read as load-dependent flake, not this diff.🤖 Generated with Claude Code
https://claude.ai/code/session_01WGufzh5dnFHGxFUBugn12b