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
Out-of-scope finding measured while scoping #6853 (registry heal / map-vs-contributors split). Recorded, not claimed. Pre-existing.
Fact (measured on origin/main @ 51f2bb8c3)
applyObjectRegistryMutation (packages/metadata-protocol/src/protocol.ts:7870) mirrors an accepted object overlay write into the registry with:
this.engine.registry.registerItem(request.type,request.item,'name');try{this.engine.registry.registerObject({ ...(request.itemasRecord<string,unknown>),_provenance: 'org'}asany,request.packageId||'sys_metadata',);}catch(err: any){console.warn(`[Protocol] registerObject failed for ${request.name}: ${err?.message??err}`);}
(generics spaced so the GitHub body sanitizer does not eat them)
SchemaRegistry.registerObject (packages/objectql/src/registry.ts:1148) throws when an own contributor from a different package already holds the name. So whenever the row's package_id does not equal the packaged owner's package id — including the ordinary package-less row, which normalises to the sys_metadata sentinel — the second half of the write is thrown away, warn-logged, and the save still reports success.
The two registry views then disagree permanently:
metadata['object'][name] (written by registerItem) holds the overlay body, so GET /api/v1/meta/object/:name serves it;
objectContributors still holds the package body, and that is what registry.getObject resolves — the surface assertObjectRegistered and every data-CRUD dispatch reads.
Measured with the protocol-delete-object-registry-heal.test.ts harness (real SchemaRegistry, real SysMetadataRepository), a packaged myapp_invoice owned by app.myapp plus a package-less overlay save carrying only name + overlay_only:
[save warning] [Protocol] registerObject failed for myapp_invoice: Object "myapp_invoice" is already
owned by package "app.myapp". Package "sys_metadata" cannot claim ownership.
[contributors] packageId=app.myapp ownership=own provenance=package
fields=[ ... name, amount, packaged_only ] <- the PACKAGE body, untouched
[metadata map] plain key "myapp_invoice" present <- the OVERLAY body
[getObject] fields=[ ... name, amount, packaged_only ] <- data plane never saw the overlay
The save's own receipt reports success, and nothing in the response says the runtime discarded half of it.
Reachability
Save path: needs the documented operator escape hatch (OS_METADATA_WRITABLE=object) or an equivalent door, because both the protocol gate (protocol.ts:8434) and SysMetadataRepository.assertAllowed (sys-metadata-repository.ts:1037) refuse an overlay over an artifact-backed object otherwise (measured: NOT_OVERRIDABLE/403 on both tenant and control-plane kernels).
Boot path: loadMetaFromDb (protocol.ts:11753) makes the same registerObject call for every stored object row. There the throw is counted — errors++ plus a Failed to hydrate warning (protocol.ts:11789) — so the boot leg is at least honest about it; the save leg is not.
Dispositions worth pricing (no recommendation forced)
Fail the save. Turn the swallowed throw into a named refusal (the overlay cannot claim ownership of a name another package owns) so declared = enforced and the caller learns the write will not take effect. Cost: a write that "worked" before now 4xx-es; needs an error code + wording decision.
Out-of-scope finding measured while scoping #6853 (registry heal / map-vs-contributors split). Recorded, not claimed. Pre-existing.
Fact (measured on
origin/main@51f2bb8c3)applyObjectRegistryMutation(packages/metadata-protocol/src/protocol.ts:7870) mirrors an acceptedobjectoverlay write into the registry with:(generics spaced so the GitHub body sanitizer does not eat them)
SchemaRegistry.registerObject(packages/objectql/src/registry.ts:1148) throws when anowncontributor from a different package already holds the name. So whenever the row'spackage_iddoes not equal the packaged owner's package id — including the ordinary package-less row, which normalises to thesys_metadatasentinel — the second half of the write is thrown away, warn-logged, and the save still reports success.The two registry views then disagree permanently:
metadata['object'][name](written byregisterItem) holds the overlay body, soGET /api/v1/meta/object/:nameserves it;objectContributorsstill holds the package body, and that is whatregistry.getObjectresolves — the surfaceassertObjectRegisteredand every data-CRUD dispatch reads.Measured with the
protocol-delete-object-registry-heal.test.tsharness (realSchemaRegistry, realSysMetadataRepository), a packagedmyapp_invoiceowned byapp.myappplus a package-less overlay save carrying onlyname+overlay_only:The save's own receipt reports success, and nothing in the response says the runtime discarded half of it.
Reachability
OS_METADATA_WRITABLE=object) or an equivalent door, because both the protocol gate (protocol.ts:8434) andSysMetadataRepository.assertAllowed(sys-metadata-repository.ts:1037) refuse an overlay over an artifact-backedobjectotherwise (measured:NOT_OVERRIDABLE/403 on both tenant and control-plane kernels).loadMetaFromDb(protocol.ts:11753) makes the sameregisterObjectcall for every storedobjectrow. There the throw is counted —errors++plus aFailed to hydratewarning (protocol.ts:11789) — so the boot leg is at least honest about it; the save leg is not.Dispositions worth pricing (no recommendation forced)
own, so the ownership rule is never reached and both layers coexist. This subsumes the finding but is the same contributor-model contract change Registry heal restores the metadata-map view but never re-registers a packaged contributor definition an overlay save replaced #6853 is escalating — see that card's option set.Related
MetadataFacade.register('object', …)writes where neither of its own object reads look #6725 (MetadataFacade.register('object', …)writing where its own reads do not look)objectis still served bySchemaRegistry.getObject— the registry heal reaches themetadatamap but neverobjectContributors#6808 / PR fix(objectql): deleting anobjectreally unregisters it — a name-addressedSchemaRegistry.unregisterObject(#6808) #6818, fix(objectql,metadata-protocol): a deleted runtime-created overlay leaves the registry, so list/get/dispatch agree (#5079) #6687, ADR-0029, ADR-0005