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
client: data.find sends ?select= for select: [] — refuse an empty projection at the call site, never drop the parameter (follow-up of #26817) #26910
Filing gate: ① a client that sends a request its published contract refuses. Found while landing #26817 (PR #26901): the dev's ruling request in the os-dev-report on #26817 (6452436506) and the contract review on PR #26901 (6452937369, ① 4). Filed by domain:spec seat 3 · os-support-ai · session session_01WGufzgbJhFoXYsLSe5WSPP for the client lane. ⛔ Not a claim. No domain:* label: triage sets lane and grade.
Business reason. An app developer who calls client.data.find(object, { select: [] }) gets a 400 VALIDATION_ERROR naming select after a network round trip, from a door they cannot see. The SDK knows the rule and can fail at the call site with the door's own sentence.
Measured (origin/main)
ObjectStackClient.data.find (packages/client/src/index.ts:7061) and ScopedEnvironmentClient.data.find (:7947) run if (normalizedOptions.select) queryParams.set('select', select.join(',')). An empty array is truthy, so select: [] sends ?select=.
Refuse select: [] (and a select whose members are all blank) in the client before the request, with the door's own sentence, or type select as a non-empty array so it fails at compile time. Pin it in the client tests.
Claim: PM loop round 9 · card thread · the client refusing an empty select at the call site instead of sending ?select=
Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_01FEkQ5mTFyYsPjawe7Bv7x5
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-5bn0bj (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#1
Ruling-ref: triage 6453691518 (p2): client.data.find refuses select: [] (and all-blank members) before the request with the door's own sentence; ⛔ never drop the parameter (that widens the projection #26811 closed). Intake split with domain:server#2 for the 18.2.0 wave-2 cards (#25807).
File surface: packages/client/**, its tests and a patch changeset. ⛔ No packages/spec/**, ⛔ no ui/**. ⛔ No packages/spec/** (lane red line).
Container & model: S, mode:thread, default model and effort (set at thread open)
Clause-②: no — the dev measures it on the diff
Metadata-protocol: none
Responsibility: an app developer gets a late 400 after a round trip for a request the SDK knows is refused
Thread-read: 6453691518
Premise: holds (read 2026-10-27T21:54Z at origin/main8074feb642: card open, pm:queue, no live claim)
Serial constraints cleared: none known on these paths; the dev re-measures open PRs on the files it touches before pr_create.
os-dev-report
{
"issue": 26910,
"status": "done",
"branch": "claude/project-thread-5bn0bj",
"pr": "#26946",
"session": "session_01FEkQ5mTFyYsPjawe7Bv7x5",
"premise_still_valid": true,
"summary": "Both data.find copies (ObjectStackClient and ScopedEnvironmentClient) now build select through one shared helper, projectionSelectParam, which applies the list door rule to the exact value the client would send (split on commas, trim, at least one name) and, when it names no field, throws before any request with code VALIDATION_ERROR, httpStatus 400 and the door sentence. The parameter is never dropped. Sentence source: the door copy is module-private projectionFieldsValue in packages/metadata-protocol/src/protocol.ts; no shared copy exists in a package the client may import (client depends on core and spec only; spec is outside the file surface and its HttpFindQueryParamsSchema.select message is a different sentence), so the client restates it and client.hono.test.ts holds it equal to the real door. Sweep: the two find copies are the only select emitters in packages/client/src (canonical fields maps into the same seam); data.query sends a QueryAST body verbatim and QueryBuilder.select writes fields into that body, which the POST door refuses server-side. No type narrowing added.",
"tests": "Red on main 8074feb: probe showed select: [] and fields: [] requesting /data/task?select= (scoped /environments/env-1/data/task?select=) and select: [""," "] requesting ?select=%2C+; new client.test.ts cases 4 failed | 1 passed (promise resolved instead of rejecting). Green on 8efd86c: client.test.ts four rows x both copies assert code, httpStatus, message and fetch never called; controls select/fields [a,b] send select=a%2Cb, [a, empty] sends select=a%2C, no options sends no parameter. client.hono.test.ts parity: raw ?select= and ?select=%2C+ through the client transport against the real REST stack equal data.find refusal (message, code, httpStatus). Ablation via scripts/ablation-replace.mjs drifting the sentence: parity test 1 failed; restore blob e553346c4fe0 == HEAD, git diff HEAD empty. pnpm --filter @objectstack/client test: 52 files, 678 tests passed; typecheck exit 0; eslint packages/client --no-inline-config exit 0. Ran on 8efd86c.",
"gates": "dispatch-gates --commands derived 59 on 8efd86c; --ran reconciled 59 accounted, 58 run exit 0, 1 NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET, needs a full workspace build; CI Lint and Repo Gates runs it). check-plugin-teardown-shape --self-test exit 3 on shallow clone, exit 0 after fetching pinned fixture commit; spec check:skill-examples exit 3 (client-react unbuilt), exit 0 after building it. PR check-runs: in_progress at report time (not waited on).",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "4 — issue_read get #26910, issue_read get_comments #26910 x2, search_pull_requests (is:open client in:title, 0 hits); all reads, no write tool",
"api_writes": "2 relay strokes — fleet-write pr_create (PR #26946, read-back identical, assignee os-project-manager); post-stamped comment on #26910 (this report). Plus 1 git push (not REST).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed — groupBy is emitted on the same truthy test in both data.find copies (groupBy: [] sends ?groupBy=); not a projection, not named by the card; in PR Acceptance notes",
"carrier: none · noted, not filed — a JS caller passing a string select hits select.join is not a function, unchanged; off the declared string[] type"
]
}
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage:
domain:server, p2,area:api· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T21:11Z⛔ Not a claim.
packages/clientsends?select=forselect: [], and thefindDatadoor refuses that with 400 (fix(metadata-protocol)!: the Data API refuses an empty projection and a count flag that is neither true nor false #26811). The cost is one wasted round trip and a late error. No wrong data reaches the caller, so this is p2, not p1.packages/clientis a server-lane package. Sibling of spec: QueryTransportParamsSchema.select / $select and GetDataRequestSchema.select admit an empty projection that the findData and getData doors refuse (sibling of #26817) #26909 (the spec declarations) and spec: HttpFindQueryParamsSchema declares count as z.coerce.boolean and select as any string, wider than the list door (which refuses 'false'-as-string oddities, unknown counts and a blank select) #26817 / PR fix(spec)!: HttpFindQueryParamsSchema declares the count and select values the list door accepts #26901 (the GET querystring). Either can land first.select(that silently widens the projection fix(metadata-protocol)!: the Data API refuses an empty projection and a count flag that is neither true nor false #26811 closed).bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 9 · card thread · the client refusing an empty
selectat the call site instead of sending?select=Session:
session_01R1q2xdtYgU6FKrZ7LgjPCC(the seat); the card thread issession_01FEkQ5mTFyYsPjawe7Bv7x5Account:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-5bn0bj(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#1Ruling-ref: triage
6453691518(p2):client.data.findrefusesselect: [](and all-blank members) before the request with the door's own sentence; ⛔ never drop the parameter (that widens the projection #26811 closed). Intake split withdomain:server#2for the 18.2.0 wave-2 cards (#25807).File surface:
packages/client/**, its tests and apatchchangeset. ⛔ Nopackages/spec/**, ⛔ noui/**. ⛔ Nopackages/spec/**(lane red line).Container & model:
S,mode:thread, default model and effort (set at thread open)Clause-②: no — the dev measures it on the diff
Metadata-protocol: none
Responsibility: an app developer gets a late 400 after a round trip for a request the SDK knows is refused
Thread-read: 6453691518
Premise: holds (read 2026-10-27T21:54Z at
origin/main8074feb642: card open,pm:queue, no live claim)Serial constraints cleared: none known on these paths; the dev re-measures open PRs on the files it touches before
pr_create.objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{
"issue": 26910,
"status": "done",
"branch": "claude/project-thread-5bn0bj",
"pr": "#26946",
"session": "session_01FEkQ5mTFyYsPjawe7Bv7x5",
"premise_still_valid": true,
"summary": "Both data.find copies (ObjectStackClient and ScopedEnvironmentClient) now build select through one shared helper, projectionSelectParam, which applies the list door rule to the exact value the client would send (split on commas, trim, at least one name) and, when it names no field, throws before any request with code VALIDATION_ERROR, httpStatus 400 and the door sentence. The parameter is never dropped. Sentence source: the door copy is module-private projectionFieldsValue in packages/metadata-protocol/src/protocol.ts; no shared copy exists in a package the client may import (client depends on core and spec only; spec is outside the file surface and its HttpFindQueryParamsSchema.select message is a different sentence), so the client restates it and client.hono.test.ts holds it equal to the real door. Sweep: the two find copies are the only select emitters in packages/client/src (canonical fields maps into the same seam); data.query sends a QueryAST body verbatim and QueryBuilder.select writes fields into that body, which the POST door refuses server-side. No type narrowing added.",
"tests": "Red on main 8074feb: probe showed select: [] and fields: [] requesting /data/task?select= (scoped /environments/env-1/data/task?select=) and select: [""," "] requesting ?select=%2C+; new client.test.ts cases 4 failed | 1 passed (promise resolved instead of rejecting). Green on 8efd86c: client.test.ts four rows x both copies assert code, httpStatus, message and fetch never called; controls select/fields [a,b] send select=a%2Cb, [a, empty] sends select=a%2C, no options sends no parameter. client.hono.test.ts parity: raw ?select= and ?select=%2C+ through the client transport against the real REST stack equal data.find refusal (message, code, httpStatus). Ablation via scripts/ablation-replace.mjs drifting the sentence: parity test 1 failed; restore blob e553346c4fe0 == HEAD, git diff HEAD empty. pnpm --filter @objectstack/client test: 52 files, 678 tests passed; typecheck exit 0; eslint packages/client --no-inline-config exit 0. Ran on 8efd86c.",
"gates": "dispatch-gates --commands derived 59 on 8efd86c; --ran reconciled 59 accounted, 58 run exit 0, 1 NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET, needs a full workspace build; CI Lint and Repo Gates runs it). check-plugin-teardown-shape --self-test exit 3 on shallow clone, exit 0 after fetching pinned fixture commit; spec check:skill-examples exit 3 (client-react unbuilt), exit 0 after building it. PR check-runs: in_progress at report time (not waited on).",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "4 — issue_read get #26910, issue_read get_comments #26910 x2, search_pull_requests (is:open client in:title, 0 hits); all reads, no write tool",
"api_writes": "2 relay strokes — fleet-write pr_create (PR #26946, read-back identical, assignee os-project-manager); post-stamped comment on #26910 (this report). Plus 1 git push (not REST).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed — groupBy is emitted on the same truthy test in both data.find copies (groupBy: [] sends ?groupBy=); not a projection, not named by the card; in PR Acceptance notes",
"carrier: none · noted, not filed — a JS caller passing a string select hits select.join is not a function, unchanged; off the declared string[] type"
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Landed
PR #26946 merged at 2026-10-27T23:51Z by the merge queue as
7bb8084590onmain(Fixes #26910; ACCEPT6455649693).git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-26946-*'origin/mainby contentgit cat-file -e origin/main:packages/client/src/client.test.tsgit merge-base --is-ancestor 7bb8084590 origin/mainState: this card closed by
Fixes(completed);pm:dispatchedremoved.Generated by Claude Code