Summary
Split out of #7743, which recorded two entangled defects. #7743's PR closes the first (an artifact-backed field override is now refused 403 NOT_OVERRIDABLE). This is the second, and it is independent: a field write that is entirely legitimate under the registry declaration is accepted, persisted, reported valid — and read by nothing.
The registry declares field with allowRuntimeCreate: true, so authoring a brand-new field through PUT /api/v1/meta/field/<object>.<name> is a supported capability. It just does not work. declared ≠ enforced, Prime Directive #10.
Why this is its own card, not part of #7743
#7743's dispatch predicted that refusing the override would destroy the evidence for the inertness. Measured: it does not. The inertness has two halves and only one of them is behind the new refusal:
So this card has a live repro, not archived evidence.
Measured (booted showcase, admin bearer)
Before #7743's fix — both halves:
PUT /api/v1/meta/field/showcase_task.title {name:'title', label:'Tampered', type:'text'}
→ 200 {"success":true,"state":"active","message":"Saved field 'showcase_task.title' (env-wide…)"}
GET /api/v1/meta/field/showcase_task.title
→ {"item":{"name":"title","label":"Tampered","type":"text","_diagnostics":{"valid":true}}}
GET /api/v1/meta/object/showcase_task
→ title.label === 'Title' ← unchanged. 24 fields.
After #7743's fix — the create half, unchanged:
PUT /api/v1/meta/field/showcase_task.zz_new_probe {name:'zz_new_probe', label:'Probe', type:'text'}
→ 200 {"success":true,"state":"active","message":"Saved field 'showcase_task.zz_new_probe' (env-wide…)"}
GET /api/v1/meta/field/showcase_task.zz_new_probe
→ {"item":{…,"_diagnostics":{"valid":true}}}
GET /api/v1/meta/object/showcase_task
→ fields count === 24, 'zz_new_probe' in fields === false ← the field does not exist
The row answers success twice over — accepted, and stored valid — for a document no consumer reads.
Where to look
A field write lands in sys_metadata as a standalone row type='field', name='<object>.<field>'. Nothing merges standalone field rows into an object's effective schema: the object's fields come from the object artifact plus its own overlay row, and applyRegistryWriteThrough routes only type === 'object' into applyObjectRegistryMutation. A field row takes the generic hydrateOverlayIntoRegistry branch, and field is supportsOverlay: false, so there is no overlay merge for it either.
Consistent with field having no standalone artifact loader at all (filePatterns: ['**/*.field.ts'] matches nothing in any app — fields are authored inside ObjectSchema.fields), which is the same structural fact #7743's root cause turned on.
The decision this needs
Three coherent outcomes; this is a maintainer call, not a mechanical fix:
- Implement it — a
field write composes into the parent object (registry write-through + read-path merge + column sync), making allowRuntimeCreate: true true. - Retire the write channel — ADR-0049 enforce-or-remove: if a field is only ever authored as part of its object,
field should not carry allowRuntimeCreate: true, and the route should refuse with a sentence pointing at PUT /meta/object/<name>. - Keep the row, document it as inert — the weakest, and it is the shape ADR-0049 forbids.
⚠️ If (1) is ever chosen, note that #7743's overlay refusal must stay: making field overrides legal is a separate decision from making field creates work, and #7743 pins the override as refused in both topologies.
Source
Extracted from #7743 (itself from the QA run #7695). Measured on origin/main at bcea363 plus #7743's fix, on the showcase with writable runtime packages.
Summary
Split out of #7743, which recorded two entangled defects. #7743's PR closes the first (an artifact-backed
fieldoverride is now refused 403NOT_OVERRIDABLE). This is the second, and it is independent: afieldwrite that is entirely legitimate under the registry declaration is accepted, persisted, reported valid — and read by nothing.The registry declares
fieldwithallowRuntimeCreate: true, so authoring a brand-new field throughPUT /api/v1/meta/field/<object>.<name>is a supported capability. It just does not work.declared ≠ enforced, Prime Directive #10.Why this is its own card, not part of #7743
#7743's dispatch predicted that refusing the override would destroy the evidence for the inertness. Measured: it does not. The inertness has two halves and only one of them is behind the new refusal:
showcase_task.title) — now 403, no longer observable. ✔ expectedshowcase_task.zz_new_probe) — still 200, still inert, still reproducible onmainafter org-override-registry-gate: thefieldoverlay lock is not enforced — an artifact-backed field PUT is accepted 200 (and is inert) #7743's PR lands.So this card has a live repro, not archived evidence.
Measured (booted showcase, admin bearer)
Before #7743's fix — both halves:
After #7743's fix — the create half, unchanged:
The row answers success twice over — accepted, and stored valid — for a document no consumer reads.
Where to look
A
fieldwrite lands insys_metadataas a standalone rowtype='field',name='<object>.<field>'. Nothing merges standalonefieldrows into an object's effective schema: the object'sfieldscome from the object artifact plus its own overlay row, andapplyRegistryWriteThroughroutes onlytype === 'object'intoapplyObjectRegistryMutation. Afieldrow takes the generichydrateOverlayIntoRegistrybranch, andfieldissupportsOverlay: false, so there is no overlay merge for it either.Consistent with
fieldhaving no standalone artifact loader at all (filePatterns: ['**/*.field.ts']matches nothing in any app — fields are authored insideObjectSchema.fields), which is the same structural fact #7743's root cause turned on.The decision this needs
Three coherent outcomes; this is a maintainer call, not a mechanical fix:
fieldwrite composes into the parent object (registry write-through + read-path merge + column sync), makingallowRuntimeCreate: truetrue.fieldshould not carryallowRuntimeCreate: true, and the route should refuse with a sentence pointing atPUT /meta/object/<name>.Source
Extracted from #7743 (itself from the QA run #7695). Measured on
origin/mainatbcea363plus #7743's fix, on the showcase with writable runtime packages.