Enable declarative custom metadata schemas for repo-backed namespaces - #2468
Merged
Conversation
A namespace's manifest can now carry `custom_metadata_schemas`, so the keys a namespace expects -- and the JSON Schema each value must satisfy -- are declared alongside the nodes that carry them, and reviewed in the same PR. Registration goes through the same helpers as the REST API, so two writers to one table cannot enforce different rules. The manifest is the whole truth for its own namespace: declared keys are upserted, and rows it no longer declares are retired. The `namespace` column is what makes that safe -- it already records who owns a row, and a global row has no owning namespace, so no deployment may retire one. `custom_metadata_schemas` is nullable because None and `[]` are different manifests. None does not manage schemas at all; `[]` manages them and declares none, which retires the namespace's rows. With a list default, every deployment predating this field would have read as the latter. Registration revives a soft-deleted row rather than inserting beside it. The unique index spans deactivated rows while every read filters them out, so an insert next to a tombstone violates the constraint -- which made a retired key permanently unregisterable, by either writer. Reviving also preserves the row's id and created_at, so a key that comes back is the same registration rather than a new one. The transaction belongs to the caller. The orchestrator opens a SAVEPOINT so a dry run can be rolled back, and committing here releases it -- so `POST /deployments/impact`, which exists only to report what a deployment would do, would have permanently registered the schemas it was asked to analyse. Index DDL is skipped for a dry run, since a rolled-back CREATE INDEX is work done for nothing.
A schema took the deploying namespace and nothing else, so a repo could only govern its whole graph at once. That is the wrong granularity for a staged rollout: a vocabulary usually starts on the part of the graph that matters most -- conformed dimensions, say -- and widens once it holds. A spec may now name its own namespace. Omitted, it still defaults to the deployment's, so nothing existing changes. Named, it must be that namespace or one beneath it: narrower is a rollout choice, while wider or sideways would let one repo govern another repo's nodes. The check lives in `set_namespaces` alongside the defaulting it already does for nodes, hierarchies and pre-aggs, and rejects a prefix that only looks like a descendant -- `shared_other` is not under `shared`. Reconciliation now covers the deploying namespace plus whatever sub-namespaces the specs name, rather than the deploying namespace alone. Both halves matter: declaring a schema for `shared.conformed` must not retire one for `shared.finance`, which another deployment owns, and an empty list must still retire the deploying namespace's own rows, which is the only thing that distinguishes "declares none" from "does not manage these".
✅ Deploy Preview for thriving-cassata-78ae72 canceled.
|
shangyian
marked this pull request as ready for review
August 28, 2026 15:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A namespace's
custom_metadatavocabulary can now be declared in the deployment manifest, next to the nodes it governs, instead of only through admin API calls:A deployment manages the complete set of schemas for the namespace it's scoped to. Any declared keys here are created, updated, or revived if previously retired. Omitting the section leaves existing schemas alone, but declaring an empty list
[]will make DJ match the (empty-list) manifest and retire any existing schemas.The schema defaults to the deploying namespace, but you can also name one to narrow it to a sub-namespace. Anything outside of the deploying namespace is rejected at spec validation, so one repo can't register schemas that govern another's nodes. Globally reserved keys remain untouchable from a deployment.
Test Plan
Last of the custom metadata schema registry stack, following #2456 and #2461.
make checkpassesmake testshows 100% unit test coverageDeployment Plan