Repository navigation
fix(runtime): the base's package export leaves out its pair's dashboard and report overrides (#29563) - #29597
Conversation
…rd and report overrides ADR-0146 D8 item 3: GET /packages/BASE/export carries the base unchanged. A published .custom dashboard or report row is registered in the registry's bare slot under the base's envelope, so the per-package layer listed it beside the base's own item and the base's export carried both. The export now drops, from a package's own export, any item that declares it overrides that package. Pinned per type (view, dashboard, report) over the real protocol and engine. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JQwxbXd7sSh6S5XDDEd7Ei
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JQwxbXd7sSh6S5XDDEd7Ei
📓 Docs Drift Check1 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 — 28 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 c756f595fc2b433d55a69115390952a019d5bc00 && git checkout c756f595fc2b433d55a69115390952a019d5bc00
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 50e35a280994dcecb714b6fa1f2d44840900f5e7 e81217fe9a50bae8e2cb9ad0563e4bd77095c798 && git checkout -B drift-repro 50e35a280994dcecb714b6fa1f2d44840900f5e7 && git merge --no-ff e81217fe9a50bae8e2cb9ad0563e4bd77095c798
node scripts/docs-audit/affected-docs.mjs --json 50e35a280994dcecb714b6fa1f2d44840900f5e7 |
|
domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS 席位核对ACCEPT ·
|
Requested by Warren · project thread
Fixes #29563
Clause-②: no
Metadata-protocol: none
维护者速读
GET /packages/BASE/export不再夹带.custom配对包已发布的仪表盘、报表覆盖项;配对包的导出照旧带覆盖项和overrides声明。packages/runtime/src/domains/packages.ts的declaresOverrideOf与assemblePackageManifest里的那一行过滤;再看新测试packages-export-base-unchanged-per-type.integration.test.ts。pnpm --filter @objectstack/runtime exec vitest run --project local src/domains/packages-export-base-unchanged-per-type.integration.test.ts,预期 3 条全绿(视图、仪表盘、报表)。What changes
assemblePackageManifest(theGET /packages/:id/exportdoor) now leaves out, from a package's own export read through the per-package layer, any item whoseoverrides.packagenames that same package. A package's own document never declares that it overrides itself: that declaration is what an item of the base's.custompair carries. The pair's export is unchanged and keeps the overriding item with itsoverridesblock. A protocol with no per-package layer is read as before, so the existing CONTROL inpackages-export-per-package-layer.test.tsstays as it is.One
@objectstack/runtimepatch changeset.Why
ADR-0146 D8 item 3: "
GET /packages/hotcrm.custom/exportcarries the overriding item with itsoverridesblock;GET /packages/hotcrm/exportcarries the base unchanged."Measured red first on the real protocol and engine (new pin, before the fix), per type:
expected [ 'Shipped label', 'Edited label' ] to deeply equal [ 'Shipped label' ];expected [ 'Shipped label', 'Edited label' ] to deeply equal [ 'Shipped label' ].Where the second item comes from, read off the registry in the same harness: publishing the pair's row writes it through to the SchemaRegistry's bare slot (
hydrateOverlayIntoRegistryinpackages/metadata-protocol/src/protocol.ts). The artifact lookup there falls back to the base's code artifact, because the pair ships no artifact of that name, so the bare copy wears the base's envelope (_packageId= the base,_provenance: 'package').listItems(type, BASE)then answers both the base's composite entry and that copy, and the per-package layer lists both under the base. Views are spared by the #22057 guard in the same hydrator, which is view-only by its own comment.The upstream (the hydrator lending a base's envelope to its pair's row) is in
protocol.ts, which is frozen until 2026-11-03 06:00Z and outside this card's claim. It is reported in the card's os-dev-report as a follow-up, with the minimal change named. This PR closes the export contract at the door the card names.ADR-0146 D8 item 2, "the export of X's app surface": read here as the pair's export, the one that carries X's app surface as customized, not as
GET /packages/X/export. Item 3 names that route and gives it the opposite rule, andgetMetaItemsPerPackage's docblock (protocol.ts) and #28409 read it the same way. The ADR text is not edited here (outside the claim); the report names the clarifying sentence for the seat.Tests
packages/runtime/src/domains/packages-export-base-unchanged-per-type.integration.test.ts: the real door (HttpDispatcher.handlePackages) over the realObjectStackProtocolImplementationandObjectQLon a SQLite file. The base is a code package, the pair is installed through the package door, each override goes through the draft save and the per-item publish. Per type (view, dashboard, report): the effective read serves the override (CONTROL), the base's export carries only the base's document with nooverridesblock, and the pair's export carries the override with its declaration.scripts/ablation-replace.mjs; the test readspackages.tsfrom source, no dist in the path): deleting the filter line turned dashboard and report red with the same two messages above, view stayed green; restore provedblob == HEADandgit diff HEADempty.Acceptance notes
studio-authoring.package-customize-restore-displayacceptance[4] is a live-run checklist item; its record is not edited in this PR (outside the claim). The seat can mark it once a live run reads the base export clean.Verification
Head
e81217fe(main merged at1a95c746; the 11 latermaincommits touch none of this PR's files).pnpm --filter @objectstack/runtime exec vitest run --project local src/domains/packages-export…(3 files): before the fix 2 failed | 1 passed (dashboard, report red); after,Test Files 3 passed (3),Tests 9 passed (9).pnpm --filter @objectstack/runtime testate81217fe:Test Files 526 passed (526),Tests 8489 passed | 19 skipped (8508), lockVERDICT command-exit 0.pnpm --filter @objectstack/runtime typecheckate81217fe: exit 0 (tsc andcheck:test-typecheck; the new file is in the checked zone with no ledger entry).pnpm lint: exit 0.dispatch-gates --commands (60) and --ran reconciliation
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 60 commands; 58 exit 0. The union ran on4a7b14f4; the only later commit (e81217fe) deletes one unused line in the new test file.NOT MEASURED, exit 3 (prerequisite not met), CI runs both:
node scripts/check-plugin-teardown-shape.mjs --self-test: its fixture is pinned to a commit the shallow clone does not hold (checker-health only).pnpm check:dual-build-cjs-loads: needs every package'sdist/; only the runtime closure was built here.dispatch-gates --ran: "60 derived famil(ies) accounted for — 58 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3)", exit 0.Human Minimum
packages/specholds no runtime logic. (Nopackages/specchange.)pnpm lintpasses.main, one pull request.packages/spectouched: n/a.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01JQwxbXd7sSh6S5XDDEd7Ei
Generated by Claude Code