Summary
A protocol-level audit of every metadata type cross-referenced each schema property's spec definition against its actual consumers (file:line) in the runtime + renderers, to determine (1) does it take effect? and (2) is it necessary/reasonable? Liveness = code consumption, not browser observation.
Result: roughly half of all metadata properties are DEAD — defined in the protocol but read by neither the runtime nor the renderers, so authoring them is a silent no-op. The full evidence (17 per-type reports + cross-type synthesis, each with file:line) is in PR #1864 → docs/audits/ (README.md is the index).
This issue is the umbrella; the checklists below are scoped so they can be split into separate issues/ADRs.
🔴 P0 — Parsed-but-UNENFORCED security props (latent access-control gaps)
Properties that imply a security boundary but enforce nothing. Either enforce or remove — shipping them as-is is a compliance/security liability.
🔴 P1 — Finish the ADR-0021 analytics migration
Spec moved to dataset+values/dimensions, but renderers/Studio still read the removed legacy shape:
🟠 P2 — Spec hygiene
Healthiest vs worst (from the audit)
- Healthiest (near-total liveness):
hook, validation.
- Worst:
policy (100% dead), portal (100% dead), tool (write-only).
Evidence + per-property recommendations: PR #1864, docs/audits/*.md.
🤖 Generated with Claude Code
Summary
A protocol-level audit of every metadata type cross-referenced each schema property's spec definition against its actual consumers (
file:line) in the runtime + renderers, to determine (1) does it take effect? and (2) is it necessary/reasonable? Liveness = code consumption, not browser observation.Result: roughly half of all metadata properties are DEAD — defined in the protocol but read by neither the runtime nor the renderers, so authoring them is a silent no-op. The full evidence (17 per-type reports + cross-type synthesis, each with
file:line) is in PR #1864 →docs/audits/(README.mdis the index).This issue is the umbrella; the checklists below are scoped so they can be split into separate issues/ADRs.
🔴 P0 — Parsed-but-UNENFORCED security props (latent access-control gaps)
Properties that imply a security boundary but enforce nothing. Either enforce or remove — shipping them as-is is a compliance/security liability.
PolicySchemais 100% dead — password complexity, session idle/absolute timeout,forceMfa, IP allow-list (trustedRanges/vpnRequired), audit retention/redaction all parsed, none enforced; not even registered as a metadata type.better-auth(auth-manager.ts:458) runs hardcoded defaults instead → false sense of compliance.allowTransfer/allowRestore/allowPurgeomitted fromOPERATION_TO_PERMISSION(permission-evaluator.ts:8-16); ownership transfer, undelete, and hard-delete/GDPR purge are not gated by RBAC.agent.permissions/visibility/accessnever enforced; the chat route hardcodes['ai:chat','ai:agents'](agent-routes.ts:109). "Who can chat with this agent" enforces nothing.runAsnever switches execution identity (service-automationengine ignores it) — a flow declaringrunAs: systemdoes not elevate/de-elevate.apiEnabled/apiMethodsnot enforced by REST — an object cannot actually be hidden from the API via these flags.disabled(CEL form) silently ignored — renderers read a non-specenabled(action-button.tsx:56); the predicate form ofdisabledhas zero consumers.parentdead (team-graph.ts:27does not walk it) — the documented "managers see subordinates' data" rollup is unimplemented.SharingRuleSchemadisconnected from the live engine — runtime enforces a divergentsys_sharing_rulemodel (JSONcriteria_json, recipient enumuser/team/department/role/queue); the spec's CELcondition+role_and_subordinates/guestrecipients are never compiled (unparsable CEL → "match nothing").🔴 P1 — Finish the ADR-0021 analytics migration
Spec moved to
dataset+values/dimensions, but renderers/Studio still read the removed legacy shape:ListView.tsx:1413/ObjectView.tsx:754read legacyxAxisField/yAxisFields/aggregation; spec exposesdataset/dimensions/values→ a spec-compliant chart renders nothing.WidgetConfigPanelstill author/read legacyobject/categoryField/valueField/aggregatewhiledashboard.zod.ts:153declaresdataset+valuesrequired → Studio emits widgets the spec rejects.chartdead on the dataset path;ReportColumnSchema/ReportGroupingSchema/ReportChartSchemaare obsolete type-only re-exports.🟠 P2 — Spec hygiene
maxLength/minLength/referenceFilters/maxRating; pagetype→pageType&label→title&visibility; dashboardtitlevslabel; app readsaccentColor/badgeVariant/separatornot declared in spec; flowhttpvs deprecatedhttp_request(Studio authors the alias); skillrequiredPermissionsvspermissions; agentknowledge.{topics→sources}; webhookobject→object_name/isActive→active.toolmetadata is a one-way projection (can't author a working tool as metadata — noimplementation/handlerfield, no executor loads it);EmailTemplateSchemais registered but the runtime reads a differently-shapedsys_email_template; thespec-bridgepage/dashboard bridges are orphaned (their exclusive props dead).experimental: field enhanced-type configs (barcode/qr/slider/rating/color/location) + governance (encryption/masking/audit/dataQuality); objectenable/versioning/partitioning/cdc/softDelete/search; agent autonomy (memory/guardrails/structuredOutput/lifecycle, exceptplanning.maxIterations); tooloutputSchema; jobretryPolicy/timeout; themespacing/breakpoints/logo/rtl/density; translationmessageFormat:'icu'(no ICU engine),supportedLocales,cache; PortalSchema (entire — not registered, no route, no renderer).component/data/rowField/columnField; viewObjectViewform-adapter keys; appaccentColor/badgeVariant/separator. These break a strictSchema.parse().filter/format/derived/dateGranularity; skilltriggerConditions(the activation-critical field); flownotify(absent from the static palette).Healthiest vs worst (from the audit)
hook,validation.policy(100% dead),portal(100% dead),tool(write-only).Evidence + per-property recommendations: PR #1864,
docs/audits/*.md.🤖 Generated with Claude Code