Context
sys_permission_set currently has two stores:
- Authoritative metadata — the layered metadata overlay (
sys_metadata), written by Studio env-scope edits (saveMetaItem / client.layered).
- Queryable data record — snake_case JSON-string columns that Setup reads for lists and user assignment.
These were only synced at boot and on publish. Env-scope metadata edits did not project onto the data record, so Setup showed stale facets — the ADR-0056 display-freshness gap (#2857).
What's already done
framework #2867 (closing #2857) added an onMetadataMutation subscriber that projects env-authored permission-set edits onto the data record.
This is a sync band-aid. It re-couples two independent sources of truth after the fact.
The remaining problem
Two authoritative stores can still drift. Any write path that bypasses the subscriber — a bulk import, a future API, a migration, a background job — desyncs metadata from the data record, and the two disagree with no single winner. The projection is eventually-consistent glue, not a cure for having two truths.
Proposed work
Make the data record a pure read-model:
- The metadata overlay is the only authoritative store.
- The data record is projected from it (read-only) and never independently authoritative — reads that need SQL/query go through the projection; writes always target metadata.
- Alternatively, evaluate collapsing to a single store if the query needs can be served from metadata directly.
This needs an ADR (follow-up to ADR-0056) to choose the direction and define the migration/backfill path.
Acceptance criteria
References
Follow-up raised after landing the #2867 projection fix — this issue is the durable root-cause fix.
Context
sys_permission_setcurrently has two stores:sys_metadata), written by Studio env-scope edits (saveMetaItem/client.layered).These were only synced at boot and on publish. Env-scope metadata edits did not project onto the data record, so Setup showed stale facets — the ADR-0056 display-freshness gap (#2857).
What's already done
framework #2867 (closing #2857) added an
onMetadataMutationsubscriber that projects env-authored permission-set edits onto the data record.This is a sync band-aid. It re-couples two independent sources of truth after the fact.
The remaining problem
Two authoritative stores can still drift. Any write path that bypasses the subscriber — a bulk import, a future API, a migration, a background job — desyncs metadata from the data record, and the two disagree with no single winner. The projection is eventually-consistent glue, not a cure for having two truths.
Proposed work
Make the data record a pure read-model:
This needs an ADR (follow-up to ADR-0056) to choose the direction and define the migration/backfill path.
Acceptance criteria
References
Follow-up raised after landing the #2867 projection fix — this issue is the durable root-cause fix.