feat(metadata): package-scoped customization overlays (ADR-0048 #1824)#1827
Merged
Merged
Conversation
Key sys_metadata overlays by (type, name, organization_id, package_id) so two installed packages shipping the same name each carry their own overlay, instead of one physically shadowing both. - Index idx_sys_metadata_overlay_active/_draft include package_id; runtime migration uses COALESCE(package_id,'') so package-less globals stay unique. - SysMetadataRepository.whereFor/put/get scope the upsert per package (a save for B no longer overwrites A's same-name overlay; package-less → global row). - getMetaItem/getMetaItemLayered overlay fallback resolves only the global (package_id IS NULL) row on a scoped miss, never another package's row. Verified live (two packages each shipping page/showcase_task_workbench): two overlay rows coexist; ?package= single reads + ?layers= editor view each return their own overlay; index migrated in place. objectql 606 green. Follow-up: unscoped list still dedupes by bare name (collapses overlay collisions); per-package single-item + editor paths unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1824.
Problem
A
sys_metadatacustomization overlay was keyed by(type, name, organization_id)— a UNIQUE index allowing one physical row per name per org. So when two installed packages ship an item of the sametype/name, customizing one shadowed both, and a package-scoped read fell back to whichever row existed. (This is the env-overlay limitation called out at the end of #1822.)Fix
Make overlays package-aware end-to-end:
idx_sys_metadata_overlay_active/…_draftnow includepackage_id. The runtime migration (ensureOverlayIndex) usesCOALESCE(package_id, '')so package-less (global) overlays stay unique among themselves (a plain unique index treats NULLs as distinct). DROP-then-CREATE, idempotent; existing rows migrate safely.SysMetadataRepository.whereFor/put/getscope the upsert to the requested package, so a save bound to package B no longer finds and overwrites package A's same-name overlay. A package-less save targets the global row.getMetaItem/getMetaItemLayeredoverlay lookups already prefer the package-scoped row (feat(runtime): package-scoped single-item metadata resolution via ?package= (ADR-0048) #1816/fix(metadata): package-scope the Studio editor read via ?package= (ADR-0048) #1819); the fallback now resolves only the global (package_id IS NULL) overlay, never a different package's row. Package-less readers unchanged (match-any, back-compat).Frontend counterpart (objectui): the Studio editor's post-save refresh scopes its layered/draft re-read to the same package (the save already binds
?package=).Verification
Live, real collision (two packages each shipping
page/showcase_task_workbench), against the migrated DB:PUT …?package=com.objectstack.studioandPUT …?package=com.example.showcase→ two rows coexist insys_metadata(the old index would have rejected/overwritten the second).GET …?package=com.objectstack.studio→ "STUDIO OVERLAY EDIT";?package=com.example.showcase→ "SHOWCASE OVERLAY EDIT".GET …?layers=true&package=com.objectstack.studio(Studio editor view) →overlay/effective= "STUDIO OVERLAY EDIT".… (type, name, organization_id, COALESCE(package_id, '')) WHERE state = 'active'.606 objectql tests green (added a per-package write-scoping test; existing ADR-0005 overlay tests updated for the
package_iddiscriminator).Known follow-up (not this PR)
The unscoped list (
GET /meta/:typewith no?package=) still dedupes by bare name, so when two packages both carry an overlay on the same name the list collapses them — the per-package single-item and Studio editor paths are unaffected. This is the same byName-dedup limitation noted in #1822; tracked for the list-dedup-by-name work.🤖 Generated with Claude Code