You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ADR-0048 (#1810, #1816, #1819, #1822, #1827) made same-name cross-package metadata resolve correctly through the single-item (?package=) and Studio editor/layered paths. The remaining gap is the unscoped list.
Problem
protocol.getMetaItems (packages/objectql/src/protocol.ts) merges registry items, sys_metadata overlay rows, draft-preview rows, and MetadataService items into the result using Maps keyed by bare name (three sites):
So when two installed packages ship an item of the same type/name, an unscoped GET /meta/:type (no ?package=) collapses them to one (last-write-wins by name).
With overlays (feat(metadata): package-scoped customization overlays (ADR-0048 #1824) #1827): as soon as either package has a sys_metadata overlay, the DB-overlay merge runs and the byName collapse drops one package's row. Verified: two page/showcase_task_workbench overlays coexist in the DB and resolve fine via ?package=, but the unscoped /meta/page returns only one.
The frontend prefer-local resolution for dashboard/report/page (preferLocal(list, name, app._packageId) in objectui app-shell) reads the unscoped list, so a collapsed list makes it pick the surviving row regardless of package.
Secondary: provenance pollution
The DB-row hydration at ~L1234-1240 registers overlay rows under the bare registry key via mergeArtifactProtection(data, lookupArtifactItem(type, name)) — a first-match (non-package-scoped) artifact lookup. On a collision this grafts the first package's _packageId onto the row, mislabeling provenance even when content is correct.
Proposed direction
Make the list merge package-aware:
Key the dedup Maps by (name, package_id) (or ${_packageId ?? ''}:${name}) instead of bare name, so a package_id=A overlay merges onto package A's artifact and package_id=B onto B's — no cross-package collapse.
Does any consumer rely on the current bare-name dedup (e.g. expecting exactly one entry per name)? Audit the Studio metadata list + sidebar.
Interaction with the ADR-0005 org-overlay-wins precedence (the merge currently also encodes that).
Acceptance
Unscoped GET /meta/page with two installed packages each shipping page/home (with or without overlays) returns both rows, each with its own correct _packageId.
Context
ADR-0048 (#1810, #1816, #1819, #1822, #1827) made same-name cross-package metadata resolve correctly through the single-item (
?package=) and Studio editor/layered paths. The remaining gap is the unscoped list.Problem
protocol.getMetaItems(packages/objectql/src/protocol.ts) merges registry items,sys_metadataoverlay rows, draft-preview rows, andMetadataServiceitems into the result usingMaps keyed by barename(three sites):byName.set(entry.name, entry)(~L1204-1243)byName.set(data.name, data)(~L1277-1291)itemMap.set(entry.name, entry)(~L1313-1336)So when two installed packages ship an item of the same
type/name, an unscopedGET /meta/:type(no?package=) collapses them to one (last-write-wins by name).Where it bites
sys_metadataoverlay, the DB-overlay merge runs and thebyNamecollapse drops one package's row. Verified: twopage/showcase_task_workbenchoverlays coexist in the DB and resolve fine via?package=, but the unscoped/meta/pagereturns only one.dashboard/report/page(preferLocal(list, name, app._packageId)in objectuiapp-shell) reads the unscoped list, so a collapsed list makes it pick the surviving row regardless of package.Secondary: provenance pollution
The DB-row hydration at ~L1234-1240 registers overlay rows under the bare registry key via
mergeArtifactProtection(data, lookupArtifactItem(type, name))— a first-match (non-package-scoped) artifact lookup. On a collision this grafts the first package's_packageIdonto the row, mislabeling provenance even when content is correct.Proposed direction
Make the list merge package-aware:
Maps by(name, package_id)(or${_packageId ?? ''}:${name}) instead of barename, so apackage_id=Aoverlay merges onto package A's artifact andpackage_id=Bonto B's — no cross-package collapse.lookupArtifactItemgraft (~L1234-1240) to the row's ownpackage_id(mirror thegetMetaItem/getMetaItemsfix from fix(metadata): keep each colliding item's own _packageId provenance (ADR-0048) #1822) so provenance stays correct.package_id IS NULL) overlay semantics in the list: it has no package to attribute to. Options: apply to the first/all same-name entries, or surface as its own row. (Same inherent ambiguity noted in ADR-0048 follow-up: package-scoped metadata overlays (env-wide overlay can't disambiguate same-name collisions) #1824.)Open questions
Acceptance
GET /meta/pagewith two installed packages each shippingpage/home(with or without overlays) returns both rows, each with its own correct_packageId./apps/<pkg>/page/hometo its own package — verified in the browser with a real collision (as fix(metadata): keep each colliding item's own _packageId provenance (ADR-0048) #1822/feat(metadata): package-scoped customization overlays (ADR-0048 #1824) #1827 were).Related: #1822 (single-item/list provenance), #1827 / #1824 (package-scoped overlays).