Repository navigation
fix(spec): os migrate meta --stored lists a stored dashboard whose global filter reuses the reserved dateRange key - #29586
objectstack-fleet[bot] wants to merge 2 commits into
Conversation
…obal filter reuses the reserved dateRange key REFUSED_STORED_SHAPES gains dashboardReservedDateRangeGlobalFilter, built on reservedDateRangeGlobalFilters (the dashboard refinement's own predicate), and both dashboard globalFilters D3 entries say the stored pass lists such a row. Claude-Session: https://claude.ai/code/session_01JQwxbXBJMBnWyspsxBN7j8 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check4 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 168 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1c99e0d779b7ad01b7f08a235456850ff051ed4e && git checkout 1c99e0d779b7ad01b7f08a235456850ff051ed4e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin b16ee8ba069d00bc00d01295869c1036fc9ea2e2 9e7c4c35d569f3bc5dafb33d18b9c44574a2644a && git checkout -B drift-repro b16ee8ba069d00bc00d01295869c1036fc9ea2e2 && git merge --no-ff 9e7c4c35d569f3bc5dafb33d18b9c44574a2644a
node scripts/docs-audit/affected-docs.mjs --json b16ee8ba069d00bc00d01295869c1036fc9ea2e2 |
|
domain:spec#5 · os-warren · session_01JQwxbWR3K3h7i1ytwycVg1 Contract-review-hold: session_01JQwxbWR3K3h7i1ytwycVg1 · head 9e7c4c3 · serial: The lane runs the at-tier review on the post-merge head. |
|
domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz Superseded by #29720: the same commits resumed on the card thread branch |
Requested by Warren · project thread
Fixes #29541
Clause-②: no
Metadata-protocol: none
维护者速读
os migrate meta --stored现在会列出「看板声明了内置dateRange,又有一个全局筛选器也叫dateRange」的已存数据行;两条看板筛选器迁移条目的验收句都补上了「存量预览会列出这种行」。dateRangeparses and silently replaces the built-in date range's binding #29213 已让每道门拒收这种看板,但升级前的存量预览不报它,运维升级前看不到哪些看板下次保存会被拒。packages/spec/src/conversions/refused-shapes.ts的dashboardReservedDateRangeGlobalFilter(调用拒收门同一个判定函数),再看refused-shapes.test.ts末尾 spec(conversions): the stored pass does not list a dashboard whose globalFilters entry is keyed dateRange beside a declared dateRange (the #29213 refusal) #29541 五条。pnpm --filter @objectstack/spec exec vitest run src/conversions/refused-shapes.test.ts,预期 88 个测试全过,其中 spec(conversions): the stored pass does not list a dashboard whose globalFilters entry is keyed dateRange beside a declared dateRange (the #29213 refusal) #29541 五条。What changes
REFUSED_STORED_SHAPESgainsdashboardReservedDateRangeGlobalFilter(idui-dashboard-global-filter-reserved-date-range-refused, the spec(dashboard): a globalFilters entry nameddateRangeparses and silently replaces the built-in date range's binding #29213 D3 entry of step 18), registered right afterdashboardDuplicateGlobalFilterName. It walksstack.dashboards[]and callsreservedDateRangeGlobalFilters(dashboard.dateRange, dashboard.globalFilters)fromui/duplicate-global-filter-names.ts, the predicateDashboardSchema's refinement reads; no logic is copied. One TODO per entry, atdashboards[i].globalFilters[j].name(or.fieldwhen the entry has noname), which is the site the parse refuses.fromcarries the reserved key and the index only. The reason leads with the fate (no lossless rewrite, loads with_diagnostics.valid: false, next save refused 422) and ends with the predicate's own message.acceptanceCriteriaof18.ui-dashboard-global-filter-reserved-date-range-refused.tsand of18.ui-dashboard-global-filter-duplicate-name-refused.ts(dashboards: two globalFilters with the same name are accepted; the board draws one control and its value filters the other filter's field #29023) each gain one sentence:os migrate meta --storedlists each such stored dashboard under the entry's id, at the site the parse refuses.refused-shapes.tsheader's list of borrowed predicates namesreservedDateRangeGlobalFilters..changeset/29541-reserved-date-range-stored-detector.md,@objectstack/specpatch.Why
The refusal's D3 entry already promised that a stored row with the pair loads as invalid and is refused on its next save, but the stored preview read such a row as already on protocol. An operator previewing the upgrade saw nothing.
Tests
refused-shapes.test.tsgains five cases under#29541, and the roster pin names the new id:dateRangebeside an entry nameddateRange): one TODO atdashboards[0].globalFilters[0].namewith the reserved word, the built-in date range and the predicate's message; the row is not rewritten, and the parse still refuses the same site;nameandfield: 'dateRange': listed once at.field, as the parse locates it;dateRange: listed under each refusal (one duplicate-key TODO and two reserved-key TODOs), exactly the threecustomissues the parse raises;dateRangedeclared, an entry keyeddateRange(by name or by field) is not listed and the parse accepts it;dateRange, a named entry whosefieldisdateRangeis not listed and parses.Ablation (fix committed first;
scripts/ablation-replace.mjs --deleteon the registry linedashboardReservedDateRangeGlobalFilter,): Tests 4 failed | 84 passed (88). The roster pin and the three listing cases went red, both controls stayed green. Restored: blob after restore equals HEAD,git diff HEADempty. The spec suite imports./refused-shapes.jsfrom source, so no dist was involved.Acceptance notes
origin/main@ff827bcfbefore the change:applyConversionsToStoredItem('dashboard', row, { onTodo })for a declareddateRangebeside an entry nameddateRangegave 0 TODOs while the parse refusedglobalFilters.0.name. The control, two filters namedr, gave 1 (ui-dashboard-global-filter-duplicate-name-refused).duplicate-global-filter-names.tsanddashboard.zod.tsare untouched. No ledger moved. The detector adds no new export, soapi-surfacedid not change.packages/metadata-protocol. The sibling's PR added one; this order's file surface names none, and fix(spec)!: refuse a dashboard globalFilters entry keyed dateRange beside a declared dateRange #29370's spec test covers the refusal in each door's form.refused-shapes.tscard. At this head noorigin/maincommit after the merge base touches the file. The list entry is purely additive.Verification
Head
9e7c4c35: one merge oforigin/mainatdbca3ef0. Every reading below was taken on that head.Package readings
pnpm --filter @objectstack/spec build: exit 0.pnpm --filter @objectstack/spec check:generated: all 14 generated artifacts up to date, exit 0.pnpm --filter @objectstack/spec test: Test Files 799 passed (799), Tests 23667 passed | 1 todo (23668), exit 0.pnpm --filter @objectstack/spec typecheck: exit 0.pnpm exec eslint --no-inline-configover the four changed source and test files: exit 0. The repo-widepnpm lintis CI's.Derived gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 81 families from 5 paths (144 changed lines). Each was run after the last commit, with its exit code recorded.--rananswered: 81 derived, 81 run, 0 NOT-MEASURED, 0 UNRUN (exit 0).pnpm check:dual-build-cjs-loadsfirst answered exit 3 (PREREQUISITE NOT MET, packages with nodist/). Afterturbo run build --filter='./packages/**'(78 tasks, all cache hits) it answered exit 0: 115 entry points across 70 packages.node scripts/check-plugin-teardown-shape.mjs --self-test: the pinned control commit621a4876was fetched first; exit 0.Lint & Repo Gates,TypeScript Type Check,Test Core,Build Core, the UI jobs) are read from this PR's check-runs, not re-run here. Dogfood is not owed: there is no!in the title and no(narrowing)arm.Human Minimum
packages/specholds no runtime logic.pnpm lintpasses.main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01JQwxbXBJMBnWyspsxBN7j8
Generated by Claude Code