Found working the #3909 G8 checklist on main @ a1a855a28 (the rc.3 train tip).
#4509 closed the door on runtime-created jobs by setting registry flags:
// packages/spec/src/kernel/metadata-plugin.zod.ts:658
{ type: 'job', label: 'Background Job', …, supportsOverlay: false,
allowOrgOverride: false, allowRuntimeCreate: false, … }
and its changeset states the intent unambiguously:
allowRuntimeCreate: false — no "create job" in Studio or via PUT /meta.
allowOrgOverride: false — no per-org job fork…
PUT /meta still creates one.
PUT /api/v1/meta/job/rc3_runtime_job
{"name":"rc3_runtime_job","label":"J",
"schedule":{"type":"cron","expression":"0 0 * * *"},"handler":"nope"}
→ 200 {"success":true,"message":"Saved customization overlay (env-wide) — type=job, name=rc3_runtime_job"}
GET /api/v1/meta/job
→ listed, with handler "nope"
handler: "nope" names no function in any compiled bundle — precisely the record #4509 argues can never be scheduled, saved and reported as success.
Not job-specific — the gate looks unenforced generally
agent is the only other type carrying allowRuntimeCreate: false. It behaves the same:
PUT /api/v1/meta/agent/rc3_agent_probe {"name":…,"label":"A","role":"assistant","instructions":"be helpful"}
→ 200 {"success":true,"message":"Saved customization overlay (env-wide) — type=agent, …}
So both flagged types accept a runtime create. A minimal-payload PUT to object / flow / job all return 422, which is schema validation firing first — that is what makes this easy to miss: the gate never runs, and only a payload that passes the schema reveals it.
supportsOverlay: false appears equally unenforced — the success message calls the row a "customization overlay" for a type declared not to support them.
Why it matters
This is the failure mode ADR-0049 exists to prevent, one level up: the enforcement flag itself is the silently-inert declaration. A reader of the registry (or of the #4509 changeset, or of the release notes) concludes Studio and PUT /meta refuse these types. Studio presumably reads allowRuntimeCreate to decide whether to show "create", so the UI honours it while the API underneath does not — the "UI-hidden but server-open" shape ADR-0066 D4 calls out for actions.
Expected
The metadata write path consults the registry's allowRuntimeCreate (and supportsOverlay / allowOrgOverride) before persisting, and refuses with a catalogued code naming the type and why it is code-only — the same shape the retired-key refusals in this same wave produce. A regression test per flagged type would pin it, since the flags are data and new types will keep arriving.
Found during the #3909 rc.3 verification (G8).
Found working the #3909 G8 checklist on
main@a1a855a28(the rc.3 train tip).#4509closed the door on runtime-created jobs by setting registry flags:and its changeset states the intent unambiguously:
PUT /metastill creates one.handler: "nope"names no function in any compiled bundle — precisely the record #4509 argues can never be scheduled, saved and reported as success.Not job-specific — the gate looks unenforced generally
agentis the only other type carryingallowRuntimeCreate: false. It behaves the same:So both flagged types accept a runtime create. A minimal-payload PUT to
object/flow/joball return 422, which is schema validation firing first — that is what makes this easy to miss: the gate never runs, and only a payload that passes the schema reveals it.supportsOverlay: falseappears equally unenforced — the success message calls the row a "customization overlay" for a type declared not to support them.Why it matters
This is the failure mode ADR-0049 exists to prevent, one level up: the enforcement flag itself is the silently-inert declaration. A reader of the registry (or of the #4509 changeset, or of the release notes) concludes Studio and
PUT /metarefuse these types. Studio presumably readsallowRuntimeCreateto decide whether to show "create", so the UI honours it while the API underneath does not — the "UI-hidden but server-open" shape ADR-0066 D4 calls out for actions.Expected
The metadata write path consults the registry's
allowRuntimeCreate(andsupportsOverlay/allowOrgOverride) before persisting, and refuses with a catalogued code naming the type and why it is code-only — the same shape the retired-key refusals in this same wave produce. A regression test per flagged type would pin it, since the flags are data and new types will keep arriving.Found during the #3909 rc.3 verification (G8).