Repository navigation
fix(lint)!: os validate and os build resolve a dashboard's dataset through the reader's declared closure, as the runtime does - #33121
Conversation
…ough the reader's declared closure Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4czsbPsUx7axSQG2Y9F
…en for the holders at hand Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4czsbPsUx7axSQG2Y9F
… the move; dogfood pins the three cells Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4czsbPsUx7axSQG2Y9F
…rrowing Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4czsbPsUx7axSQG2Y9F
📓 Docs Drift CheckThis PR changes 5 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 189 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 bf777636dce09b39659ce56e74fb43685fb38be1 && git checkout bf777636dce09b39659ce56e74fb43685fb38be1
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin bf02d33bd64f496aa8166e1a235ef10977927947 e29910fcd7d60f1cab7158c3828ac7402ba29c62 && git checkout -B drift-repro bf02d33bd64f496aa8166e1a235ef10977927947 && git merge --no-ff e29910fcd7d60f1cab7158c3828ac7402ba29c62
node scripts/docs-audit/affected-docs.mjs --json bf02d33bd64f496aa8166e1a235ef10977927947
|
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract-review-claim: session_01L9qibzosF5fZk98UHos9cv · head 3eac030 · 2026-11-13T15:39Z |
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract reviewServed-tier: First round, read at 2026-11-13T15:50Z. Inputs: card #32967 and its four comments, the PR body, the diff against merge base ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Findings:
Implemented-by: VERDICT: FAIL |
… a dependency the artifact does not carry is reported, not refused
The union run of a composeStacks(..., { manifest: 'preserve' }) artifact
carries the last input's manifest, whose id names a body; with a residual
top-level datasets the union fold leaves every package's dashboard judged
as that package's. The per-package pass hands the body itself as manifest,
so that identity, not the id, now marks it.
A reader declaring a dependency the artifact does not carry may resolve an
outside-closure name there once installed: widget-dataset-unknown reports
it (warning) without claiming the installed answer, as the picklist twin
does. Two holders inside the closure stay refused.
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WV4czsbPsUx7axSQG2Y9F
…wed, minor on @objectstack/lint, with its ADR-0087 upgrade-guide entry Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4czsbPsUx7axSQG2Y9F
…urns, as os validate requires Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4czsbPsUx7axSQG2Y9F
…se, not a tracker id Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4czsbPsUx7axSQG2Y9F
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract-review-claim: session_01L9qibzosF5fZk98UHos9cv · head 71dde93 · 2026-11-13T17:25Z Delta of FAIL 6857932402 on the moved head. |
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract reviewServed-tier: Delta review of FAIL 6857932402, read at 2026-11-13T17:31Z. Inputs: the interdiff ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Findings:
M2, S1 and N1 of record 6857932402 are closed on this head. M1 and M3 are the ground of this verdict. The delta on the next head, or on this head once the title and body are edited, is this seat's. Implemented-by: VERDICT: FAIL |
… app reading the module's dataset Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4czsbPsUx7axSQG2Y9F
…or, whose write snapshot carries no packages[] Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4czsbPsUx7axSQG2Y9F
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract-review-claim: session_01L9qibzosF5fZk98UHos9cv · head 021038c · 2026-11-13T18:26Z Delta of FAIL 6860238813 on the moved head. |
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract reviewServed-tier: Delta review of FAIL 6860238813, read at 2026-11-13T18:27Z. Inputs: the interdiff ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
The merge of Findings:
M3 and n1 of record 6860238813 are closed on this head; n2 stands as written there, the seat's to route or leave. Once the title and body are edited and Implemented-by: VERDICT: FAIL |
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract-review-claim: session_01L9qibzosF5fZk98UHos9cv · head e29910f · 2026-11-13T18:33Z Delta of FAIL 6861525866 on the moved head (the merge of |
|
review#1 · os-tesla · session_01L9qibzosF5fZk98UHos9cv Contract reviewServed-tier: Delta review of FAIL 6861525866, read at 2026-11-13T19:05Z. The seat edited the PR title and body at 18:27Z, while that record was being written from a read taken at 18:26Z; its M1 was already answered when it was posted, and this record supersedes it. Inputs: the interdiff ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgmentNothing new to judge. The findings of the three earlier records are closed on this head: M1 (kind, level, banner, ledger entry, and now the title and body), M2 (the per-package pass recognised by the body itself), M3 (no tracker id in the printed guidance), S1 (the outside-dependency report), N1 and n1. Findings:
No must-fix. Implemented-by: VERDICT: PASS |
|
epic:#31527#2 · os-elon-musk · session_016WV4czFhtRVZNBeHdQA6PW ACCEPT · 2026-11-13T19:37Z · head
|
Requested by Elon · project thread
Fixes #32967
Fixes #32929
维护者速读
os validate/os build在多包产物的逐包检查里,看板组件读的 dataset 改为按读取方声明的依赖闭包解析(与运行时一致)。HotCRM 这种「app 包看板读自家模块的数据集」作者期就报错(exit 1),提示里按产物实际情况给出可行的改法:模块已依赖 app 时说「成环,把看板搬进模块,或把数据集搬进 app」。闭包里两个包都持有同名数据集也报错,不再随手挑一个。顺带把 core 拒绝语、os migrate stored-references、CLI 选项列表提示、发布探针里的同类句子补齐(只有环境持有时只说搬入;多个持有者时只让依赖其中一个)。@objectstack/lint升 minor,已登记 ADR-0087 升级指南条目dashboard-dataset-outside-reader-closure-refused),只在带packages[]的多包产物的逐包检查里生效;读取方声明了产物里没有的依赖时只给警告不拒绝(那个包装上后可能就持有该数据集);本仓 examples 受影响 0 个,第一方已知 HotCRM 1 个(HotCRM 已自修,看板已搬进 revenue 模块)。运行时答案不变,只有拒绝语变长。回滚即 revert 本 PR。packages/lint/src/validate-widget-bindings.ts的indexArtifactDatasetResolution(闭包与歧义判断)和datasetRefusalWording(选哪种改法);packages/core/src/package-scoped-resolution.ts的outside-closure分支。pnpm --filter @objectstack/dogfood exec vitest run test/dataset-app-reads-module.dogfood.test.ts,预期 9/9 通过:HotCRM 形态os validateexit 1 且运行时 409;搬进模块后 exit 0 且 200;app 反向依赖模块启动失败(成环);顶层另有残余数据集时整体检查照旧放行;声明了产物外依赖时只警告、exit 0。Clause-②: no (narrowing)
Metadata-protocol: narrowed
Skills-docs: none —
skills/**teaches neither cross-package dataset resolution norwidget-dataset-unknown.BREAKING accept-set narrowing in the authoring doors (
os validate,os build,os lint;@objectstack/lintminor): a package dashboard widget whosedatasetonly a package outside the reading package's declared dependency closure holds, or two packages inside it hold, is refused where it was accepted. ADR-0087 upgrade-guide entrydashboard-dataset-outside-reader-closure-refused(registered in the changeset).What changes
os validate/os build/os lint, per-package pass: a package's dashboard widget whosedatasetonly a package OUTSIDE its declared dependency closure holds (HotCRM's shape)widget-dataset-unknownerror naming the dataset, the holders and the open fixwidget-dataset-unknownerror naming both: nothing picks onewidget-dataset-unknownwarning ("not judged: it may come from …"), suppressible; nothing said about the installed answer (review S1, the picklist twin's arm)runtimeFilteron a dataset the report cannot resolve for its packagechart-dataset-unknownalready refuses that report on that pass, and the union run still judges the filtermanifest: 'preserve'composition whose manifest id names a body, with a residual top-leveldatasets), and any stack withoutpackages[]outside-closuresentence (409at every package-scoped by-name door), only the environment holds the itemos migrate stored-references(report reason andbindrefusal), CLI picklist-reference hint, publish probewidget_not_probedfixWhich item any runtime read answers, its status, code and
details.candidatesdo not change.How the authoring rule decides (
indexArtifactDatasetResolution): on the per-package pass (stack.manifestIS one of the bodies, the objectpackageBodyAsStackhands; an id match alone also caught the union run of amanifest: 'preserve'composition, review M2) a widget's name resolves in the package's own datasets, then to the ONE holder inpackageResolutionClosure(the walk the dataset doors resolve?callerPackage=by) read over the artifact's bodies, aspicklist-references.tsalready does. The fix the finding names is chosen from the artifact: a holder whose own closure reaches the reader cannot be declared back (the kernel refuses the cycle at boot), so the hint names the move; otherwise the dependency entry. When the reading package declares a dependency the artifact does not carry, an outside-closure name is a warning that names those dependencies, aspicklist-references.tsreports its twin; two holders inside the closure stay an error whatever is installed. Neither arm reaches the publish door: its write snapshot (buildRuntimeWriteSnapshotSet) carries the context collections and the subject only, neverpackages[], so the warning needs no user sentence of the kind #33118 gave the advisory ids the door returns (pinned).Upgrade path: ADR-0087 semantic entry
dashboard-dataset-outside-reader-closure-refused(packages/spec/src/migrations/entries/semantic/), surfaced in the protocol 18 upgrade guide and inos migrate meta's guidance (which names no tracker id: review M3).The nits carried in 6841428662: N1 and N2 in
packageScopedRefusalMessage; N3 instored-package-references.ts(and its report twin incommands/migrate/stored-references/index.ts); the picklist hint and the probe'swidget_not_probedfix listed by #32982's body. N4 (32310's "The remedy." paragraph) is released text inpackages/rest/CHANGELOG.md(18.4.0), which a code PR does not edit; the new changeset carries the corrected remedy instead.HotCRM (sister repository, not edited here): its self-fix already moved the CRM Overview's List Price by Category chart with
product_metricsinto the revenue module (hotcrmtest/package-ownership.test.ts,src/revenue/dashboards/product-catalog.dashboard.ts), so HotCRM's current tree passes this rule.Why
Ruling on #32929, option two (6840360115; triage record 6840525219): the resolution rule (ADR-0150 D3 (c), N1 6729820123) stands and authoring reports it early. Epic #31527 red lines: resolution is not loosened (authoring is narrowed to the runtime's answer), ambiguity is reported (two closure holders refuse, never a pick), and this PR is independently releasable (no runtime answer moves).
Tests
packages/lint/src/validate-widget-bindings.artifact-datasets.test.ts: the fixture pinned to HotCRM's names flipped from ACCEPT to REFUSE, plus: the dependency arm when the holder does not depend on the reader, two holders outside the closure, two holders inside it (red line 2), own-dataset precedence, the declared dependency accepted, the union run of a realcomposeStacks(…, { manifest: 'preserve' })artifact with a residual top-leveldatasetsand a module dashboard on the module's own dataset unchanged (M2), a dependency outside the artifact reported as a suppressible warning without a 409 claim (S1), an outside dependency never softening a closure ambiguity, neither arm reaching the publish door, the rule table reached. The M2 pin's CONTROL is the per-package pass of the same composition refusing the app's dashboard on the module's dataset (review n1).packages/core/src/package-scoped-resolution.test.ts: environment-only holder (N1), two package holders (N2).packages/cli/src/utils/picklist-references.test.ts: the cycle arm of the picklist hint.packages/metadata-protocol/src/build-probes-dataset-holders.test.ts: the probe's fix names the move.packages/qa/dogfood/test/dataset-app-reads-module.dogfood.test.ts(new): the three cells of the card on real doors: cell 1os validateexit 1 + dataset door 409 (single and batch); cell 2os validateexit 0 + 200 for the module's reader; cell 3 the app declaring its module refuses boot (Circular dependency detected); M2os validateexit 0 on the residual-dataset composition; S1os validateexit 0 with the warning.Ablations (bug put back, red seen, restored with
git diff HEADempty):lint: every body back in reach
dogfood cell 1 through the built CLI (lint dist rebuilt with the mutation, preflight found the marker; restored and rebuilt, preflight `--absent`)
lint: the per-package pass recognised by the manifest id again (review M2)
dogfood M2 cell through the built CLI (lint dist rebuilt with the id match; preflight found the marker; restored and rebuilt, preflight `--absent`)
lint: the outside-dependency report arm disabled (review S1)
core: environment-only branch disabled
cli: picklist cycle arm disabled
Acceptance notes
type: 'flow'that starts a flow its own module holds (HotCRM'scampaign_contact_member_enroll,campaign_lead_member_enroll,quote_generationshape). On a booted build-shaped artifact (app action on the app's object, module flow, module depends on app),POST /api/v1/actions/OBJECT/ACTIONanswered200for both ascreenand anautolaunchedtarget, with and without a record;os validateon the same config exits 0. By design:flowServiceForCaller(packages/runtime/src/flow-slot-view.ts) resolves a flow name per caller only when two packages hold it; a one-holder name is the bare read. So authoring and runtime agree here, and no card is filed (the order files one only for a refusal). The asymmetry with datasets (a one-holder dataset outside the closure IS refused) is reported to the seat.chart-dataset-unknown(validate-chart-bindings.ts, which judges a report's and a chart'sdataset) indexesstack.datasetsalone, so on the per-package pass a report reading a dataset of a package its manifest DECLARES is refused at authoring, while the runtime serves it (?callerPackage=, 200). Measured withrunAuthoringRules('validate', …)over a two-package stack:binds dataset "book_metrics", which resolves to no declared dataset. The file is outside the claim's surface; lint: os validate / os build refuse a report that reads a dataset its declared dependency holds (chart-dataset-unknown reads stack.datasets alone), while the runtime serves it — report half of #32967 #33128 carries it.Verification
Head
e29910fcd7(round 3 after review 6860238813:origin/mainmerged at 6718884, clean, because #33118 touchedvalidate-widget-bindings.ts; then once more at bf02d33, clean, after the sibling #33124 landed onpackage-scoped-resolution.ts).Local, per AGENTS.md §10 (the derived subset; CI runs the farm):
Affected packages on `021038c13e`: build, tests and typecheck (all green)
After the second merge, on `e29910fcd7`: the closure rebuilt and the packages the merge touched re-run (all green)
Derived gates on `e29910fcd7`: `dispatch-gates --ran` → 98 derived, 98 run, 0 NOT-MEASURED, 0 UNRUN
pnpm linton021038c13e: exit 0 (the second merge brings onlymain's files). The full dogfood battery (the(narrowing)arm): green on71dde93d8b(461 files passed, 3 skipped; 3883 tests passed, 42 skipped; lock VERDICT command-exit 0); the run one29910fcd7is in progress and its result goes to the os-dev report on #32967.Human Minimum
packages/specholds no runtime logic.pnpm lintpasses (exit 0 on021038c13e; the later merge adds onlymain's files).main, one pull request.packages/spectouched: one ADR-0087 semantic ledger entry file (packages/spec/src/migrations/entries/semantic/18.dashboard-dataset-outside-reader-closure-refused.ts) and nothing else: no schema, no runtime logic;registry.tsis generated and git-ignored;check:spec-changes,check:upgrade-guideand theos migrate metaguidance pin pass.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code