From 882bbf7733362e973f776f6a4995d1feb879f34e Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 10:21:52 +0000 Subject: [PATCH] docs(ui): read QueryResult.data in the react-pages live-data sample, and name the real cost of a dropped query option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two defects in the "Live data" section of content/docs/ui/react-pages.mdx. 1. The sample read `result.records`, which the adapter never emits. `useAdapter()` returns `ObjectStackAdapter`; its `find()` resolves through `normalizeQueryResult`, which returns the `QueryResult` shape declared in objectui packages/types/src/data.ts — `data` / `total` / `page` / `pageSize` / `hasMore` / `cursor`, with no `records` key. The `Array.isArray(result)` arm never fired either, because the adapter has already folded the array case into an object. So `records` fell to `[]` and the published sample rendered an empty list forever, with no error. Now spelled canonical-first with the legacy key as a fallback and the array arm preserved, matching every objectui consumer of this contract (data-list.tsx, record-picker.tsx, ObjectRefField.tsx, record-history.tsx). This was the third instance of the same read: fixed once in examples/app-showcase/src/ui/pages/crm-workbench.page.ts and again in renewals-pipeline.page.ts. The doc is the copy the customer starts from. 2. The Callout below it named the wrong consequence. It warned that a dropped query option comes back "with the default page size"; the GET list route has no default page size, so an absent `top` returns the ENTIRE match set. Verified in the route itself: `findData` (packages/metadata-protocol/src/protocol.ts) resolves paging as `typeof options.limit === 'number' && options.limit > 0 ? options.limit : undefined` and never assigns a default, and its own comment reads "Without a limit the full result set is returned". Measured by protocol-unknown-query-param.test.ts's "baseline — no params returns every row" (10 rows seeded, total 10, no params). The Callout now states the unbounded read, so a reader debugging it stops looking for pagination that does not exist. Docs-only; publishes nothing, so no changeset. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_c970724d-303c-5614-9d20-a3f92205cfad --- content/docs/ui/react-pages.mdx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/content/docs/ui/react-pages.mdx b/content/docs/ui/react-pages.mdx index 7f60c43fe7..8995d104b0 100644 --- a/content/docs/ui/react-pages.mdx +++ b/content/docs/ui/react-pages.mdx @@ -144,7 +144,7 @@ function Page() { $filter: ['status', '!=', 'paid'], $top: 200, }); - const records = Array.isArray(result) ? result : (result && result.records) || []; + const records = result?.data ?? result?.records ?? (Array.isArray(result) ? result : []); if (alive) setRows(records); })(); return () => { alive = false; }; @@ -156,8 +156,10 @@ function Page() { The `$` prefixes are load-bearing. An unprefixed `top:` or a `filters:` key is not a -query option — it is silently dropped, and the query comes back unfiltered or with the -default page size. There is no error. +query option — it is silently dropped, and the query runs as if you had not written +it: a dropped `filters:` comes back unfiltered, and a dropped `top:` comes back with +**every matching row**, because the list route has no default page size. The failure +mode is an unbounded read, not a truncated one. There is no error. `$filter` takes an ObjectQL filter array: `['field', 'op', value]`, with `and` / `or`