Repository navigation
feat(types): declare the filter/sort members both renderers read (objectui#8174) - #8788
Merged
os-bill merged 3 commits intoSep 9, 2026
Merged
Conversation
…ectui#8174) `ObjectKanbanSchema` declared no `filter`; `ObjectCalendarSchema` declared neither `filter` nor `sort` — while `@objectstack/spec` declares them (`ComponentPropsMap['object-kanban']` carries `filter`, `['object-calendar']` carries `filter` and `sort`), both plugins' registration `inputs` publish them (`plugin-kanban/src/index.tsx:523`, `plugin-calendar/src/index.tsx:400-401`, all `type: 'array'`), and both renderers read them (`ObjectKanban.tsx` `$filter: schema.filter`; `ObjectCalendar.tsx` `$filter: schema.filter` and `$orderby: convertSortToQueryParams(schema.sort)`). The declaration face of this package was the only one that stayed silent, so an authored value reached the renderer through `BaseSchema`'s `[key: string]: any` (`base.ts:467`) and the mirror's `.passthrough()` — admitted, never examined. That is verbatim objectui#7322's reasoning for moving `groupBy` and `limit` into this same interface. Spelled exactly as `ObjectGanttSchema` spells them (`filter?: any[]`, `sort?: SortConfig[]`, and the matching `z.array(z.any())` / `z.array(SortConfigSchema)` mirrors) so the views' query vocabularies cannot fork. Both members optional on both faces, so the mirrors stay at zero drift for these pairs. No `sort` on the kanban board, and the absence is measured rather than overlooked: `ObjectKanban.tsx` has ZERO `schema.sort` read sites and the spec's `object-kanban` entry declares no `sort` either. objectui#7927's ceiling is unchanged and is pinned rather than claimed away: a MISSPELLED key still rides the index signature on both faces. What declaring buys is the VALUE dimension — `filter: 'status = open'` and the objectui#8221-retired `sort: 'name asc'` move from "type-checks green, parses green, then silently drops at runtime" to refused at authoring time. Claude-Session: https://claude.ai/code/session_012W3vMLTFY9SPr2LyxhSeYi Co-authored-by: Claude <noreply@anthropic.com>
…ban-calendar-declare-filter-sort # Conflicts: # packages/types/src/zod/objectql.zod.ts
Additive on the type face and on the accept set; what changes verdict is a wrong-typed value at a correctly spelled key, which the index signature and `.passthrough()` used to admit unexamined. Claude-Session: https://claude.ai/code/session_012W3vMLTFY9SPr2LyxhSeYi Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ 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
|
os-bill
marked this pull request as ready for review
September 9, 2026 07:51
os-bill
deleted the
claude/issue-8174-kanban-calendar-declare-filter-sort
branch
September 9, 2026 08:09
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 #8174
ObjectKanbanSchemagainsfilter.ObjectCalendarSchemagainsfilterandsort. Both published faces of@object-ui/types— the TypeScript interface inpackages/types/src/objectql.tsand its hand-written zod mirror inpackages/types/src/zod/objectql.zod.ts.Re-measured on
fb0102271, not inherited from the card's9bfd618mainmoved a great deal between the filing and this branch, so every anchor below was re-derived; the card's:2744/:2698line addresses no longer hold.Member lists, pulled from the interface bodies — the full list per interface is its own control that the extraction works:
ObjectKanbanSchema(objectql.ts:2779-2900), 11 members:type,objectName?,groupBy,groupField?,limit?,titleField?,cardFields?,quickAdd?,coverImageField?,allowCollapse?,conditionalFormatting?— nofilter, nosort.ObjectCalendarSchema(objectql.ts:2733-2774), 8 members:type,objectName?,data?,staticData?,startDateField?,endDateField?,titleField?,defaultView?— nofilter, nosort.Read census —
schema.KEYoccurrences off disk, withobjectNameas the positive control that the query reaches the file:schema.filterschema.sortschema.objectNameplugin-kanban/src/ObjectKanban.tsxplugin-calendar/src/ObjectCalendar.tsxThe live sites:
$filter: schema.filteron the kanbandataSource.findand again in that effect's dependency list;$filter: schema.filterand$orderby: convertSortToQueryParams(schema.sort)on the calendar's, and both again in its dependency list.The other two faces, re-read rather than quoted:
@objectstack/spec17.3.0'sComponentPropsMapdeclaresfilteronobject-kanban(13 keys) andfilterplussortonobject-calendar(9 keys), and declares nosortonobject-kanban. Both plugins' registrationinputspublish the same set —plugin-kanban/src/index.tsx:523,plugin-calendar/src/index.tsx:400-401, alltype: 'array'.So the key had four declaration faces and this package's two were the silent ones. An authored value reached the renderer through
BaseSchema's[key: string]: any(base.ts:467, the interface's last member) and through the mirror's.passthrough()— admitted, never examined. That is verbatim objectui#7322's reasoning for movinggroupByandlimitinto this same interface, one key over.No
sorton the board, and the absence is measured rather than overlooked: zeroschema.sortread sites inObjectKanban.tsx, and the spec declares none either. Declaring it would be this repo inventing a key.The judgement the card delegated to the taker
The card asks whether this is worth the edit at all, or whether it should wait behind objectui#7927 — which measured that
BaseSchemaends in an index signature, so no annotation on any node schema catches a MISSPELLED key.Proceeding. The ceiling is real, and it caps a different dimension from the one this buys.
filter: 'status = open'type-checked green through the index signature and parsed green through.passthrough(); it is now a type error and a named refusal. That is a measurable acquisition, not editor completion.sorthalf is the sharpest case, and it is a live silent failure. objectui#8221 retired the legacy string clause:convertSortToQueryParamsno longer admits a string in its signature and returnsundefinedfor one after reporting the retired spelling (core/src/utils/sort-query.ts:133,141). Sosort: 'start_date asc'on anobject-calendarnode type-checked green, parsed green, and then drew an UNSORTED calendar with nothing refusing it anywhere. Declaring the member is what makes that retirement audible at the authoring boundary.BaseSchema, it tightens the KEY dimension — and a tightening that lands while these three members are still undeclared turns every correctly authoredfilter/sortnode into a refusal. Declaring them is a prerequisite for that card, not a duplicate of it.The pin, and the ablation that shows it can fail
packages/types/src/__tests__/kanban-calendar-filter-sort-8174.test.tsasserts membership on the mirror's own.shaperather than on parse acceptance — under.passthrough()acceptance cannot tell "declared" from "admitted unexamined". Type-level pins use invariant equality, so a member that fell back to the index signature reads asanyand therefore as a failure. A control key must stay undeclared on both faces, and a misspelling must stay admitted.That file IS compiled.
packages/types' package tsconfig excludes the test tree, buttype-checkruns a third program,tsconfig.test.json, that includes it — verified with--listFilesrather than assumed: the pin is line 413 of that program's file list and absent from the main program's.Three ablation legs. Each proved the mutation reached disk before its run was read, and each restored, with the restore proved by an empty
git diff HEADand a hash equal to the HEAD blob:ObjectCalendarSchema.sortfromobjectql.ts(anchor count 4 to 3)@ts-expect-error(the retired string clause, and the badordervalue)sortfrom the calendar mirror (anchor count 4 to 3)tscinsteadzod-mirror-parity.test.tsTS2322, that pair not assignable toneverLeg 3 is the one worth reporting. Leg 2 alone would have read as "the mirror half is covered only by my own new file", because the parity ledger stayed green under vitest. It is not: the ledger's unmirrored-declared half is a TYPE-level operator, so it lands on
tscand not on the test runner. The mirror edit is mandatory rather than a courtesy — and mandatory in a way a vitest-only run cannot see.A first attempt at leg 1 was a no-op: the slice anchor was off by one newline, nothing changed on disk, and the script's own before/after count refused to run the leg. Reported because the failure mode it caught is exactly the one that otherwise reads as a passing ablation.
Nothing in the parity ledger needed editing: mirroring at the same requiredness as the interface — both optional on both faces — leaves it at zero drift for these pairs.
__tests__/zod-mirror-parity.test.tsis untouched, as arezod/layout.zod.ts,zod/form.zod.ts,layout.tsandform.ts, all held by PR objectui#8763.Gates
Run in this worktree at
a9c30cb, on a merge oforigin/mainfb0102271. Exit codes captured by redirecting first and reading the status after, never through a pipe.pnpm --filter @object-ui/types type-check(all three programs)pnpm exec vitest run packages/types/from the repo rootpnpm exec vitest runover plugin-kanban, plugin-calendar, the console registry/spec parity file and the two app-shell block-config filespnpm --filter @object-ui/types buildpnpm --filter @object-ui/types lintnode scripts/check-changeset-fixed.mjsnode scripts/check-changeset-no-major.mjsnode scripts/check-control-bytes.mjsnode scripts/check-spec-symbol-derivation.mjsnode scripts/check-doc-component-types.mjsnode scripts/check-unreferenced-sources.mjsnode scripts/check-element-data-source-declaration.mjsnode scripts/check-governed-queue-guard.mjs --testover the four changed pathsFour whole-tree scans returned a prerequisite complaint instead of a verdict, because they need every package built and this worktree builds only the affected one:
check:doc-snippets,check:doc-examplesandcheck:sdui-registration-pins(exit 2 each, each printing the build it wants), andcheck:readme-exports(exit 1, its own message being "runpnpm buildfirst" for five documented types across four packages, followed by a collapsed-population report). Those read here as NOT MEASURED, not as green and not as red; they belong to CI, which builds the tree.Scope
Additive only: 4 files, +486 / −0, all inside the claimed surface. The changeset is
minorfor@object-ui/types— the accept set only widens, but a wrong-typed value at a correctly spelled key changes verdict, which is more than a patch.majoris refused bycheck-changeset-no-major, andskip-changesetdoes not apply becausepackages/typesships these declarations.BaseSchema's index signature is untouched — that is objectui#7927. No other undeclared member on these two interfaces was touched: objectui#7742 and objectui#7780 are censuses over the same two interfaces on different keys, and they are not this card.Merge posture
DRAFT, and it stays draft. Clause-② applies — this adds declared members to a published interface — so it carries
needs:contract-reviewand a ceiling review runs before it may be enqueued. Not flipped ready, not enqueued, no auto-merge.Session:
https://claude.ai/code/session_012W3vMLTFY9SPr2LyxhSeYiGenerated by Claude Code