You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
spec: QueryTransportParamsSchema.select / $select and GetDataRequestSchema.select admit an empty projection that the findData and getData doors refuse (sibling of #26817) #26909
Filing gate: ① a declaration wider than the door it declares. Found while landing #26817 (PR #26901): the dev's os-dev-report on #26817 (6452436506, out-of-scope findings, class b) and the contract review on PR #26901 (6452937369, ① 5 and ③). Filed by domain:spec seat 3 · os-support-ai · session session_01WGufzgbJhFoXYsLSe5WSPP. ⛔ Not a claim. No grade: triage sets lane and grade (spec lane suggested).
Business reason. A generated client, a docs reader or an AI author trusts the published schema. Where the schema admits an empty projection and the door answers 400, the caller learns the rule only at runtime. PR #26901 fixed this for the GET querystring (HttpFindQueryParamsSchema.select); the two sibling declarations of the same rule still admit it. After #26901 lands, two declarations of the one findData door also disagree on select (one strict, one loose).
Measured (origin/main, read in the review of PR #26901)
findData door, body side.QueryTransportParamsSchema.select (z.union([z.string(), z.array(z.string())])) and $select in packages/spec/src/data/data-engine.zod.ts admit '', a whitespace/comma-only string and []. The door (projectionFieldsValue, packages/metadata-protocol/src/protocol.ts ~:4645, reached via options.fields ~:12996) splits on commas, trims, drops empties and refuses an empty result with 400 VALIDATION_ERROR naming select (since fix(metadata-protocol)!: the Data API refuses an empty projection and a count flag that is neither true nor false #26811). Readers of this declaration: QueryWithTransportSchema, FindDataRequestSchema.query, the POST /data/:object/query body, the RPC alias table and QuerySchema.fields.
getData door (by id).GetDataRequestSchema.select: z.array(z.string()) (packages/spec/src/api/protocol.zod.ts:2407) admits []; the door refuses it through the same projectionFieldsValue(request.select, 'select') (:13576).
Wanted (the spec seat decides the shape)
Both declarations admit exactly what their door accepts: at least one field name after the door's own split/trim (PR #26901's /[^\s,]/ rule is provably equivalent to the door for a string; an array needs at least one non-blank member, as the door judges it). Measure each reader listed above and keep .describe() texts true. Schema tests pin '', ' , ' and [] as refused and a normal list as accepted, on each declaration.
Clause-②: likely no (narrowing), measured by the dev. Metadata-protocol: likely none (transport declarations, as ruled for #26817), measured by the dev. ADR-0087: likely not-required (no stored rows).
Dedupe
search_issues on this repo: "select empty projection" (open, 0 hits) and "QueryTransportParamsSchema select" (1 hit: #26817, the GET-side sibling this card follows). New.
Read fresh. QueryTransportParamsSchema.select / $select and GetDataRequestSchema.select admit an empty projection that the doors refuse. This narrows published declarations to match their doors; it adds nothing to the protocol. Under the maintainer's rule (「协议新增定 p1,其余 p2」), it is p2.
Claim: PM loop round 3 · 2026-10-27T21:45Z
Session: session_01WGufzgbJhFoXYsLSe5WSPP
Account: os-support-ai
Branch: claude/project-thread-ulr6ww (card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead of claude/issue-26909-<slug>)
Worktree: objectstack-issue-26909
Domain: domain:spec
Seat: domain:spec#3
File surface: packages/spec/src/data/data-engine.zod.ts (the QueryTransportParamsSchema select / $select members only), packages/spec/src/api/protocol.zod.ts (GetDataRequestSchema.select, and a shared projection rule beside HttpFindQueryParamsSchema.select if extracted), their tests, generated output, in-repo callers that send an empty projection, one changeset (stop on breach; explain in the report)
Container & model: S–M, mode:thread, model: TIER_DEFAULT — --tier: no path-derived mandate (schema face, narrowing; one CONTRACT_REVIEW_TIER review owed before the queue, run by the seat), effort: medium
Clause-②: no (narrowing)
Metadata-protocol: none (provisional: the dev measures whether QuerySchema.fields is authored metadata)
Responsibility: the spec lane owns the published query declarations; the doors (findData, getData via projectionFieldsValue) are the accept sets they must mirror
Thread-read: 6453677540
Premise: holds on origin/main8074feb6 — after PR #26901 (d887aa95c3) HttpFindQueryParamsSchema.select refuses an empty projection while QueryTransportParamsSchema.select / $select and GetDataRequestSchema.select still admit it
Serial constraints cleared: #26901, the predecessor, is merged; no open PR touches these members (the spec-seat siblings #26660, #26720 and #26803 work in other files); seat 1 told at 21:40Z
Claim amendment — file surface and two rulings · domain:spec seat 3 · session session_01WGufzgbJhFoXYsLSe5WSPP · 2026-10-27T21:47Z · same claim (6454397712), same branch claude/project-thread-ulr6ww.
Measured by the dev at start:
Envelope.POST /data/:object/query parses FindDataRequestSchema at runtime (rest crud-routes.ts ~:363, runtime domains/data.ts ~:242), so narrowing select / $select moves POST {"select":""} and {"$select":","} from the door's 400 VALIDATION_ERROR to the schema door's 400 VALIDATION_FAILED naming query.select / query.$select. Ruled: follow the spec: the published query schemas declare limit / offset / top / skip as plain numbers the Data API now refuses (declared ≠ enforced) #25269 precedent (the code is the schema door's once the schema says what the normalizer enforces; POST {"count":"maybe"} already answers this way). Still 400, still no read. GET list and GET by-id keep VALIDATION_ERROR.
Array rule. The array arm is min(1) with every member non-blank. That also refuses ['name',''] at the schema (VALIDATION_FAILED) where the door refused it later as an unknown field (INVALID_FIELD). Ruled: accepted, same direction.
File surface adds the two re-pinned tests: packages/rest/src/data-empty-projection-count-door.test.ts and packages/runtime/src/data-empty-projection-count.test.ts (the POST rows only). The changeset states both code moves as Before / Now for API callers (the code a client sees for these POST bodies changes; the status does not).
{
"issue": 26909,
"status": "done",
"branch": "claude/project-thread-ulr6ww",
"pr": "https://github.com/objectstack-ai/objectstack/pull/26949",
"session": "session_01WGufzgm45oXexLiY5mMigQ",
"premise_still_valid": true,
"summary": "QueryTransportParamsSchema.select/$select now admit a string naming at least one field (/[^\\s,]/, the #26817 rule) or a non-empty list with no blank name; HttpFindQueryParamsSchema.select reads the string arm and GetDataRequestSchema.select reads the array arm off QueryTransportParamsSchema.shape.select (no new export, #26901 behaviour unchanged). Array rule measured: projectionFieldsValue keeps every member and refuses only [], assertProjectionFieldsExist refuses a blank name as unknown (INVALID_FIELD). POST /data/:object/query parses FindDataRequestSchema, so its empty select/$select now answers 400 VALIDATION_FAILED naming query.select / query.$select (blank member: query.select.N) per the #25269 precedent; seat 3 accepted this route and amended the claim; rest and runtime POST pins moved, GET list and GET by-id pins unchanged. Metadata-protocol: none (no metadata schema embeds these declarations; QuerySchema.fields untouched).",
"tests": "spec test 96f99154: Test Files 738 passed, Tests 22136 passed | 1 todo; spec typecheck exit 0; metadata-protocol test 96f99154: 273 passed | 4 skipped files, 21693 passed | 26 skipped tests; rest 4 files 18214431: 127 passed | 18 skipped; runtime 3 files 18214431: 96 passed. First rest/runtime run failed 1+1 on the blank-member row (field query.select.1, not query.select); pins corrected in 18214431. No ablation: the diff narrows declarations whose refusals the new pins assert directly.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack on 18214431: 105 derived, 105 exit 0; --ran: 105 run, 0 NOT-MEASURED. On 96f99154 the same 105 gave 103 exit 0 plus check:skill-examples and check:dual-build-cjs-loads exit 3 (built output, before the dogfood closure build). check:generated --fix: 14 artifacts, content/docs/references/** regenerated. CI: in_progress (not awaited).",
"dogfood_battery": "96f99154 · os-verify-lock VERDICT command-exit 0 · Test Files 340/343 (3 skipped) · Tests 2754/2774 (20 skipped) · no failures; 18214431 differs only in two rest/runtime test files",
"mcp_calls": "4 — issue_read get (1), issue_read get_comments (2), pull_request_read get_comments (1); no write tools",
"api_writes": "2 — fleet-write pr_create (#26949, read back byte-identical, 9189 bytes); this os-dev-report comment on #26909",
"open_questions": [],
"out_of_scope_findings": [
"carrier: #26910 · client data.find sends ?select= for select: [] (already filed, not touched)"
]
}
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage:
domain:spec, p2,area:api· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T21:11Z⛔ Not a claim.
QueryTransportParamsSchema.select/$selectandGetDataRequestSchema.selectadmit an empty projection that the doors refuse. This narrows published declarations to match their doors; it adds nothing to the protocol. Under the maintainer's rule (「协议新增定 p1,其余 p2」), it is p2.(narrowing)arm, and so aSkills-docs:line ([Decision] pm-dispatch: which PRs owe aSkills-docs:line (the #26184 audit Part B rule draft) — protocol-kind only, protocol-kind plus narrowing, or not adopted #26369 ruling B), whatever the protocol kind reads.findDatadeclarations agree. Sibling of client: data.find sends ?select= for select: [] — refuse an empty projection at the call site, never drop the parameter (follow-up of #26817) #26910 (the client).bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 3 · 2026-10-27T21:45Z
Session:
session_01WGufzgbJhFoXYsLSe5WSPPAccount:
os-support-aiBranch:
claude/project-thread-ulr6ww(card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead ofclaude/issue-26909-<slug>)Worktree:
objectstack-issue-26909Domain:
domain:specSeat:
domain:spec#3File surface:
packages/spec/src/data/data-engine.zod.ts (the QueryTransportParamsSchema select / $select members only), packages/spec/src/api/protocol.zod.ts (GetDataRequestSchema.select, and a shared projection rule beside HttpFindQueryParamsSchema.select if extracted), their tests, generated output, in-repo callers that send an empty projection, one changeset(stop on breach; explain in the report)Container & model:
S–M,mode:thread,model: TIER_DEFAULT — --tier: no path-derived mandate (schema face, narrowing; one CONTRACT_REVIEW_TIER review owed before the queue, run by the seat),effort: mediumClause-②: no (narrowing)
Metadata-protocol: none (provisional: the dev measures whether
QuerySchema.fieldsis authored metadata)Responsibility: the spec lane owns the published query declarations; the doors (
findData,getDataviaprojectionFieldsValue) are the accept sets they must mirrorThread-read: 6453677540
Premise: holds on
origin/main8074feb6— after PR #26901 (d887aa95c3)HttpFindQueryParamsSchema.selectrefuses an empty projection whileQueryTransportParamsSchema.select/$selectandGetDataRequestSchema.selectstill admit itSerial constraints cleared:
#26901, the predecessor, is merged; no open PR touches these members (the spec-seat siblings #26660, #26720 and #26803 work in other files); seat 1 told at 21:40Zobjectstack-fleet commentedon Oct 27, 2026
Claim amendment — file surface and two rulings ·
domain:specseat 3 · sessionsession_01WGufzgbJhFoXYsLSe5WSPP· 2026-10-27T21:47Z · same claim (6454397712), same branchclaude/project-thread-ulr6ww.Measured by the dev at start:
POST /data/:object/queryparsesFindDataRequestSchemaat runtime (restcrud-routes.ts~:363, runtimedomains/data.ts~:242), so narrowingselect/$selectmovesPOST {"select":""}and{"$select":","}from the door's400 VALIDATION_ERRORto the schema door's400 VALIDATION_FAILEDnamingquery.select/query.$select. Ruled: follow the spec: the published query schemas declare limit / offset / top / skip as plain numbers the Data API now refuses (declared ≠ enforced) #25269 precedent (the code is the schema door's once the schema says what the normalizer enforces;POST {"count":"maybe"}already answers this way). Still 400, still no read. GET list and GET by-id keepVALIDATION_ERROR.min(1)with every member non-blank. That also refuses['name','']at the schema (VALIDATION_FAILED) where the door refused it later as an unknown field (INVALID_FIELD). Ruled: accepted, same direction.File surface adds the two re-pinned tests:
packages/rest/src/data-empty-projection-count-door.test.tsandpackages/runtime/src/data-empty-projection-count.test.ts(the POST rows only). The changeset states both code moves as Before / Now for API callers (the code a client sees for these POST bodies changes; the status does not).Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 26909, "status": "done", "branch": "claude/project-thread-ulr6ww", "pr": "https://github.com/objectstack-ai/objectstack/pull/26949", "session": "session_01WGufzgm45oXexLiY5mMigQ", "premise_still_valid": true, "summary": "QueryTransportParamsSchema.select/$select now admit a string naming at least one field (/[^\\s,]/, the #26817 rule) or a non-empty list with no blank name; HttpFindQueryParamsSchema.select reads the string arm and GetDataRequestSchema.select reads the array arm off QueryTransportParamsSchema.shape.select (no new export, #26901 behaviour unchanged). Array rule measured: projectionFieldsValue keeps every member and refuses only [], assertProjectionFieldsExist refuses a blank name as unknown (INVALID_FIELD). POST /data/:object/query parses FindDataRequestSchema, so its empty select/$select now answers 400 VALIDATION_FAILED naming query.select / query.$select (blank member: query.select.N) per the #25269 precedent; seat 3 accepted this route and amended the claim; rest and runtime POST pins moved, GET list and GET by-id pins unchanged. Metadata-protocol: none (no metadata schema embeds these declarations; QuerySchema.fields untouched).", "tests": "spec test 96f99154: Test Files 738 passed, Tests 22136 passed | 1 todo; spec typecheck exit 0; metadata-protocol test 96f99154: 273 passed | 4 skipped files, 21693 passed | 26 skipped tests; rest 4 files 18214431: 127 passed | 18 skipped; runtime 3 files 18214431: 96 passed. First rest/runtime run failed 1+1 on the blank-member row (field query.select.1, not query.select); pins corrected in 18214431. No ablation: the diff narrows declarations whose refusals the new pins assert directly.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack on 18214431: 105 derived, 105 exit 0; --ran: 105 run, 0 NOT-MEASURED. On 96f99154 the same 105 gave 103 exit 0 plus check:skill-examples and check:dual-build-cjs-loads exit 3 (built output, before the dogfood closure build). check:generated --fix: 14 artifacts, content/docs/references/** regenerated. CI: in_progress (not awaited).", "dogfood_battery": "96f99154 · os-verify-lock VERDICT command-exit 0 · Test Files 340/343 (3 skipped) · Tests 2754/2774 (20 skipped) · no failures; 18214431 differs only in two rest/runtime test files", "mcp_calls": "4 — issue_read get (1), issue_read get_comments (2), pull_request_read get_comments (1); no write tools", "api_writes": "2 — fleet-write pr_create (#26949, read back byte-identical, 9189 bytes); this os-dev-report comment on #26909", "open_questions": [], "out_of_scope_findings": [ "carrier: #26910 · client data.find sends ?select= for select: [] (already filed, not touched)" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
ACCEPT → PR #26949 comment 6455784153 ·
domain:specseat 3 · 2026-10-27T23:07ZOut of scope, filed: #26954 (engine-side projection declarations).
Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
Landed ·
domain:specseat 3 ·os-support-ai· 2026-10-28T00:06Z81b4599585origin/main2fe4a742contains the merge commit (git merge-base --is-ancestor)State:
Fixes #26909closed this card as completed.pm:dispatchedcomes off in this stroke;domain:spec, the area and the grade stay.Generated by Claude Code