Filed by the domain:ui execution seat (session session_012u2pRjcqAYtoEjgr3wwhnK), surfaced and measured while implementing #5024 (PR #5672). Filed by the seat rather than the implementer because the GitHub API quota was exhausted at their reporting turn and they declined to file without a dedupe search — correctly.
Measured
packages/data-objectstack/src/metadata-client.ts, MetadataClient.layered() reads a raw res.json() body and casts straight through — no parse, no allowlist, no default:
...(body.lock !== undefined ? { lock: body.lock as MetadataLayered['lock'] } : {})
The same treatment is applied to the entire ADR-0010 protection envelope: lock, lockSource, provenance, overlayScope, editable, deletable, resettable.
@objectstack/spec 17.1.0 declares all of them, in GetMetaItemLayeredResponseSchema. The producer has a schema; the consumer ignores it.
Why this is the real root cause of #5024's symptom
#5024 was written as a duplicated-union card, and the duplication was real. But a union types what this repo writes and constrains nothing about what a server sends. The consequence, measured on the real render path rather than argued:
- The gate that opens the lock banner is
isLocked = layered?.lock && layered.lock !== 'none' — true for any non-none value.
- So a server sending a lock state this console has never heard of opened the amber box, drew the padlock and the border, and rendered the title
<div> completely empty. A locked-looking banner that never says what is locked or why.
- No fifth state ever had to be added to this repo for that to happen.
#5672 fixes the symptom properly — the banner now names the unrecognised token to the operator, who is the only person able to report which state their server actually sent. It does not fix this, deliberately: making layered() parse would move an accept set, which is a different card by the seat's own dispatch rules.
Ask
Decide whether layered() should validate against GetMetaItemLayeredResponseSchema at the boundary.
Worth stating plainly so the next reader does not mis-scope it: the fix is not "add a .parse()". Parsing turns a silently-wrong render into a thrown or rejected response, which is a behaviour change for every consumer of this client, not a tightening of types. The real question is what a metadata console should do when the server speaks a dialect it does not know — reject, degrade, or pass through and label. #5672 chose pass through and label, for one field. This card is where that choice gets made for the envelope.
Filed unassigned.
Filed by the
domain:uiexecution seat (sessionsession_012u2pRjcqAYtoEjgr3wwhnK), surfaced and measured while implementing #5024 (PR #5672). Filed by the seat rather than the implementer because the GitHub API quota was exhausted at their reporting turn and they declined to file without a dedupe search — correctly.Measured
packages/data-objectstack/src/metadata-client.ts,MetadataClient.layered()reads a rawres.json()body and casts straight through — no parse, no allowlist, no default:The same treatment is applied to the entire ADR-0010 protection envelope:
lock,lockSource,provenance,overlayScope,editable,deletable,resettable.@objectstack/spec17.1.0 declares all of them, inGetMetaItemLayeredResponseSchema. The producer has a schema; the consumer ignores it.Why this is the real root cause of #5024's symptom
#5024 was written as a duplicated-union card, and the duplication was real. But a union types what this repo writes and constrains nothing about what a server sends. The consequence, measured on the real render path rather than argued:
isLocked = layered?.lock && layered.lock !== 'none'— true for any non-nonevalue.<div>completely empty. A locked-looking banner that never says what is locked or why.#5672 fixes the symptom properly — the banner now names the unrecognised token to the operator, who is the only person able to report which state their server actually sent. It does not fix this, deliberately: making
layered()parse would move an accept set, which is a different card by the seat's own dispatch rules.Ask
Decide whether
layered()should validate againstGetMetaItemLayeredResponseSchemaat the boundary.Worth stating plainly so the next reader does not mis-scope it: the fix is not "add a
.parse()". Parsing turns a silently-wrong render into a thrown or rejected response, which is a behaviour change for every consumer of this client, not a tightening of types. The real question is what a metadata console should do when the server speaks a dialect it does not know — reject, degrade, or pass through and label. #5672 chose pass through and label, for one field. This card is where that choice gets made for the envelope.Filed unassigned.