Split out of #15950 (fixed there: PR #16223), which deliberately left this half alone.
What #16223 does, and the residual it leaves
#15950 was that the runtime authoring gate's resolution universe came from the
SchemaRegistry alone, so an item saved through PUT /meta/:type was a phantom
"unknown" reference until the process restarted. PR #16223 folds the stored half
onto the registry half — additively: a sys_metadata row contributes a name
the registry does not already carry, and never displaces a registry entry.
The additivity is deliberate and argued in the method's docblock: an object's
registry copy is its RESOLVED schema (ADR-0029 D9.2, base layer plus its
extend contributors) while a sys_metadata row is the base layer alone, which
is exactly why getMetaItems runs foldObjectExtendersFromRegistry when its own
merge lets an overlay win. Letting a raw row displace a resolved body would have
traded one phantom for a subtler one.
The residual that leaves: where an org (or env-wide) overlay REDEFINES an item
a code package already declares, the gate still judges that item's CONTENT from
the registry's version.
The shape to check
A code package ships dataset/orders_ds with a measure order_count. A tenant
overrides that dataset through PUT /meta/dataset/orders_ds and removes
order_count. The name resolves either way, so widget-dataset-unknown is
silent — but a dashboard widget binding values: ['order_count'] is judged
against the code-package body, where the measure still exists, and is accepted.
The runtime then serves the overlay, where it does not.
That is a phantom in the OPPOSITE direction to #15950: an acceptance that should
have been a refusal, rather than a refusal that should have been an acceptance.
Status of this reading
⚠️ REASONED FROM THE MERGE RULE, NOT DRIVEN. #16223's round measured the
absence-direction defect end to end and pinned it; this direction was derived
from the additive merge it chose and was not reproduced. Whoever takes this
should reproduce it first — the same harness shape works
(packages/metadata-protocol/src/protocol.runtime-gate-stored-universe.test.ts
drives saveMetaItem over a stub engine, and a code-package dataset plus an
overriding store row is a two-line change to its fixtures).
It is also possible the right answer is "the overlay body should win, folded the
way getMetaItems folds it" rather than "the gate should notice the
disagreement" — those are different repairs with different blast radii, and
picking between them is the work.
Where
packages/metadata-protocol/src/protocol.ts — foldStoredCollection, the
"The fold is ADDITIVE, deliberately" section of its docblock states this residual
in the source, so a reader of the code finds it.
Generated by Claude Code
Split out of #15950 (fixed there: PR #16223), which deliberately left this half alone.
What #16223 does, and the residual it leaves
#15950 was that the runtime authoring gate's resolution universe came from the
SchemaRegistry alone, so an item saved through
PUT /meta/:typewas a phantom"unknown" reference until the process restarted. PR #16223 folds the stored half
onto the registry half — additively: a
sys_metadatarow contributes a namethe registry does not already carry, and never displaces a registry entry.
The additivity is deliberate and argued in the method's docblock: an object's
registry copy is its RESOLVED schema (ADR-0029 D9.2, base layer plus its
extendcontributors) while asys_metadatarow is the base layer alone, whichis exactly why
getMetaItemsrunsfoldObjectExtendersFromRegistrywhen its ownmerge lets an overlay win. Letting a raw row displace a resolved body would have
traded one phantom for a subtler one.
The residual that leaves: where an org (or env-wide) overlay REDEFINES an item
a code package already declares, the gate still judges that item's CONTENT from
the registry's version.
The shape to check
A code package ships
dataset/orders_dswith a measureorder_count. A tenantoverrides that dataset through
PUT /meta/dataset/orders_dsand removesorder_count. The name resolves either way, sowidget-dataset-unknownissilent — but a dashboard widget binding
values: ['order_count']is judgedagainst the code-package body, where the measure still exists, and is accepted.
The runtime then serves the overlay, where it does not.
That is a phantom in the OPPOSITE direction to #15950: an acceptance that should
have been a refusal, rather than a refusal that should have been an acceptance.
Status of this reading
absence-direction defect end to end and pinned it; this direction was derived
from the additive merge it chose and was not reproduced. Whoever takes this
should reproduce it first — the same harness shape works
(
packages/metadata-protocol/src/protocol.runtime-gate-stored-universe.test.tsdrives
saveMetaItemover a stub engine, and a code-package dataset plus anoverriding store row is a two-line change to its fixtures).
It is also possible the right answer is "the overlay body should win, folded the
way
getMetaItemsfolds it" rather than "the gate should notice thedisagreement" — those are different repairs with different blast radii, and
picking between them is the work.
Where
packages/metadata-protocol/src/protocol.ts—foldStoredCollection, the"The fold is ADDITIVE, deliberately" section of its docblock states this residual
in the source, so a reader of the code finds it.
Generated by Claude Code