Repository navigation
fix(lint)!: the view and object publish doors refuse a list-view chart whose dataset or measure does not resolve - #26906
Conversation
The list-view chart walk now opens the two standalone view shapes the publish door carries (the flattened list overlay and the ViewItem config), and the reference-integrity suite crosses the rule onto view and object writes. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufziFPBpGc76tAFHbB8v
…doors Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufziFPBpGc76tAFHbB8v
…ect doors Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufziFPBpGc76tAFHbB8v
…tures Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufziFPBpGc76tAFHbB8v
📓 Docs Drift CheckThis PR changes 1 package(s): 5 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 4 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 db5554db0b387c443345867f27ff4077a05de307 && git checkout db5554db0b387c443345867f27ff4077a05de307
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 57820085fa1cfb522fefc1e24e12f252d8d4630e 96844466d4db1163476073fbbe825875c0fe8d8e && git checkout -B drift-repro 57820085fa1cfb522fefc1e24e12f252d8d4630e && git merge --no-ff 96844466d4db1163476073fbbe825875c0fe8d8e
node scripts/docs-audit/affected-docs.mjs --json 57820085fa1cfb522fefc1e24e12f252d8d4630e
|
Contract reviewServed-tier: Inputs: card #26847 (body, triage ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgmentThe narrowing, read against the published spec on
Implemented-by: VERDICT: PASS |
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufziFPBpGc76tAFHbB8v
席位核对 · ACCEPT ·
|
Requested by Yibo Wang · project thread
Fixes #26847
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Skills-docs: updated here —
content/docs/data-modeling/analytics.mdxgains the rule and its remedy; noskills/**file teaches list-view chart bindings, so no skill changes.维护者速读
values写了数据集里没有的度量(维度同理),通过视图或对象发布时直接拒绝(422),给出与os validate相同的结论;草稿保存不拦。packages/lint/src/validate-chart-bindings.ts(列表视图遍历新增的两种独立视图形态)、packages/lint/src/reference-integrity-suite.ts(validateChartBindings一行的runtimeTypes与上方注释)、packages/rest/src/meta-view-chart-binding.test.ts末尾的#26847段。pnpm --filter @objectstack/lint exec vitest run src/validate-chart-bindings.test.ts -t 26847,应见 24 条全绿(三种视图形态 × 未知数据集 / 未知度量 / 对照,加对象发布门与运行时门)。What changes
validateChartBindings(packages/lint) already gavechart-dataset-unknown,chart-dimension-unknownandchart-measure-unknownfor a list-view chart underos validate, but the runtime publish door never ran it for a view or an object. Two things kept it out:reference-integrity-suite.tsdeclaredruntimeTypes: ['flow', 'report']. It is now['flow', 'report', 'view', 'object'], and the comment above the row is rewritten: a list-view chart resolves againststack.datasetsalone, which every per-write snapshot carries, so crossing it opens no missing-collection false-positive channel. The rule's report, page and dashboard surfaces read collections a view or object snapshot does not carry, so on those writes they find nothing.views[].list,views[].listViews.KEYandobjects[].listViews.KEY, but not the two standalone shapesPUT /api/v1/meta/viewhands the suite: the flattened list overlay (viewKind: 'list', chart at the top level) and the ViewItem record (viewKind: 'list', chart insideconfig). Both rungs are added, recognised the wayvalidateListViewFieldRefsrecognises them. Without them, addingviewtoruntimeTypeswould have been a no-op for those two shapes.One guard moves with it: the rule's early return (
no datasets, no reports, no views, no pages) now also looks atobjects, so an object list view naming a dataset in a stack that declares none is reported instead of skipped. That is what makes theobjectdoor judge an object written into an environment with no datasets.The verdicts are unchanged:
chart-dataset-unknownatchart.dataset,chart-measure-unknownatchart.values[i],chart-dimension-unknownatchart.dimensions[i], allerror, so the publish answers422 INVALID_METADATA. A draft save is not gated.Why
A Studio or MCP author who mistypes a dataset name, or names a measure the dataset lacks, gets a saved view whose chart renders empty or broken. Nothing says why, and the CLI would have refused the same file.
Tests
packages/lint/src/validate-chart-bindings.test.ts, new[#26847]block (24 cases): each of the three view shapes (ViewItemconfig, flattened overlay, containerlistViewsmember) giveschart-dataset-unknownandchart-measure-unknownat the right path, with a clean control; a ViewItem record is walked atconfigonly; an object list view in a stack with no datasets is reported. At the runtime door (runRuntimeAuthoringRules, the functionmetadata-protocolcalls): a lit probe per verdict per view shape and on an object write, each with a clean control, and a pin that the row declaresviewandobject.packages/rest/src/meta-view-chart-binding.test.ts, new#26847block (9 cases) on the real composition (realRestServerroute, realsaveMetaItem, realObjectQL+ SQLitesys_metadata): per shape,no_such_dataset→ 422INVALID_METADATAwithchart-dataset-unknownat….chart.datasetand nothing stored;ghost_measure→ 422 withchart-measure-unknownat….chart.values[0]and nothing stored; the control → 200 and stored. The file'sboot()now publishes thelead_metricsdataset its fixtures bind, throughPUT /api/v1/meta/dataset: the existing spec(ui): the view write door accepts a chart list view that names no dataset (type: 'chart'with nochartblock, oroptions.chartwith onlychartType); once objectui stops reading the legacy axes, such a view saves green and renders only a refusal #22491 control bound that dataset without declaring it, and is refused now that the door resolves it.viewandobjectmember-surface rosters (runtime-gate.view-writes.test.ts,runtime-gate.object-writes.test.ts) gainvalidateChartBindingswith the argument written beside them. The spec: a chart list view on object A accepts a dataset bound to another object or another package without refusal #26719 save-door probes invalidate-list-view-field-refs.test.tschartedstatus/task_countagainst the person dataset, which declares neither; they now select names their dataset declares, so the foreign object stays the only thing wrong with them.Acceptance notes
main20457f6f, with the same harness as the new REST block and a declaredlead_metricsdataset, all six bad PUTs answered200(three shapes ×no_such_dataset/ghost_measure), and the three controls200. On this branch the six answer422atviews[0].config.chart.dataset/views[0].chart.dataset/views[0].listViews.pipeline.chart.dataset(and….values[0]for the measure), the controls still200. The lint dist was rebuilt from each tree before its run.21e8217b: every view sent throughrunRuntimeAuthoringRules({ type: 'view' })and every object withlistViewsthrough{ type: 'object' }, each with its own stack's objects and datasets as context.examples/app-crm3 views / 6 objects,examples/app-todo1 / 1,examples/app-showcase6 views / 24 objects / 4 datasets,examples/app-multi-packagenone,packages/platform-objects53 objects (29 withlistViews). Two list views chart (showcasetaskchart,projectbudget_chart): 0 chart findings at either door. A lit probe (the showcase chart rebound to an unknown dataset) is refused.apps/holds only the docs site; a repo-wide search fortype: 'chart'outside tests finds no other list-view chart.dashboardandpagewrites still do not run this member; their surfaces are owned by their sibling rules.Verification
All local, on
35d40a9e, throughscripts/pm/os-verify-lock.sh(every VERDICT linecommand-exit 0):pnpm --filter @objectstack/lint test: Test Files 169 passed (169), Tests 7490 passed (7490).pnpm --filter @objectstack/lint typecheck: exit 0.pnpm --filter @objectstack/rest test: Test Files 328 passed (328), Tests 6522 passed, 326 skipped.pnpm --filter @objectstack/metadata-protocol test: Test Files 270 passed, 4 skipped (274), Tests 21666 passed, 26 skipped.node scripts/pm/dispatch-gates.mjs --commands(merge base20457f6f, 6 paths): 88 derived families, 86 exit 0.check:skill-examplesandcheck:dual-build-cjs-loadsexit 3 (prerequisite: they read a full build); they re-run afterpnpm build, and that reading, the full dogfood battery on the final head and the--ranreconciliation are in the os-dev report on spec(lint): the view publish door accepts a chart list view whose dataset does not exist or whosevaluesnames no measure of its dataset #26847.Human Minimum
packages/specholds no runtime logic.eslint --no-inline-configon the seven changed source and test files exits 0 (the repo-widepnpm lintis CI's run).main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed. (Not touched.)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01WGufziFPBpGc76tAFHbB8v