Repository navigation
fix(data-objectstack): read analytics rows in one spelling, the post-unwrap rows (objectui#7028) - #10363
Conversation
…unwrap `rows` (objectui#7028) @objectstack/client 17.3.0 converged analytics.query on unwrapResponse (objectstack#13079), and the ruling on that card ordered aggregate()'s tolerant row ladder tightened in the same wave. The ladder read five spellings and answered anything else with []. - read `rows` on the AnalyticsResult only; any other value throws the new AnalyticsResultShapeError, which aggregate()'s catch rethrows before the classifier so the client-side fallback never answers it - drop the widened AnalyticsResult alias the retired branches needed - raise the @objectstack/client floor to ^17.3.0, the first release that unwraps this method (lockfile specifier only; the resolution is unchanged) - site-scoped pins: the unwrapped shape yields rows, an envelope throws (through the real client and as a pre-17.3.0 client's value), the other retired spellings throw, and the measure-missing fallback still runs Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
….0 with the adapter's The quick-reference Client row anchors on both apps/console and packages/data-objectstack and states one value; the adapter's floor moved to ^17.3.0 with the single-spelling row read, so the console's declared range moves with it. Lockfile specifier only; the resolution is unchanged. QUICK_REFERENCE.md rewritten by `pnpm quick-reference:sync`. Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
…ctui#7028) The change adds a public export (AnalyticsResultShapeError), turns a shape that used to resolve into a throw, and moves the @objectstack/client floor; behaviour-changing work in this repo is declared minor. Front matter only; the body names no level. Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Fixes #7028
Clause-②: yes
What
aggregate()now reads theclient.analytics.queryanswer in one spelling:rowson the post-unwrapAnalyticsResult. This is condition 3 of the objectstack#13079 ruling's landing requirements (director batch #19, option A, maintainer 2026-08-31), quoted verbatim: 「objectui 容错链同波收紧:已立 objectui#7028,带时序门(严格在收敛合并、objectui 采版之后 —— 该链今天是承重的)」. The card's sequencing gate is met:@objectstack/client17.3.0 carries the convergence, and the workspace lockfile resolves 17.4.0.rows,dataas an array,data.data.rowsandresults, and answered anything else with[]. Onlyrowssurvives. Any other value throws the new exportedAnalyticsResultShapeError(code: 'ANALYTICS_RESULT_SHAPE_INVALID',envelope: truefor the pre-17.3.0 envelope).aggregate()'stry. Itscatchwould have classified the error asunknownand answered it withaggregateViaFind's client-side numbers, so the catch now rethrowsAnalyticsResultShapeErrorbefore it classifies anything. I chose a throw over a diagnostic because the file already treats contract violations that way:AnalyticsQueryRejectedErrorrefuses the fallback for the same reason (framework#3878). A[]would repeat the confident zero that objectui#5954 removed on the failure side.AnalyticsResultalias is gone, along with the branches it existed for.@objectstack/clientfloor moves from^17.0.0to^17.3.0inpackages/data-objectstackandapps/console. Only the lockfile specifier changes; the resolution stays at 17.4.0.QUICK_REFERENCE.md's Client row was rewritten bypnpm quick-reference:sync.The premise, measured
db16b94changes onlypackages/clientand the spec migration registry, and no server code.POST /analytics/queryanswersdeps.success(result)in objectstack'sdomains/analytics.tsfrom its first extraction (8f124a7b7, 2026-07-27, before 17.0.0 shipped on 2026-08-14) tomain. Every 17.x server therefore sends the same{ success, data }envelope. Only the client decides whether it is unwrapped:unwrapResponsestrips it at 17.3.0+, while 17.2.0 endedreturn res.json()(read in the installed 17.4.0dist/index.mjsand a packed 17.2.0 tarball). No server is dropped. The compatibility axis is the client range, and that is why the floor moves.git log -Son the unshallowed history):rowsanddata.data.rowscame from70cb62b85(2026-04-01): the post-unwrap and envelope forms of the one route.dataas an array andresultscame fromf25e6c288(2026-02-25). That commit targeted a rawGET /api/v1/analytics/{resource}fetch, whichd91f2e2a0replaced withclient.analytics.queryten minutes later, and the three branches were carried over without shape evidence.77fadbfcabefore 17.0.0) answered{ success, data: { rows, fields } }. No producer of this call site ever returned the other three shapes.analytics.metaandanalytics.explainhave no call sites in objectui.git grepfinds onlyanalytics.queryhere, with a positive control on the same pattern. In the installed 17.4.0 client,metaandexplainboth endreturn this.unwrapResponse(res), declaredAnalyticsMetadataResponse["data"]andAnalyticsSqlResponse["data"].analytics.queryis declared as a Promise ofAnalyticsResult(the generic is spelled out in words because GitHub strips angle-bracket spans).Surface beyond the claim, stated
The claim named only
index.ts(the ladder), the tests beside it and one changeset. Two extensions were needed:aggregate()'scatchplus the new error class. Without them the throw is silently answered by the fallback, which the pins require it must not be.packages/data-objectstack/package.json,apps/console/package.json, the twopnpm-lock.yamlspecifier lines andQUICK_REFERENCE.md. Leaving^17.0.0would publish a range this change makes false.scripts/__tests__/quick-reference-current-release-4143.test.tswent red on the adapter-only bump, because that row anchors both manifests. No open pull request holds these lines: fix(fields): lookup candidate queries expand the reference columns they display (objectui#10223) #10341 and chore(deps): lucide-react 1.31.0 -> 1.43.0, with the one retired spelling repaired #8941 touch the lockfile and the console manifest in disjoint hunks, and chore: release packages #5400 is the release pull request.isLegacyOverlayRowand the rest ofindex.tsare untouched.Seat amendment (2026-09-24T20:14Z). The seat accepted both extensions and widened the claim's File surface to match (claim comment
5820950909, edited). Line 2 now readsClause-②: yes, because the diff adds a public export (AnalyticsResultShapeError); a contract review is owed before enqueue. The changeset level moved frompatchtominorat heade6e26e35d(objectui precedent #9061 / #9175).Pins (site-scoped, new file)
packages/data-objectstack/src/aggregate-rows-post-unwrap-7028.test.ts, 7 tests:{ success, data: { rows } }wire envelope goes through the real client./api/v1/datais never requested. This is tested twice: through the real client (a success-less{ data: { rows } }body thatunwrapResponseleaves alone), and as the value a pre-17.3.0 client handed back.[].Verification (final head
52f5a6c21)pnpm --filter @object-ui/data-objectstack type-check: exit 0.--listFilesconfirms the new test file is in that program.pnpm exec vitest run packages/data-objectstack/from the repo root:Test Files 68 passed (68),Tests 933 passed (933).scripts/__tests__suite namingdata-objectstack,QUICK_REFERENCE,apps/console/package.jsonorpnpm-lock.yaml. Result:Test Files 27 passed (27),Tests 1137 passed (1137).eslint .in the package: 77 files linted (from--format json), 0 errors. Type-aware linting is off, so this diff cannot move any verdict in untouched files.check:control-bytes,check:new-line-citations(0 new),check-changeset-presence,check:changeset-claims,check:lockfile-integrity,check:lockfile-dedupe,check:installed-pin-claims,check:pending-changeset-literals,quick-reference:check.check:changeset-claimslists5793,6361and7122for namingpnpm-lock.yaml. I read each paragraph, and none is falsified by this diff.check:spec-floors: NOT MEASURED. It refuses on an unbuilt workspace (no-artifact), and it reads@objectstack/specfloors only, which this diff does not move.ablation-replace.mjs(anchor 1 to 0, blob0b7bc68a9ed1to3b936fc60bb8). Result:Tests 5 failed | 2 passed (7), with every failure beingaggregate() resolved; it was expected to throw AnalyticsResultShapeError. The two greens are the positive pin and the control. The restore is proven: blob equals HEAD0b7bc68a9ed1andgit diff HEADis empty.catchrethrow. Result: the same 5 fail and 2 pass, because the error is answered by the fallback. The restore is proven the same way../indeximport, so nodistleg applies.Acceptance notes
analytics.metaandanalytics.explainare not called anywhere in this repo, so they have nothing to tighten..changeset/7122-objectstack-family-17-3-0.mdstill says the branches were kept "rather than deleted" and frames the question as one about servers. It is true of its own change and will publish in the same release as this one, so the new changeset names it and supersedes it rather than editing it.aggregate-capability.test.tscase "a{ success, data: { rows } }envelope is still a result" stays green. It is the server's wire envelope, which the installed client unwraps. After this change it is a positive control, not tolerance.plugin-charts,plugin-dashboardandcomponentsreadaggregate()results through theDataSourceinterface and do not depend on this package. The only export-surface change is one added class:exportlines in the diff are+1 -0, and theaggregatesignature is untouched. No export-star re-export exists, and no other declaration of the name exists, so no importer's type-check input changes. The full workspace Type Check runs in CI.Session:
https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC(dev run dispatched by thedomain:uiseat 1).Generated by Claude Code