Final step of ADR-0070 D5 (migration), split out of Epic #2278 because it is gated on a runtime precondition, not just code.
Context
The "Local / Custom (this env)" package-selector scope (objectui#1946) was a stopgap that surfaced the package-less (package_id = null) orphan bucket. ADR-0070 repurposes it as a migration affordance and says it should be removed "once an environment has no orphans."
The migration tooling that makes removal safe is already merged:
- kernel:
protocol.reassignOrphanedMetadata + POST /packages/:id/adopt-orphans (framework#2301)
- Studio UI: the "Adopt loose items" action in
PackagesPage.tsx (objectui#1983)
- new orphans are prevented at the kernel by
writable_package_required (framework#2285)
So all that remains is removing the scope itself once it is empty.
Still present (to remove)
../objectui/packages/app-shell/src:
layout/ContextSelectors.tsx — the "Local / Custom (this env)" / 本地 / 自定义(本环境) option
views/metadata-admin/package-scope.ts — isLocalScope() + the sentinel scope helpers
Acceptance
- A guard/telemetry confirms target envs report 0 orphans (
reassignOrphanedMetadata would reassign nothing), OR the scope is shown only while orphans exist (auto-hide when empty).
- Remove the "Local / Custom" scope from the selector; drop
isLocalScope and the null/sys_metadata create-destination path.
- ADR-0070 D5 §"retire the stopgaps" can be ticked.
Out of scope
The kernel null-as-legacy-overlay read path stays (ADR-0070 D5: null survives as a read-side rehydration tag for legacy rows).
Repo: ../objectui. Parent epic: #2278.
Final step of ADR-0070 D5 (migration), split out of Epic #2278 because it is gated on a runtime precondition, not just code.
Context
The "Local / Custom (this env)" package-selector scope (objectui#1946) was a stopgap that surfaced the package-less (
package_id = null) orphan bucket. ADR-0070 repurposes it as a migration affordance and says it should be removed "once an environment has no orphans."The migration tooling that makes removal safe is already merged:
protocol.reassignOrphanedMetadata+POST /packages/:id/adopt-orphans(framework#2301)PackagesPage.tsx(objectui#1983)writable_package_required(framework#2285)So all that remains is removing the scope itself once it is empty.
Still present (to remove)
../objectui/packages/app-shell/src:layout/ContextSelectors.tsx— the "Local / Custom (this env)" /本地 / 自定义(本环境)optionviews/metadata-admin/package-scope.ts—isLocalScope()+ the sentinel scope helpersAcceptance
reassignOrphanedMetadatawould reassign nothing), OR the scope is shown only while orphans exist (auto-hide when empty).isLocalScopeand the null/sys_metadatacreate-destination path.Out of scope
The kernel
null-as-legacy-overlay read path stays (ADR-0070 D5:nullsurvives as a read-side rehydration tag for legacy rows).Repo:
../objectui. Parent epic: #2278.