Repository navigation
fix(spec): os migrate meta --stored lists a stored dashboard whose global filter reuses the reserved dateRange key - #29720
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>
Resolve refused-shapes.ts and its test additively: keep #29589's object_extension fieldPatches detector and this card's dashboard reserved-dateRange detector; the roster pin counts both. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzg4LNpBsJKihJRTLqD
📓 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 db8dd24101e3e0cada4a8a87088f8d2a82819c5b && git checkout db8dd24101e3e0cada4a8a87088f8d2a82819c5b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 9b4fa6cc9d8295e891d5f8d2264aee1cca36c203 76d25fa9854e7d8620cb02013943a56e7d69bae5 && git checkout -B drift-repro 9b4fa6cc9d8295e891d5f8d2264aee1cca36c203 && git merge --no-ff 76d25fa9854e7d8620cb02013943a56e7d69bae5
node scripts/docs-audit/affected-docs.mjs --json 9b4fa6cc9d8295e891d5f8d2264aee1cca36c203 |
|
domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (account at-tier budget spent, maintainer 2026-10-28; 2026-11-03T02:47Z) · head 76d25fa Scope: the whole diff (no review ran on #29586). A stored-pass detector |
|
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U Path: none Triage: contract-review handoff declined · head
|
|
domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz Contract reviewServed-tier: Head read as ① Derived judgments
② Semver level
Clause-②: no ③ Boundary flags
④ Design judgment
Gates on the head (conclusions read, not re-run): Must-fix: none. Should-fix: none on the Implemented-by: VERDICT: PASS |
|
domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz 维护者速读
席位意见:检测器直接调用拒收门的同一判定函数,与 #29589 的合并是纯追加,同意落地。 席位核对 — ACCEPT · domain:spec#2 · head
|
domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz
Requested by Yibo Wang · project thread
Fixes #29541
Supersedes #29586 (same commits, resumed on a new branch, merged with main after #29589; #29586 is closed)
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(调用拒收门同一个判定函数,与 fix(spec): read a stored object_extension row as an objectExtensions entry, and list its refused fieldPatches keys #29589 的objectExtensionFieldPatchKeyGrammar并存),再看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,预期 92 个测试全过(含 spec(conversions): the stored pass maps no object_extension row onto objectExtensions, so no conversion or refused-shape detector ever runs over a stored extension #29554 的四条),其中 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.57958aab) edited the samerefused-shapes.tsand merged first. The merge oforigin/main@3d5933a9conflicted inrefused-shapes.tsand its test and was resolved additively: fix(spec): read a stored object_extension row as an objectExtensions entry, and list its refused fieldPatches keys #29589'srefusedFieldPatchKeys/objectExtensionFieldPatchKeyGrammar(and itsObjectExtensionSchemaimport) stay, this card's dashboard detector stays, the header docblock names both borrowed predicates, andREFUSED_STORED_SHAPESlistsdashboardReservedDateRangeGlobalFilterthenobjectExtensionFieldPatchKeyGrammar. The roster pin counts both new ids. No generated path moved on either side, soos-regen-merge.shhad nothing to take.Verification
Head
76d25fa9: the commits of #29586 (through9e7c4c35) plus one merge oforigin/mainat3d5933a9. Every reading below was taken on that head. The readings of the old head are in #29586.Package readings
pnpm --filter @objectstack/spec test+typecheckunderscripts/pm/os-verify-lock.sh: Test Files 802 passed | 1 skipped (803), Tests 23789 passed | 1 skipped | 1 todo (23791); typecheck exit 0 (migration registry current: 535 semantic). Lock verdict command-exit 0.refused-shapes.test.tsalone: 92 passed (92), the 88 of fix(spec): os migrate meta --stored lists a stored dashboard whose global filter reuses the reserved dateRange key #29586 plus spec(conversions): the stored pass maps no object_extension row onto objectExtensions, so no conversion or refused-shape detector ever runs over a stored extension #29554's four.pnpm build(whole repo, under the lock): 117 of 117 tasks, exit 0.Derived gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 80 families from 5 paths (144 changed lines vs merge base3d5933a9). Each was run on this head.--ran: 80 derived, 80 run, 0 NOT-MEASURED, 0 UNRUN.check-changeset-no-major.mjs --base origin/mainandcheck-adr-0087-registration.mjs --base origin/mainexit 0 on the merged head with the unchanged declarations (Clause-②: no,Metadata-protocol: none,@objectstack/specpatch).dist/); after the full build each answered exit 0.!in the title and no(narrowing)arm. The at-tier contract review on this head goes to triage, per the claim.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_01WGufzg4LNpBsJKihJRTLqD