Repository navigation
Description
epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
Filing gate: ④ child of epic #28236, filed on the maintainer's word in direct chat with the epic PM seat, 2026-11-03: 「发记录并立卡」 and 「相关卡 p1, 让车道处理」. ⛔ Not a claim.
QA-source: #29648 · studio-authoring.package-customize-restore-display · acceptance[4]
Part of #28236 · governs: ADR-0146 D8 item 3
Reader: domain:server (the export read in packages/runtime).
Dedupe (open and closed): base export, export override, declaresOverrideOf. #29563 (closed, the earlier symptom) and #29600 (open, the registry cause) are the nearest. Neither says the item goes missing. New.
reach: any read-only base whose .custom pair has published a dashboard or report override.
type: Bug
Business reason. A customer who exports their base after customizing it gets a package with items missing. That export cannot be redeployed as the vendor's package, and nothing warns them.
What happens
Measured on main at 322cf9068f, on a real showcase boot, before and after a restart.
| type | item | base export before | base export with a published override |
|---|---|---|---|
| dashboard | showcase_ops_dashboard |
3 items | 2 items: absent |
| report | showcase_hours_by_status |
4 items | 3 items: absent |
| view | showcase_task.in_progress |
36 items | 36 items, byte-identical |
D8 item 3: GET /packages/hotcrm.custom/export "carries the overriding item with its overrides block; GET /packages/hotcrm/export carries the base unchanged". Removing the override brings the item back.
Reproduce
- On a fresh showcase,
GET /api/v1/packages/com.example.showcase/export:dashboards[]holdsshowcase_ops_dashboard. POST /api/v1/packages/com.example.showcase/ensure-customization;PUT /api/v1/meta/dashboard/showcase_ops_dashboard?mode=draft&package=com.example.showcase.customwith the item andoverrides: {package:'com.example.showcase', basedOn:'0.1.0'};POST /api/v1/packages/com.example.showcase.custom/publish-drafts.- Repeat step 1's read. Expected: the item byte-identical to step 1, no
overrideskey. Actual: absent.
Why (read from source, the dev confirms)
PR #29597 added items.filter((it) => !declaresOverrideOf(it, packageId)) at packages/runtime/src/domains/packages.ts:3423. It assumes the per-package layer holds both documents. On this boot the layer holds no base document for that name, so the filter leaves nothing. #29600 measured the override registered in the bare slot wearing the base's envelope.
PR #29597's pin stays green while this fails: packages-export-base-unchanged-per-type.integration.test.ts registers its base so that the layer lists both documents.
Wanted
GET /packages/BASE/exportcarries the base's own document for every type while an override is live, byte-identical to the export without it.- A pin that fails on today's behaviour: drive a base booted as the showcase is, and assert the item is present and equal, not only that no
overrideskey appears. - The re-run of
studio-authoring.package-customize-restore-displayacceptance[4] passes on a real boot.
Serial: #29600 is in flight in the same area (os-steve), and it may remove the cause. Read its branch first, and say on this card whether it closes this one. Do not hand this card over to #29600 without measuring it on a real boot.
Links back: #29648, #29563, #29600, PR #29597, #28236, ADR-0146 D8.
Activity
objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS
Claim: PM loop round 9 · 2026-11-03T00:03Z
Session:
session_01JQwxbacSXJQqAztgt4UMrS(seat); dev = card threadsession_01JQwxbac7S1AsbGi5a46PrBAccount:
os-warrenBranch:
claude/project-thread-56mldo(a project card thread pushes only its assigned branch; measured platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-29649Domain:
domain:serverSeat:
domain:server#4File surface: the base-export assembly in
packages/runtime/src/domains/packages.ts(assemblePackageManifest,declaresOverrideOf) and its integration pins; tests, changesets (stop on breach; explain in the report). ⛔ Nopackages/spec/**; nopackages/metadata-protocol/src/protocol.ts(freeze until 2026-11-03 06:00Z); the registry slot (#29600's cause) is out of scope, stop and report if the fix needs it.Container & model:
M,mode:thread(the os-dev agent type is not loaded in seat sessions),model: TIER_DEFAULT,effort: project default (the maintainer sets effort)Clause-②: no
Metadata-protocol: none
Responsibility:
own regression — PR #29597 (#29563), landed by this seatThread-read: none
Premise: measured by the filer on
main322cf9068f(real showcase boot); dev reproduces red per type first and measures whether #29600 would close itSerial constraints: #29600 (open,
pm:queue, the registry cause) — not a blocker; this card's fix stays in the export readobjectstack-fleet commentedon Nov 3, 2026
domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4
Serial note · 2026-11-03T00:31Z
From
domain:server#5, answering seat 4's mailbox note 6591910232. PR #29640 (#29600) merged 2026-11-03T00:13:00Z as7dae3b3c0d. Its diff does not touchpackages/runtime/src/domains/packages.ts; it changespackages/metadata-protocol/src/protocol-package-bindings.ts,protocol.ts, two objectql tests and a changeset. Whether it closes this card is for this card's measurement onorigin/mainat or after7dae3b3c; seat 5 holds no claim onpackages.ts.objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbac7S1AsbGi5a46PrB
os-dev-report
{ "issue": 29649, "status": "done", "branch": "claude/project-thread-56mldo", "pr": "https://github.com/objectstack-ai/objectstack/pull/29687", "pr_state": "draft", "head": "51c4d1ee", "session": "session_01JQwxbac7S1AsbGi5a46PrB", "premise_still_valid": true, "summary": "Premise measured true on a real showcase boot at b391feb1: a published dashboard or report override left the base export without the item (dashboards 3 to 2, reports 4 to 3, views 36 to 36 equal). Cause: the per-package layer merges the registry's items over the metadata service's, one per (name, package) slot, so the override copy in the registry bare slot (wearing the base's envelope) takes the base's slot and the #29563 filter leaves nothing; the #29597 pin has no metadata service, so its layer listed both. #29600 (PR #29640, merged as 7dae3b3c during this card) closes the dashboard and report rows on its own, measured on a real boot, but NOT the card: on 7dae3b3c a published page, app, dataset, doc or book override still drops the item (pages 29 to 28, apps 1 to 0, datasets 4 to 3, docs 8 to 7, books 1 to 0). Fix stays in the export read: assemblePackageManifest replaces an item declaring an override of the exported package by the package's own code artifact (registry.getArtifactItem prefer-local, kept only when its _packageId is the package's and it declares no override), in place, when the layer lists no own item of the name. With it, all eight types are equal and the whole base export is byte-identical on a real boot (7dae3b3c), and after a restart (b391feb1, persistent OS_HOME). No protocol.ts, no registry slot, no packages/spec.", "files_changed": [ "packages/runtime/src/domains/packages.ts (ownDocumentsOf + call site comment)", "packages/runtime/src/domains/packages-export-base-showcase-boot.integration.test.ts (new pin, 8 types)", ".changeset/29649-base-export-keeps-overridden-items.md (patch @objectstack/runtime)" ], "tests": "New pin (real HttpDispatcher, protocol, ObjectQL on SQLite, real MetadataManager stamped as MetadataPlugin's artifact door stores the base): asserts presence, equality and a byte-identical whole base export before/after the published override and after a restart. Red first: 3-type version on b391feb1 without the fix, dashboard and report red ('expected [] to deeply equal' the shipped item), view green; 8-type version on 7dae3b3c without the fix, page/app/dataset/doc/book red, the other three green; with the fix 8/8. Neighbours green: packages-export-base-unchanged-per-type, packages-export-override-declaration, packages-export-per-package-layer. pnpm --filter @objectstack/runtime test exit 0 on e373cc16: Test Files 530 passed (530), Tests 8520 passed, 19 skipped (lock VERDICT command-exit 0, 870 s). Runtime typecheck exit 0 on 51c4d1ee. Live repro script per tree in the PR's Tests table.", "gates": "Head 51c4d1ee: dispatch-gates --commands derived 59; 58 exit 0; NOT MEASURED exit 3: node scripts/check-plugin-teardown-shape.mjs --self-test (positive control pinned to a commit the shallow clone cannot reach). --ran: '59 derived famil(ies) accounted for, 58 run, 1 NOT-MEASURED'. Earlier union on e373cc16 caught check:query-options-erasure exit 1 (the pin's as-any driver query, test surface 236 to 237), fixed in 51c4d1ee, exit 0 at 236. pnpm lint exit 0 (e373cc16; the later commit only removes an as-any in the pin). CI check-runs: in_progress at report time.", "dogfood_battery": "n/a: no '!' in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2: fleet-write relay pr_create (PR #29687, 7658 bytes sent and stored, identical); post-stamped os-dev-report comment on #29649 (this one). Plus git push (not REST).", "open_questions": [], "security_findings": "withheld", "out_of_scope_findings": [ "class: a · reach: GET /api/v1/meta/page/showcase_start_here (with or without ?package=com.example.showcase) on a real showcase boot at 7dae3b3c answers the shipped label after a published .custom override; same for app, dataset, doc, book; the pair's export lists none of them · evidence: live repro in this card thread; the pin's control records it (pairServed false); #29613 measured getMetaItem serving these overrides from the bare slot on a harness with no metadata service, and on a real boot the metadata service copy wins · carrier: #29613 (its row-served path, item 1), noted for the seat to add there, not filed · dedupe words: override not served metadata service page, real boot effective read override, pair export empty page" ], "deviations": "Commit messages carry no card trailer (pre-push check refused 'Refs #29649' once; reworded before any push). origin/main merged into the branch once (7dae3b3c) to measure #29640; origin/main has since moved to 744211fc (spec only), not merged." }objectstack-fleet commentedon Nov 3, 2026
domain:server#4 · os-warren · session_01JQwxbacSXJQqAztgt4UMrS
Landing record · #29649 · PR #29687 · 2026-11-03T02:13Z
git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-29687-*'git merge-base --is-ancestor 33ee9aa1 origin/maingit grep -c ownDocumentsOf origin/main -- packages/runtime/src/domains/packages.tsRelease: claim
6591700109(session_01JQwxbacSXJQqAztgt4UMrS, card threadsession_01JQwxbac7S1AsbGi5a46PrB, branchclaude/project-thread-56mldo) · full landingProduce: PR #29687 merged as
33ee9aa1at 2026-11-03T02:12Z. The base package's export now keeps an item that a later package overrides:ownDocumentsOfswaps the override copy back for the base's own artifact item, for all eight overridable types (dashboard, report, page, app, dataset, doc, book, and the rest of the list), pinned on a real showcase-style boot with the metadata service registered. #29640 had closed only dashboard and report. ACCEPT on the PR.Fixes #29649closed this card as completed.pm:dispatchedremoved; the card is closed.test(runtime): the #29649 showcase-boot export pin serves the pair ov…
objectstack-fleet commentedon Nov 3, 2026
epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
2026-11-03T02:52Z
Re-measured live on
mainatc9636f1e50, on a real showcase boot: with published overrides ofshowcase_ops_dashboardandshowcase_hours_by_status, the base export keeps dashboards 3 → 3 and reports 4 → 4, each item byte-identical to the export without the override and with nooverrideskey. Removing them returns the export to baseline.studio-authoring.package-customize-restore-displayacceptance[4] passes for both. The view leg was not repeated; it passed at322cf9068f.