Recording only, per Prime Directive #10 — found while implementing #6621 (PR #6807), on a different function than the one that card touches, and pre-existing on both callers.
The fact (measured on origin/main @ 4bb6f01af)
deleteMetaItem ends its repository delete with restoreArtifactRegistryView — the #6687 three-tier heal. That walk operates entirely on SchemaRegistry's generic metadata map: removeRuntimeShadow, registerItem, and removeOverlayEntry all address this.metadata.get(type).
An object lives in two places. applyRegistryWriteThrough → applyObjectRegistryMutation writes both:
this.engine.registry.registerItem(request.type, request.item, 'name'); // metadata map
this.engine.registry.registerObject({ ...item, _provenance: 'org' }, pkg); // objectContributors
The heal only undoes the first. Measured with the real SysMetadataRepository over an in-memory engine, a runtime-created object saved and then deleted:
BEFORE delete: metadata['object'] keys -> ["myapp_invoice"] | objectContributors -> ["myapp_invoice"]
AFTER delete: metadata['object'] keys -> [] | objectContributors -> ["myapp_invoice"]
registry.getObject('myapp_invoice') -> STILL SERVED
registry.getItem('object','myapp_invoice') -> STILL SERVED (getItem special-cases the
object type back to getObject)
getObject is the surface data CRUD dispatches on, so the half that survives is the load-bearing half: the sys_metadata row is gone and the object is still resolvable, syncable and writable for the life of the process. The half that is cleaned (metadata['object']) backs listing, which is the less consequential of the two.
Why there is no one-line fix
SchemaRegistry has no per-(type, name) object unregister at all — the only removal verb is unregisterObjectsByPackage(packageId, force) (packages/objectql/src/registry.ts:1339), which is package-wide and throws when an owner still has extenders. So closing this is a registry API change (a name-addressed unregisterObject honouring the ADR-0029 single-owner/extender rules), not a protocol-side call.
Reachability
Live on the ordinary Studio path: delete a runtime-created object, and the running process keeps dispatching it. Both delete-shaped callers are affected identically, because both run the same heal:
Not the same as #6725
#6725 is the write side of the same map-vs-contributors asymmetry (MetadataFacade.register('object', …) writing where its own reads do not look), and is dormant in-tree. This one is the removal side, on the shipped protocol path, and is reachable today. Same underlying split in SchemaRegistry, two different seams — a fix for either does not close the other, though a name-addressed object unregister would be the natural place to settle both.
Related: #6687, #5079, #4521, #6621 (PR #6807), #6725, ADR-0029.
Recording only, per Prime Directive #10 — found while implementing #6621 (PR #6807), on a different function than the one that card touches, and pre-existing on both callers.
The fact (measured on
origin/main@4bb6f01af)deleteMetaItemends its repository delete withrestoreArtifactRegistryView— the #6687 three-tier heal. That walk operates entirely onSchemaRegistry's genericmetadatamap:removeRuntimeShadow,registerItem, andremoveOverlayEntryall addressthis.metadata.get(type).An
objectlives in two places.applyRegistryWriteThrough→applyObjectRegistryMutationwrites both:The heal only undoes the first. Measured with the real
SysMetadataRepositoryover an in-memory engine, a runtime-created object saved and then deleted:getObjectis the surface data CRUD dispatches on, so the half that survives is the load-bearing half: thesys_metadatarow is gone and the object is still resolvable, syncable and writable for the life of the process. The half that is cleaned (metadata['object']) backs listing, which is the less consequential of the two.Why there is no one-line fix
SchemaRegistryhas no per-(type, name)object unregister at all — the only removal verb isunregisterObjectsByPackage(packageId, force)(packages/objectql/src/registry.ts:1339), which is package-wide and throws when an owner still has extenders. So closing this is a registry API change (a name-addressedunregisterObjecthonouring the ADR-0029 single-owner/extender rules), not a protocol-side call.Reachability
Live on the ordinary Studio path: delete a runtime-created object, and the running process keeps dispatching it. Both delete-shaped callers are affected identically, because both run the same heal:
deleteMetaItem(single-item delete / "reset to factory default");revertCommit's soft-remove limb, which PR fix(metadata-protocol): a successful revertCommit refreshes the SchemaRegistry, on both limbs (#6621) #6807 just wired to the same heal — that PR pins the two callers as leaving the same registry view precisely so the parity assertion stays green when this is fixed for both, rather than freezing the current behaviour.Not the same as #6725
#6725 is the write side of the same map-vs-contributors asymmetry (
MetadataFacade.register('object', …)writing where its own reads do not look), and is dormant in-tree. This one is the removal side, on the shipped protocol path, and is reachable today. Same underlying split inSchemaRegistry, two different seams — a fix for either does not close the other, though a name-addressed object unregister would be the natural place to settle both.Related: #6687, #5079, #4521, #6621 (PR #6807), #6725, ADR-0029.