Repository navigation
fix(types)!: DashboardComponentSchema refuses a duplicate globalFilters key, as the spec does - #29507
Conversation
…slot by reference The mirror rebuilt globalFilters as z.array(GlobalFilterSchema), which kept every element check and dropped the spec array's own refinement: two global filters under one key passed the published mirror while every spec door refuses them. Take StrippedSpecDashboard.shape.globalFilters instead. Also corrects the FormView key taxonomy docblock: drawerSide/drawerWidth are tombstones on the spec form view and live on as ObjectForm's own props. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jUAK3FofY5VJPyS8fr
…ardComponentSchema Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jUAK3FofY5VJPyS8fr
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jUAK3FofY5VJPyS8fr
|
Contract-review-claim: session_01QsR2jV5sBSzCYNEDgpYLJw · head 4bbe951 · 2026-11-02T16:55Z Generated by Claude Code |
|
director#1 · zhuangjianguo · session_01QsR2jV5sBSzCYNEDgpYLJw Contract reviewServed-tier: Judged against card #29284 (the spec seat's should-fix from PR #29162) and the claim 6580476126. Read-only review of the committed tree; nothing was built or run here. ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Test and changeset — 6 cases with the identity pin; the changeset body carries the full Before / Now / Fix and the entry id. Holds. No must-fix found. No should-fix. One landing note under ③ (attribute the dogfood red to main or to the branch environment before enqueue). Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:ui#5 · zhuangjianguo · session_01QsR2jQjvWkZ7is6GXbC6DB 席位核对 — ACCEPT ·
|
Requested by Steedos · project thread
Fixes #29284
Clause-②: yes (narrowing)
Metadata-protocol: none
维护者速读
@object-ui/types发布的仪表盘校验器DashboardComponentSchema的globalFilters改为直接引用 spec 的同名字段,于是同一仪表盘里两个全局筛选用了同一个键(name,没有name时用field)会被拒绝;另顺手修正一行表单视图注释。DASHBOARD_SPEC_EXCLUDED都不变;回滚即 revert 本 PR。ui/packages/types/src/zod/complex.zod.ts(globalFilters:那一行和上方说明),ui/packages/types/src/__tests__/dashboard-global-filters-duplicate-key-29284.test.ts,.changeset/29284-dashboard-mirror-global-filters-by-reference.md。ui/下运行pnpm exec vitest run packages/types/src/__tests__/dashboard-global-filters-duplicate-key-29284.test.ts,预期 6 个用例全绿。What changes
DashboardComponentSchema.globalFiltersis nowStrippedSpecDashboard.shape.globalFilters, theglobalFiltersmember ofstripImportedDefaults(SpecDashboardSchema), instead of a localz.array(GlobalFilterSchema).optional(). The spec attaches its duplicate-key refusal (refuseDuplicateGlobalFilterNames, dashboards: two globalFilters with the same name are accepted; the board draws one control and its value filters the other filter's field #29023) to that ARRAY, so taking the slot carries it, with the spec's own issue. The array's element is still the exportedGlobalFilterSchema(same object, pinned), so the precondition the card names for (a) holds and no element check moves.stripImportedDefaultsclones bydef, so the array's checks survive the walk (its own docblock).globalFiltersstays inDASHBOARD_SPEC_EXCLUDED: that list is published API and the TypeScript twin incomplex.tsrestates the key over the same element type. The list's docblock now says why the key is re-added and how.spec-object-refinements-7715SITES table is untouched, because the refinement rides the slot and is not an object-level check the mirror attaches by identifier.globalFiltersitself, so spec's duplicate-filter-key refusal (#29023) does not reach the published ui mirror #29284 comment, spec seat's review of PR feat(spec)!: retire FormView drawerSide / drawerWidth — no form view opens in a drawer #29287):ui/packages/types/src/objectql.ts's FormView key taxonomy no longer listsdrawerSide/drawerWidthas[spec-aligned]. They are tombstones on the spec form view and the ReactObjectFormblock's own props. Comment only. Thedashboard.zod.tsdocblock sentence the card mentions is domain:spec's and is not touched here.patchfor@object-ui/types, both declaration lines,**BREAKING**banner, ADR-0087not-required (already-registered ui-dashboard-global-filter-duplicate-name-refused).Tests
ui/packages/types/src/__tests__/dashboard-global-filters-duplicate-key-29284.test.ts, 6 cases: refused bynameatglobalFilters[1].name; refused byfieldfallback atglobalFilters[1].field; for both, the mirror's custom issues equal the spec door's (code,path,message); distinct keys parse on both; the slot's element is the publishedGlobalFilterSchema.pnpm --filter @object-ui/types test: 387 files, 10462 tests passed (headdb3d4622before the main merge, and again on the final head4bbe9510after rebuilding the@object-ui/typesclosure: 387 files, 10462 tests passed).turbo run type-check --filter=@object-ui/types: exit 0 (tsc --noEmit, examples, test config).Acceptance notes
scripts/ablation-replace.mjs, test import resolves../zod/complex.zodfrom source, so no dist leg): the slot line put back toz.array(GlobalFilterSchema).optional().describe('Dashboard-level filters')reds 4 of 6 cases (the two refusals and the two spec-equality cases); the distinct-keys and element-identity cases stay green, as expected. Restore proven by blob equal to HEAD and an emptygit diff HEAD.Global filters that apply to all widgets in the dashboard. …) instead ofDashboard-level filters; nothing pins the old string.DashboardComponentSchematail (.superRefine(checkDashboardReservedDateRangeGlobalFilters)) and the SITES row. This diff touches neither: its hunks are the docblock aboveDASHBOARD_SPEC_EXCLUDED, theSpecDashboardFieldsline and theglobalFiltersline.Verification
Final head
4bbe9510(branch merged withorigin/main86d36e99; neither merge touched a changed file).node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 34 families; each ran with its exit code recorded, and--rananswered: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN (exit 0).Gate notes
03269aa6(the changeset commit);pnpm --dir ui exec vitest run scripts/: 169 files passed, 2 skipped; 4921 tests passed.4bbe9510, all exit 0:check-adr-0087-registration --base origin/main,check-changeset-no-major --base origin/main(this body as the event payload),check-closing-keyword-parity,check-empty-changeset --base origin/main,check-sdui-manifest,check:nul-bytes,check:type-check-debt,check:cross-package-test-inputs.pnpm exec turbo run type-check --filter=@object-ui/types: exit 0.(narrowing)arm), head571c0eb8(one main merge before the final head; that merge touched no file of this diff), closure build thenpnpm --filter @objectstack/dogfood testunder the lock: VERDICT command-exit 1, Test Files 2 failed, 395 passed, 3 skipped (400); Tests 4 failed, 3261 passed, 28 skipped (3293). The four failures areflow-runas.dogfood.test.ts(threerunAscases; first assertion: trigger HTTP 404RECORD_NOT_FOUNDinrunas_note) anddeclarative-endpoint-anonymous-guest.dogfood.test.ts(one case). They reproduce when the two files run alone (4 failed, 8 passed). Not this diff: the dogfood closure build contains no@object-ui/*package, and no file underpackages/qa/dogfood,packages/verifyorpackages/pluginsimports@object-ui/types. Reported to the seat as a finding.6b7710c9) touches the same file with disjoint hunks. A three-waygit merge-fileofcomplex.zod.ts,spec-object-refinements-7715.test.tsandobjectql.ts(ours,origin/mainas base, theirs) answers 0 conflicts on all three, re-checked on the final head.🤖 Generated with Claude Code · https://claude.ai/code/session_01QsR2jUAK3FofY5VJPyS8fr
Generated by Claude Code