feat(core)!: retire the legacy string sort clause — one spelling, the array (objectui#8221) - #8758
Conversation
…he array `convertSortToQueryParams` drops the string arm (objectui#8221, director ruling, decision batch #77, option B). Its signature narrows to `QuerySortEntry[]`, and a string that still reaches it at runtime is REFUSED with a `console.error` naming the array form, quoting what arrived and stating that the query carries no `$orderby` — never a silent drop. Every declaration that published a string arm narrows with it, TypeScript face and zod mirror together: `ObjectGridSchema.sort`, `ObjectMapSchema.sort`, `ObjectGanttSchema.sort`, plus the local `sort` inputs on `LineItemsPanel`, `ObjectTimeline` and `deriveRelatedLists`'s ListView reader. Docs teach the array only. Deliberately untouched, measured rather than assumed: `record:related_list`'s `'field'` / `'-field'` string is a DIFFERENT dialect, normalized by `RelatedList.normalizeSortSpec`, and never reaches this sink. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
… and re-key the moved doc-example ledger row
`examples/schema-catalog/src/schemas/plugin-view/object-view-list.json` authored
`table.sort: "name asc"` — the retired clause. `pnpm check` reported it by name
("did not validate as an ObjectUI schema"), and `objectui validate` gave the
reason: `table -> sort` expected array, received string. Migrated to
`[{ "field": "name", "order": "asc" }]`; the warning count moved 4 -> 3, which
is the firing control that the fixed file is the one that moved.
`scripts/check-doc-example-types.mjs`'s ledger is keyed by FILE:LINE, and the
`objectql.ts` edits shifted `ObjectFormSchema`'s example block 1604 -> 1607.
Re-keyed; `scripts/__tests__/check-doc-example-types.test.ts` is green again.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
✅ 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
|
Final consolidated readings, taken after the last commit (
|
Ceiling contract review: PASS — clearing the carrier and enqueueing. ⛔ But §6 of the body carries one sentence that is FALSE, and it is corrected here rather than merged unchallenged
⛔ The false sentence§6 states:
The second half does not hold. Measured by the ceiling reviewer through the real
⭐ It changes the scope of the follow-up, ⛔ not the verdict. Nothing this PR ships is wrong; the escalation was correct and the reviewer's judgement is that the asymmetry is a separate card rather than incoherence here — the ruling names the helper, its signature and the docs, ⛔ not ObjectGrid's private lowering, and closing it rewrites ≥4 pinned wire-shape tests. Landing bar, each item measured
⭐ Two findings the review added that the body did not claim, recorded so they are not lost: the retirement also refuses ⇒ Carrier cleared on both card and PR, draft flipped, enqueued. ⛔ Not hand-merged; ⛔ this seat never merges its own lane's PRs — the queue lands it. Generated by Claude Code |
…rid's own read site (objectui#8767) `ObjectGrid` reads `schema.sort` and lowers it with PRIVATE code, so PR #8758's narrowing of the shared sink `convertSortToQueryParams` never reached it: after that PR a bare `object-grid` still forwarded a runtime string verbatim to `$orderby`, while the SAME key routed through `object-view` was refused with a diagnostic. One key, two meanings, chosen by which block you are on — the per-block divergence the objectui#8221 ruling declined by name. Route C, as ruled by the maintainer 2026-09-10: keep the wire shape, refuse the string. The string arm now calls the shared sink for its refusal alone — that reporter names the offending spelling once per spelling and answers `undefined`, so the query carries no `$orderby` — and the return value is deliberately unused, because the array arm keeps lowering to this block's own `"field order"` join string. Route B (routing the whole key through the sink, which would send its `{field: direction}` map instead) was explicitly not taken; the export path and the header-arrow reader `parseSchemaSort` are untouched. - `gridRetiredStringSort-8767.test.tsx` pins BOTH halves, so the pin cannot pass by refusing everything: a string reaches no `$orderby` and reports once per spelling; the array arm still emits `'name desc'` and `'status asc, name desc'` with no diagnostic. - `serverSorting.test.tsx`'s "replaces the declared sort" case authored the retired string and asserted it went out verbatim — that assertion is this card's own subject, so its fixture is re-authored in the declared array spelling and its #3106 subject is preserved. - Two comments this change falsifies are corrected, comment-only: the `parseSchemaSort` docblock no longer claims the fetch path reads all three spellings, and both it and the header-arrow read site now record that this reader is WIDER than the fetch path and that closing the gap is route B. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
… (objectui#8961) Executes the maintainer ruling of 2026-09-15, director batch #135 item 5, letter A. Not a decision; execution. ## What a user saw A view authored `sort: "name desc"` lit a descending arrow on the `name` header before anyone clicked anything, while the query that fetched those rows carried no ordering at all. The arrow stated something about the list that was not true of the rows beside it, and the first click on that column then asked for `asc` on a list that was in no declared order. The only signal was a `console.error` no end user reads. ## Why the two halves disagreed objectui#8221 retired the legacy string clause — one spelling, the array, everywhere — and objectui#8767 (route C) made this block's fetch path REFUSE a string `sort` and send no `$orderby`. That ruling deliberately left the other reader of the same key alone: `parseSchemaSort`, which feeds the header indicators, went on parsing `"name desc"` and `["name desc", ...]`. One key, two readers, opposite answers. ## What this does `parseSchemaSort` admits only `[{ field, order }, ...]` — the spelling `@objectstack/spec` declares for `ObjectGridPropsSchema.sort` and the only one the fetch path still lowers. A retired string yields nothing, so it lights no arrow. The refusal is per entry: a mixed array still lights the arrows for the keys spelled in the declared form. No second diagnostic is added. The author is already told once per spelling by PR #8758's reporter at the fetch path, which quotes the offending value and prescribes the array form; a second voice here would only restore the arrow the wire cannot honour. ## What is deliberately unchanged The wire shape. The array arm still lowers to this block's own `"field order"` join string; routing the key through the shared sink's `{field: direction}` map is route B on objectui#8767, which stays declined until the protocol declares that shape. Measured while here: the server-side export path reads `schema.sort` itself rather than through `parseSchemaSort`, so it was already array-only and does not move — the retired docblock claim that narrowing this reader "takes the export path with it" was not borne out. ## Pins, both directions `serverSorting.test.tsx`: the declared array lights the arrow (the case that already existed); a retired string lights NEITHER direction while the query carries no `$orderby` and the one diagnostic still fires once. That case previously pinned the divergence — the arrow drawn beside an empty query — so the arrow half is what flips. Its non-vacuity control is the neutral sort indicator, still rendered, so "no arrow" cannot pass by the column having quietly stopped offering sorting. The unit block re-judges every spelling it used to admit, each refusal paired with a declared-array control. `gridArrayArmOrderby-8973.test.tsx`'s docblock cited this card by a label that had already moved; it now names the ruling, which does not move. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCpmqvacV4BypY48QdoxcE
…rid's own read site (objectui#8767) (objectstack-ai#8960) * fix(plugin-grid): refuse the retired string `sort` clause at object-grid's own read site (objectui#8767) `ObjectGrid` reads `schema.sort` and lowers it with PRIVATE code, so PR objectstack-ai#8758's narrowing of the shared sink `convertSortToQueryParams` never reached it: after that PR a bare `object-grid` still forwarded a runtime string verbatim to `$orderby`, while the SAME key routed through `object-view` was refused with a diagnostic. One key, two meanings, chosen by which block you are on — the per-block divergence the objectui#8221 ruling declined by name. Route C, as ruled by the maintainer 2026-09-10: keep the wire shape, refuse the string. The string arm now calls the shared sink for its refusal alone — that reporter names the offending spelling once per spelling and answers `undefined`, so the query carries no `$orderby` — and the return value is deliberately unused, because the array arm keeps lowering to this block's own `"field order"` join string. Route B (routing the whole key through the sink, which would send its `{field: direction}` map instead) was explicitly not taken; the export path and the header-arrow reader `parseSchemaSort` are untouched. - `gridRetiredStringSort-8767.test.tsx` pins BOTH halves, so the pin cannot pass by refusing everything: a string reaches no `$orderby` and reports once per spelling; the array arm still emits `'name desc'` and `'status asc, name desc'` with no diagnostic. - `serverSorting.test.tsx`'s "replaces the declared sort" case authored the retired string and asserted it went out verbatim — that assertion is this card's own subject, so its fixture is re-authored in the declared array spelling and its objectstack-ai#3106 subject is preserved. - Two comments this change falsifies are corrected, comment-only: the `parseSchemaSort` docblock no longer claims the fetch path reads all three spellings, and both it and the header-arrow read site now record that this reader is WIDER than the fetch path and that closing the gap is route B. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w * fix(plugin-grid): repair two false contract claims in the changeset, and pin the arrow-vs-wire divergence instead of freezing it green (objectui#8767) Contract review VERDICT: REWORK, two bounded items. The refusal mechanism, the control pins, the `minor` grading and objectui#8961's parking are judged correct and are untouched — `ObjectGrid.tsx` is byte-identical to the reviewed head. R1 — the changeset body carried two sentences that are false about the contract: - "the only one `@objectstack/spec` accepts". Measured against the installed `@objectstack/spec@17.4.0`: `ui.ObjectGridPropsSchema.sort` is `z.unknown().optional()`, so `safeParse` PARSES `'name desc'`, `'name'`, `42`, `['name desc']` and `{ name: 'desc' }` alike, while an undeclared `bogusProp` is REFUSED with `unrecognized_keys` — the control that shows those readings are real. The protocol's validator does not refuse the string. What the protocol DECLARES is the array, in three places: the key's own `describe` ("Initial sort (array of { field, order })"), the sibling `ElementRecordPickerPropsSchema.sort` typed as `z.array(SortItemSchema)` (which refuses a string outright), and the `defaultSort` retirement text ("wrap the value in an array"). The sentence is now a claim about what the protocol declares, which is true, rather than about what it accepts. - "(`order` is optional and means `'asc'`)". `SortConfig.order` is REQUIRED in `@object-ui/types` and in its zod mirror, and the protocol's `SortItemSchema` requires it too (measured: it refuses `[{ field: 'name' }]` with `invalid_value` at `0.order`). Worse, this block's untouched array arm interpolates whatever is there, so an omitted `order` lowers to `$orderby: 'name undefined'`. The changeset now says both keys are required and names that behaviour; the defect itself is pre-existing, is NOT widened into this diff, and is filed as a successor card. R2 — `serverSorting.test.tsx` had a defect frozen green at the arrow case: - its fixture is re-authored in the declared array spelling, the same principle this PR already applied to the sibling case; - the string's behaviour is now an EXPLICIT pin naming objectui#8961, asserting both halves — the arrow is drawn AND the query carries no `$orderby` AND the disagreement is announced once. A test that asserted only the arrow was a green certificate that the state is intended, not a record of a divergence; - the `parseSchemaSort` describe title ("the header reads what the fetch path reads") was falsified by this PR and is renamed to say what that block actually pins: the reader's own contract, wider than the fetch path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w --------- Co-authored-by: Claude <noreply@anthropic.com>
… (objectui#8961) (objectstack-ai#9604) Fixes objectstack-ai#8961 Executes the maintainer ruling of 2026-09-15 — director batch objectstack-ai#135 item 5, 「135 同意」, **letter A** (objectui#8961 comment 5682605192). Not a decision; execution. ## What a user saw A view authored `sort: "name desc"` lit a descending arrow on the `name` header **before anyone clicked anything**, while the query that fetched those rows carried no ordering at all. The arrow stated something about the list that was not true of the rows beside it, and the first click on that column then asked for `asc` on a list that was in no declared order. The only signal was a `console.error` no end user reads. ## Why the two halves disagreed objectui#8221 retired the legacy string clause — one spelling, the array, everywhere. objectui#8767 (route C) made this block's fetch path REFUSE a string `sort` and send no `$orderby`, and deliberately left the other reader of the same key alone: `parseSchemaSort`, which feeds the header indicators, went on parsing `"name desc"` and `["name desc", ...]`. One key, two readers, opposite answers. ## What this does `parseSchemaSort` admits only `[{ field, order }, ...]` — the spelling `@objectstack/spec` declares for `ObjectGridPropsSchema.sort` (read from the installed `@objectstack/spec@17.4.0`, not copied from the order) and the only one the fetch path still lowers. A retired string yields nothing, so it lights no arrow. The refusal is **per entry**: a mixed array still lights the arrows for the keys spelled in the declared form. No second diagnostic is added: the author is already told once per spelling by PR objectstack-ai#8758's reporter at the fetch path, which quotes the offending value and prescribes the array form. A second voice here would only restore the arrow the wire cannot honour. Route B remains declined and untouched — this diff routes nothing through `convertSortToQueryParams` and moves no wire shape. ## Pins, both directions - `serverSorting.test.tsx` — declared array lights the arrow (the case that already existed, unchanged); a retired string lights **neither** direction while the query carries no `$orderby` and the one diagnostic still fires exactly once. That case previously pinned the divergence (arrow drawn beside an empty query), so the **arrow** half is what flips; the wire half stays asserted because "no arrow" is only right while the query really carries no ordering. - Non-vacuity control in that case: the neutral sort indicator is still rendered, so the two "no arrow" nulls cannot pass by the column having quietly stopped offering sorting. - The unit block re-judges every spelling it used to admit (bare string, array-of-strings, mixed array), each refusal paired with a declared-array control, single- and multi-key. - `gridArrayArmOrderby-8973.test.tsx`'s docblock cited this card by a **label** that had already moved twice; it now names the ruling, which does not move. ## Reverse verification (one-off, not left in the tree) From the committed fix, `parseSchemaSort`'s narrowed body was reverted to its pre-fix form on disk and the pins re-run, then restored. Mutation and restoration were each proven on disk by occurrence counts, not by an editor's exit code. Numbers and the head they were taken at are in the report on objectui#8961. ## Gates and tests Commands, exit codes and the ratchet-bearing runs are listed in the report comment on objectui#8961. Repo-wide scans (`pnpm lint`, the full `pnpm test`) are CI's run, not this branch's claim. ## Measured while here, out of scope The docblock this diff replaces claimed that narrowing this reader "takes the export path with it". It does not: the server-side export path reads `schema.sort` itself (`Array.isArray(schemaSort)`), never through `parseSchemaSort`, so it was already array-only and does not move. The new docblock says so. ## Acceptance notes - `plugin-view`'s `ObjectView.tsx` carries a cross-package comment quoting this function's old opening line verbatim (`typeof sort === 'string' ? [sort] : ...`). Its load-bearing conclusion — a bare object yields an empty list — is still true; the quoted opening is not. Left untouched: that file is outside this claim's declared surface. Noted, not filed; the successor is whoever next edits that sort block. - The server-side export path maps an array of retired strings to an empty `sort` array rather than omitting the key (the entries are filtered out, the empty array is still sent). Pre-existing, unrelated to the arrow, not filed. --- _Generated by [Claude Code](https://claude.ai/code/session_01VCpmqvacV4BypY48QdoxcE)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #8221
Director ruling, decision batch #77 (2026-09-07), option B, recorded at issue comment
5567944420: the legacy stringsortclause is retired. One spelling, the array. Option A (per-block string arms) was rejected by name.⛔ Draft on purpose, and it stays draft. Clause ② is
yeson this card (an accept set moves on published@object-ui/core), so under the enqueue bar written today this PR is built at the default tier and gated by a ceiling-tier contract review before it may be enqueued. This seat has not flipped ready, has not enqueued, has not armed auto-merge, and has not touched theneeds:contract-reviewlabel — that carrier is already on the card.1. What changed
packages/core/src/utils/sort-query.tsconvertSortToQueryParamsdrops the string arm; signature narrows toQuerySortEntry[]; docblock rewritten; a string that still arrives at runtime is refused with a diagnostic naming the array formpackages/types/src/objectql.tsObjectGridSchema.sort,ObjectMapSchema.sort,ObjectGanttSchema.sortnarrow toSortConfig[]packages/types/src/zod/objectql.zod.tsz.uniontoz.array(SortConfigSchema)— TS face and mirror move togetherpackages/app-shell/src/utils/deriveRelatedLists.tslist.sortnarrowspackages/plugin-form/src/LineItemsPanel.tsx,packages/plugin-timeline/src/ObjectTimeline.tsxsortinputs narrowcontent/docs/plugins/plugin-map.mdx,content/docs/plugins/plugin-view.mdx,packages/plugin-view/README.mdteach the array onlyexamples/schema-catalog/src/schemas/plugin-view/object-view-list.jsonauthored the retired clause; migratedscripts/check-doc-example-types.mjsledger row re-keyed (its key is FILE:LINE andobjectql.tsgrew three lines)2. The surface, re-derived on this head — and it differs from the dispatched list
git grep -nE "sort\??:\s*string\s*\|"on1492fc30, plus the zod unions (which that pattern cannot see) and the sevenconvertSortToQueryParamscall sites, enumerated rather than searched for by spelling:Population differs in two directions. One hit the dispatched list did not carry (a stale comment in a plugin-view test), and — the load-bearing one — two of its hits are a different string dialect entirely and are deliberately left alone. §6.
Call sites of the helper — seven, as the card said, all still compiling after the narrowing:
Workspace
type-checkis green across all 81 tasks, which is the check that every call site still compiles.3. The accept set, MEASURED — against the built
dist, every refusal paired with a working controlProbe imported
packages/core/dist/utils/sort-query.js(the published face, notsrc) and countedconsole.errorcalls:"name desc"undefined"name asc"undefined"name"undefined"name DESC"undefined" "undefined[{"field":"name","order":"desc"}]{"name":"desc"}orderomitted[{"field":"name"}]{"name":"asc"}[{stage,asc},{amount,desc}]{"stage":"asc","amount":"desc"}""undefinedundefinedundefined42undefined{"name":"desc"}undefinedWhat a caller can no longer pass: the first four rows. Before this PR each of them lowered — the assertions deleted from
packages/core/src/utils/__tests__/sort-query.test.tsatf6205c10state exactly that ('name desc'→{name:'desc'},'name asc'→{name:'asc'},'name'→{name:'asc'},'name DESC'→{name:'desc'}), and those assertions were green onmain.The controls are what make the four refusals a verdict: a sink that refused everything would satisfy them and fail the eight rows below.
""is falsy and short-circuits on the!sortguard before any spelling is inspected, so it stays silent (it means "nothing was authored")." "is truthy, so it is a string and is reported. Both wereundefinedbefore this PR too; only the diagnostic is new.4. The runtime string — the case the types cannot stop, and its pin
Types are erased. A JSON document, a stored metadata row, or an
as anybag still reaches the sink carrying"name desc", and that path is live in this repo today:deriveRelatedListsreadsobject.list.sortfrom platform view metadata through a cast.What happens now, pinned end to end rather than asserted:
undefined, so the query carries no$orderby;console.errorfires once per spelling (module-state dedupe, the house formreportRetiredFieldTypealready uses, with an exportedresetRetiredSortSpellingReports()test seam);console.errorand notwarn, and not dev-gated: this refuses an authored row order, so the page renders in a different order than the author asked for — the same severity class asreportRetiredFieldType, which is also unconditional.Pins, five files:
packages/core/src/utils/__tests__/sort-query.test.ts— refusal, message content, once-per-spelling with a different-spelling control, and silence for values that were never the clause (with a firing control on the same spy);packages/types/src/__tests__/sort-string-arm-retired-8221.test.ts(new) — the three zod mirrors refuse the clause and still accept the array; type-level equality on both the interface face and the mirror'sz.inputface;packages/app-shell/src/utils/__tests__/deriveRelatedLists.inheritSort.test.ts— the inherit boundary refuses and reports; the seven charactersseq_no descstill never travel as a field name;packages/app-shell/src/views/RecordDetailView.relatedListInheritedSort-5795.test.tsx— the same, end to end on the wire, with the parent scope and$topas live controls that the query really ran;packages/plugin-view/src/__tests__/ObjectView.sortSink.test.tsx—table.sortrefused at the real read site, with the array arm on the same read site as the control.5. Ablation — the pin reddens, and the restore is proven by hash
Mutation: delete the reporter call, keep the refusal (i.e. restore the silent drop). Predicted direction before running: reddens, and specifically only on the diagnostic assertions.
Run from a script carrying
trap restore EXIT INT TERMwith an absoluteREPO_ROOT; restore isgit checkout HEAD -- path(never the bare form, which takes the polluted index) and is verified by blob hash againstHEAD, an emptygit diff HEADfor the path, and grep counts back to 1 and 0. Re-run after restore: 6 files, 86 tests, all green.The 24 that stayed green under ablation include every
toBeUndefined()refusal assertion — which is the point: the pins are about the diagnostic, not merely about the refusal, and a silent drop cannot satisfy them.distpreflight applies to this ablation and none was faked: the root vitest config aliases@object-ui/coretopackages/core/src(vitest.config.mts:498), so every one of those pins resolves to source. Thedistmeasurement is §3, which imports the built file directly.6. Deliberately NOT touched — measured, not assumed
Two hits on the dispatched surface list belong to a different string dialect.
packages/types/src/record-components.ts:172andpackages/plugin-detail/src/synth/buildDefaultPageSchema.ts:211arerecord:related_list.sort, whose string arm is the OData-ish'field'/'-field'form. It is read byRelatedList.normalizeSortSpec(packages/plugin-detail/src/RelatedList.tsx:261-275), a normalizer of its own, and it never reachesconvertSortToQueryParams. Retiring it is not what was ruled, and would delete working behaviour with no ruling behind it. Both were narrowed, measured, and reverted byte-identically (blob hashes verified againstHEAD) once the dialect was established.The spec still accepts the clause where the platform, not this repo, is the producer. Measured on
@objectstack/spec@17.3.0with controls on the same call:'name desc'[{field,order}]42ListViewSchemasort/invalid_unionbogusProprefused by nameRecordRelatedListPropssort/invalid_unionbogusProprefused by nameElementDataSourceSchemainvalid_typebogusProprefused by nameObjectGridPropsSchema/ObjectCalendarPropsSchemabogusProprefused by name⇒ a platform view record carrying
sort: 'name desc'is still spec-legal today and stops being inherited by a derived related list after this PR — loudly, which is the whole reason the diagnostic exists. The spec-side pull-back is its own card; the ruling's item 4 already routes that class toobjectstack.plugin-list'sListView.parseSortConfigreads that same spec-blessed slot and is untouched.packages/plugin-grid/src/ObjectGrid.tsx:1852-1858lowersschema.sortitself — it does not use the shared sink, and it forwards a runtime string to$orderbyverbatim (for the array arm it emits a comma-joined"field order"string). So after this PR a bareobject-gridstill honours the retired spelling at runtime while the same key throughobject-viewis refused. That state is not introduced here (the two paths already differed), but it is the "one key meaning different things on different blocks" the ruling rejected, and closing it changes the$orderbywire shape for every grid — a behaviour change well beyond this card. Reported to the PM rather than taken.packages/plugin-calendar/src/ObjectCalendar.tsx:76declaressort?: any, which is wider than the retired union, so the narrowing does not reach calendar's local face. Noted, not filed.STRING_ARM_REGISTERED_TYPESexported by@objectstack/specis a false friend — it is the ledger for the component TYPE union's open string arm (record:line_items), nothing to do withsort. objectui references it nowhere.7. Changeset, and how it was graded
.changeset/8221-retire-legacy-string-sort.mddeclares seven released packages.@object-ui/coreisminor, notmajor— the rule applied is AGENTS.md 版本号策略 line 240, verbatim: objectui's own breaking changes are scoredminorwith the breaking semantics written in the body, because every package sits in one fixed group and a singlemajorwould carry all of them off the@objectstackmajor this repo is pinned to.scripts/check-changeset-no-major.mjsenforces it. The breaking semantics are in the changeset body.8. Gates — command, exit code, and what it printed
turbo run build --filter=!@object-ui/site --concurrency=2turbo run type-check --concurrency=2 --continuetype-checkincludes itstsconfig.test.jsonlegpnpm exec vitest run(repo root, path filters)turbo run linton the seven touched packagesnode scripts/check-changeset-presence.mjsnode scripts/check-changeset-no-major.mjsmajordeclarednode scripts/check-changeset-fixed.mjspnpm check:control-bytespnpm checkpnpm check:doc-types/:doc-fences/:doc-snippets/:readme-exports/docs:check-linkscheck:*gatesci.ymlruns per PR, plustype-check:scriptsnode scripts/check-governed-queue-guard.mjs --teston all 25 pathsnode scripts/check-doc-example-types.mjsmain, zero delta from this branch — see belowOn that last one. Measured in a separate detached worktree at the merge base
f6205c10, installed and built with the command the gate itself prescribes: the gate exits 1 there too, with exactly the same single failure (packages/types/src/zod/imported-defaults.ts:318 stripImportedDefaults, TS2304), which arrived with PR #8721 two hours before this branch. Filed as #8757. This branch adds no new failure to it, and it had to touch that file only to re-key a FILE:LINE ledger row its own diff moved. The gate is inpackage.jsonand in no workflow, so CI never runs it — measured here or nowhere.9. Test batches, with their real numbers
packages/core/ packages/types/packages/app-shell/ packages/plugin-form/ packages/plugin-timeline/ packages/plugin-map/packages/plugin-view/ packages/plugin-grid/ packages/plugin-list/ packages/plugin-detail/ packages/plugin-calendar/ packages/plugin-gantt/packages/plugin-view/ apps/console/ examples/ scripts/Every first-round failure was a fixture or pin that named the retired arm, and every one was triaged rather than batch-rewritten: three files had the spelling changed because the string was only a vehicle; four had pins replaced because what they pinned was the arm that is gone. Vitest was run from the repository root throughout, so objectui#3378's guard is satisfied — each run printed
RUN v4.1.10 /home/user/objectui-issue-8221.10. NOT MEASURED
Build Docs,check:node-esm-load,check:published-dist— not per-PR gates, and not run here.pnpm testin full (all 4 CI shards) — the packages this diff can reach were run above; the remainder (components,react,fields,layout,i18n,data-*,mobile,providers,permissions,auth,collaboration) contain no reference toconvertSortToQueryParamsor to the narrowed declarations, and workspacetype-checkis green across all 81 tasks. CI runs the full sharded suite.test:dist,test:e2e,test:e2e:live,performance-budget— not run here.ObjectGridstring path (§6) is acceptable — not decided here; it needs a ruling, and it is reported rather than taken.check:doc-examplesshould join a workflow — named in decision(ci):check:doc-examplesis declared in package.json and run by no workflow — wire it, or record that it is hand-run only #8757, not decided here.Session for this implementation:
https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w🤖 Generated with Claude Code
https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
Generated by Claude Code