You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Filed by the domain:metadata execution seat (#6367, session session_012WMpuAfA2KSdDjGF6tm1bH) out of #8154's dev report. Unassigned and deliberately NOT lane-labelled — it lands in packages/spec, so triage should route it to domain:spec (#6017), the single owner of that package.
Why this card exists
#8154 asks for a generic per-type redaction hook on the metadata read path (GET /api/v1/meta/datasources serves stored cleartext credentials; datasource is the first consumer, not the fix). Its dev measured that the hook's registry cannot live in packages/metadata-protocol, and that measurement is the whole content of this card.
The dependency graph forbids it. The type owners that must register a redactor are service packages — service-datasource today, and #8009's SSO seat next. No service or connector package depends on @objectstack/metadata-protocol. Verified independently by the PM before filing:
git grep -l "@objectstack/metadata-protocol" origin/main \
-- 'packages/services/*/package.json' 'packages/connectors/*/package.json'
→ (no matches)
# control — the packages that DO depend on it resolve normally:
git grep -ln "PLURAL_TO_SINGULAR" origin/main -- packages/
→ packages/metadata-protocol/… , packages/metadata/… , packages/objectql/… , packages/lint/…
⇒ a registry in metadata-protocol is unreachable from the packages that must call it. @objectstack/spec/kernel is the seam every type owner already imports, alongside registerMetadataTypeSchema and registerMetadataTypeActions — this is the same shape, not a new concept.
The ask
A per-type redaction registration seam in @objectstack/spec/kernel, beside the two existing registerMetadataType* functions.
⛔ Two alternatives were considered and rejected on measured grounds — do not re-derive them:
Two implementations, both derived from the driver contracts — duplicates a security list across two doors that must agree. That drift is a cost this repo keeps paying.
Register the redactor from DatasourceAdminServicePlugin.init (the seam that already calls registerMetadataTypeActions) — ⛔ fail-open, and measured to be so. That plugin is opt-in: the runtime does not install it; only tests, apps and the CLI do. sys_metadata rows and the /meta read exits exist regardless. So a host storing datasource rows without that plugin would serve them in cleartext with the hook installed and looking healthy — the worst available outcome, because it reads as protected.
⚠️ Model tiering — no downward discretion
This card widens @objectstack/spec's public surface (a new registration seam, plus a moved export). Under the seat rule that is the domain:spec semantic lane ⇒ claude-fable-5, not opus. An error in the one contract package poisons every downstream consumer.
Consumer, and the ordering
#8154 consumes this and is Blocked-by: it — contract-first: the seam lands here, the metadata read path consumes it. #8154 additionally carries a write-path carry-forward whose absence is a data-loss bug, measured on the consumer side: saveMetaItemaccepts a redacted datasource body and persists the credential away, so a read scrub with no inverse converts today's loud 422 into silent credential deletion on an ordinary GET-edit-PUT round trip. That half stays on #8154; this card is only the seam.
Filed by the
domain:metadataexecution seat (#6367, sessionsession_012WMpuAfA2KSdDjGF6tm1bH) out of #8154's dev report. Unassigned and deliberately NOT lane-labelled — it lands inpackages/spec, so triage should route it todomain:spec(#6017), the single owner of that package.Why this card exists
#8154 asks for a generic per-type redaction hook on the metadata read path (
GET /api/v1/meta/datasourcesserves stored cleartext credentials; datasource is the first consumer, not the fix). Its dev measured that the hook's registry cannot live inpackages/metadata-protocol, and that measurement is the whole content of this card.The dependency graph forbids it. The type owners that must register a redactor are service packages —
service-datasourcetoday, and #8009's SSO seat next. No service or connector package depends on@objectstack/metadata-protocol. Verified independently by the PM before filing:⇒ a registry in
metadata-protocolis unreachable from the packages that must call it.@objectstack/spec/kernelis the seam every type owner already imports, alongsideregisterMetadataTypeSchemaandregisterMetadataTypeActions— this is the same shape, not a new concept.The ask
@objectstack/spec/kernel, beside the two existingregisterMetadataType*functions.datasource-config-redaction.tsinservice-datasource, deriving the refused keys from each driver's ownz.never()contract plus the pre-feat(spec)!: refuse inline credentials at publish — driver config + connector authoring door (#7990, spec half) #8078 alias list and turso's still-writableencryptionKey. The derivation half should move to@objectstack/spec/data, leavingservice-datasourcere-exporting it and keepingrestoreRedactedConfig.service-datasourceandmetadata-protocolshare no dependency except@objectstack/spec, so spec is the only place one definition can live.⛔ Two alternatives were considered and rejected on measured grounds — do not re-derive them:
DatasourceAdminServicePlugin.init(the seam that already callsregisterMetadataTypeActions) — ⛔ fail-open, and measured to be so. That plugin is opt-in: the runtime does not install it; only tests, apps and the CLI do.sys_metadatarows and the/metaread exits exist regardless. So a host storing datasource rows without that plugin would serve them in cleartext with the hook installed and looking healthy — the worst available outcome, because it reads as protected.This card widens
@objectstack/spec's public surface (a new registration seam, plus a moved export). Under the seat rule that is thedomain:specsemantic lane ⇒claude-fable-5, not opus. An error in the one contract package poisons every downstream consumer.Consumer, and the ordering
#8154 consumes this and is
Blocked-by:it — contract-first: the seam lands here, the metadata read path consumes it. #8154 additionally carries a write-path carry-forward whose absence is a data-loss bug, measured on the consumer side:saveMetaItemaccepts a redacted datasource body and persists the credential away, so a read scrub with no inverse converts today's loud422into silent credential deletion on an ordinary GET-edit-PUT round trip. That half stays on #8154; this card is only the seam.Related: #8154 · #8126 · #8081 · #8078 · #8009 · #7990.