ADR: framework#2277 (ADR-0070, Accepted). This card tracks the cross-repo rollout.
Status (2026-06-27): functionally complete. All six decisions (D1–D6) are implemented and merged across framework / ../objectui / ../cloud, and ADR-0070 is Accepted with an end-to-end live dogfood. The full lifecycle is now also covered by an automated gate (framework#2358). One deliberately-deferred tail remains, tracked as #2359 (retire the "Local / Custom" stopgap scope once envs are orphan-free). See the status comment below for the PR-by-PR map.
Problem (from a business-user Studio dogfood pass)
Authored metadata can end up orphaned (package_id = null) with no container to delete/export — "a pile of loose metadata, how do I clean it up?". Root cause: no package-first contract. Stopgaps shipped: framework#2252 (coerce-to-null), objectui#1946 (Local scope). We adopt the Airtable base model: create/select a writable package (base) first; author into it; manage/delete/export by base.
Rollout checklist
Open questions (resolved)
- Auto-provision a base on first authoring → resolved: a prompted/named one-click base (cloud auto-creates a named base; no silent
com.workspace).
allowOrgOverride in single-tenant → keep overlay for surgical tweaks (design note; non-blocking).
- Delete-cascade also delete records? → resolved:
deletePackage({ keepData }) + a "structure-only delete" UI option (objectui#1983).
- Base naming vs stable id (
app.<slug>) → surface a name, keep the id stable (design note).
Repos: framework (kernel, ADR, dogfood gate), ../objectui (Studio), ../cloud (service-ai-studio). Remaining tail: #2359.
ADR: framework#2277 (ADR-0070, Accepted). This card tracks the cross-repo rollout.
Problem (from a business-user Studio dogfood pass)
Authored metadata can end up orphaned (
package_id = null) with no container to delete/export — "a pile of loose metadata, how do I clean it up?". Root cause: no package-first contract. Stopgaps shipped: framework#2252 (coerce-to-null), objectui#1946 (Local scope). We adopt the Airtable base model: create/select a writable package (base) first; author into it; manage/delete/export by base.Rollout checklist
isWritablePackagepredicate + reject runtime creates with no writable target (code: 'writable_package_required'); evolved fix(objectql): don't stamp runtime-authored metadata into a loaded code package #2252 coerce-to-null → reject.@objectstack/objectqlprotocol.saveMetaItem. ✅ framework#2285../objectui. ✅ objectui#1970../cloudservice-ai-studio: dropped auto-com.workspacefallback; auto-creates an intentional named base viainstallPackage; requires package context. ✅ cloud#479 / chore(deps)(deps): bump commander from 11.1.0 to 14.0.3 #481 / tests chore(deps)(deps): bump react and @types/react #480 (+ follow-ups Add auth plugin package with route scaffolding and service registration #577 / Fix startup message to show correct API endpoint #588 / Align authentication endpoints with better-auth protocol #590 "Edit with AI")duplicatePackage(re-namespace + reference rewrite). UI: Duplicate / structure-only delete. ✅ framework#2299, objectui#1983reassignOrphanedMetadata+POST /packages/:id/adopt-orphans(+ "Adopt loose items" UI) bulk-rebind legacynullrows. ✅ framework#2301, objectui#1983. ◐ tail: removing the chore(spec): prune 7 dead field governance/compliance props (dead-surface plan) #1946 "Local / Custom" scope is gated on envs being orphan-free → tracked in ADR-0070 D5 tail: retire the "Local / Custom" stopgap scope from the Studio selector (once envs are orphan-free) #2359. (fix(objectql): don't stamp runtime-authored metadata into a loaded code package #2252 coerce-to-null already replaced by the D1 reject.)@objectstack/dogfoodcoverage: create→bind→publish→editable→discoverable→delete-cascade + adopt-orphans + duplicate, against the real booted stack. ✅ framework#2303 (D1/D2) + framework#2358 (full D3/D4/D5 lifecycle); cloud#594 / [WIP] Release patch version for updates #598 (quantified build-quality evals).Open questions (resolved)
com.workspace).allowOrgOverridein single-tenant → keep overlay for surgical tweaks (design note; non-blocking).deletePackage({ keepData })+ a "structure-only delete" UI option (objectui#1983).app.<slug>) → surface a name, keep the id stable (design note).Repos:
framework(kernel, ADR, dogfood gate),../objectui(Studio),../cloud(service-ai-studio). Remaining tail: #2359.