Repository navigation
docs(api): sort spellings are slot-specific, not equivalent across routes - #19055
Merged
os-try-charles merged 1 commit intoSep 18, 2026
Merged
os-try-charles merged 1 commit into
os-try-charles merged 1 commit into
Conversation
…utes
`content/docs/api/data-api.mdx` taught three `POST /data/:object/query` sort
spellings as "all equivalent". Measured over real HTTP on both routes, two of
the three answer `400 VALIDATION_FAILED` on `orderBy`:
{"orderBy": [{"field":"created_at","order":"desc"}]} 200
{"orderBy": ["-created_at"]} 400 @ query.orderBy.0
{"orderBy": {"created_at":"desc"}} 400 @ query.orderBy
The record map is a transport-slot value — it works on `$orderby` / `sort` in
the same body. The shorthand string, bare or inside an array, reaches no body
slot at all; it is a querystring spelling, served by `normalizeSortNodes` at
the ingress.
Replaces the sentence with a per-route, per-slot table whose every cell was
measured, on a booted CRM app, on both routes.
Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
Co-authored-by: Claude <noreply@anthropic.com>
os-try-charles
marked this pull request as ready for review
September 18, 2026 14:54
os-try-charles
deleted the
claude/issue-19027-data-api-orderby-spellings-not-equivalent
branch
September 18, 2026 15:34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #19027
Clause-②: no
What the page said, and what the runtime does
content/docs/api/data-api.mdxtaught threePOST /data/:object/querysortspellings as "all equivalent". Reproduced at the exact input
rest-server.tsbuilds —
FindDataRequestSchema.safeParse({ object, query: { ...body, object } })— and again over real HTTP against a booted
examples/app-crm:{"orderBy": [{"field": "created_at", "order": "desc"}]}⭐ lit controlsuccess: true{"orderBy": ["-created_at"]}query.orderBy.0·invalid_type· "expected object, received string"VALIDATION_FAILED{"orderBy": {"created_at": "desc"}}query.orderBy·invalid_type· "expected array, received object"VALIDATION_FAILEDThe lit control returns 200, so the instrument is sound and the defect is the
page's, as the card diagnosed.
Where the card's diagnosis needed correcting
The card says the record map and the shorthand array "are transport-slot values
— they have to arrive on
$orderby/sort". Measured, that holds for the mapand not for the shorthand array. Every POST-body slot, one tree:
orderBy$orderbysort[{"field": "created_at", "order": "desc"}]{"created_at": "desc"}(and1/-1)["-created_at"]"-created_at"(bare string)QueryTransportParamsSchema.$orderbyisDataEngineSortSchema, which declaresthe record map and
SortNode[]and no string form at all. So the shorthandstring is not a transport-slot value on this route either — it is a
querystring spelling, read by
normalizeSortNodesat the ingress. Measuredon the querystring:
?sort=-created_at,?$orderby=-created_atand?orderBy=-created_atall sort; the two JSON shapes sent there are400 INVALID_SORT, because that route parses no JSON in this slot and reads thewhole value as one field name.
Had the page simply been trimmed to the card's diagnosis, a reader sent to
{"$orderby": ["-created_at"]}would have got the same 400 from a differentline.
The fix
The sentence is replaced by a per-route, per-slot table plus two short
paragraphs. Every cell in it is a measurement, not a reading of the schema.
The page's only mention of
POST /data/:object/querywas inside the sentencebeing replaced, so the table is also now that route's only description here.
The status-code split is stated per route as well: a wrong shape in a body is
400 VALIDATION_FAILEDwith the path infields(query.orderBy.0,query.orderBy.0.order) and never reaches the field check, while an unknownfield name is
400 INVALID_SORTon either route.Verification
the full slot matrix above and the malformed-shape cases.
pnpm dev:crm -- --fresh -p PORT(a random high port), signed inas the seeded dev admin,
GET /data/crm_accountandPOST /data/crm_account/query. Ascending/descending row order is the litcontrol on every 200 cell:
['Acme Corp','Globex Ltd','Initech']vs['Initech','Globex Ltd','Acme Corp'], so an accepted-but-unapplied sortcould not read as a pass.
and asserts each cell's verdict token equals the measured one, that the four
spellings are still shown (so deleting them would fail it), and that no
cross-route equivalence wording survives. It reports 8 failures against the
pre-edit page and passes against the edited one; both legs were run with the
same scoped instrument.
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, 39 commands, all run; exits in the report.No changeset — measured, not asserted
No published package contains
content/docs/api/data-api.mdx: over the 70non-private manifests in the tree, zero sit at or above that path. Positive
control, same method:
packages/spec/dist/index.jsresolves into@objectstack/spec, whosefiles[]shipsdist.apps/docs, which rendersthis tree, is
private: true. So nothing published moves and the change takesskip-changeset.Acceptance notes
#18977is not addressed here, andPR #19018is untouched by this diff —this PR edits one file, that one edits four, and they do not overlap. No
packages/spec/**path is in this diff: the measurement showed the defect isthe documentation's, which is the branch the dispatch reserved for staying on
this page.
packages/spec/src/api/odata.zod.tsalready carries thecorrect account of this split in a schema comment (the
#18977cross-reference), including the sentence that the string forms are served by
normalizeSortNodesand not by the body door. The customer-facing page hadno pointer to it in either direction. Successor: the next PR to touch that
schema comment or this page.
🤖 Generated with Claude Code
https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
Generated by Claude Code