# Data Model: RBAC Role Definition Diff UX Upgrade ## Overview This feature introduces no database schema changes. The data model is a presentation-layer model that adapts existing `Finding.evidence_jsonb.rbac_role_definition` content into shared diff presentation objects. ## Existing Input Model ### RbacRoleDefinitionEvidence - **Source**: `Finding.evidence_jsonb.rbac_role_definition` - **Purpose**: authoritative comparison payload already produced by the baseline comparison engine - **Core fields**: - `diff_kind`: string such as `metadata_only`, `missing`, or `unexpected` - `diff_fingerprint`: stable change fingerprint for recurrence logic - `changed_keys`: array of operator-facing diff keys that materially changed - `metadata_keys`: array of metadata-related changed keys - `permission_keys`: array of permission-related changed keys - `baseline`: `RbacRoleDefinitionSide` - `current`: `RbacRoleDefinitionSide` ### RbacRoleDefinitionSide - **Source**: `rbac_role_definition.baseline` and `rbac_role_definition.current` - **Purpose**: stores one side of the RBAC comparison - **Core fields**: - `normalized`: map of `field_key => value` - `is_built_in`: nullable boolean used for role source display fallback - `role_permission_count`: nullable integer used for permission-block summary fallback ## New Presentation Model ### RbacRoleDefinitionDiffBuilder - **Type**: new consumer-local adapter class - **Purpose**: translate `RbacRoleDefinitionEvidence` into shared `DiffPresentation` - **Responsibilities**: - merge baseline and current normalized rows - apply RBAC label mapping - apply deterministic field ordering - mark Allowed Actions and other approved list-like fields for inline list rendering - pass `changed_keys` through to shared state classification - preserve no-change and sparse-data behavior ### DiffPresentation - **Type**: existing shared DTO from Spec 141 - **Fields**: - `summary`: `DiffSummary` - `rows`: ordered array of `DiffRow` - **Purpose**: single render-ready result consumed by the RBAC Blade entry ### DiffSummary - **Type**: existing shared DTO - **Fields**: - `changedCount` - `addedCount` - `removedCount` - `unchangedCount` - `hasRows` - `message` - **Purpose**: drive summary badge counts and no-change/no-data messaging ### DiffRow - **Type**: existing shared DTO - **Fields**: - `key`: stable field key - `label`: operator-facing label - `status`: `changed | unchanged | added | removed` - `oldValue` - `newValue` - `isListLike` - `addedItems` - `removedItems` - `unchangedItems` - `meta` - **Purpose**: represent one renderable field row in the RBAC diff region ## Consumer Configuration Model ### RbacFieldLabelMap - **Type**: internal associative map in the builder - **Purpose**: keep operator-facing labels stable and concise when internal keys need normalization or fallback handling - **Examples**: - `Role definition > Display name` - `Role definition > Description` - `Role definition > Role source` - `Role definition > Permission blocks` - `Permission block 1 > Allowed actions` ### RbacFieldOrderRules - **Type**: internal ordering strategy in the builder - **Purpose**: preserve predictable review order - **Desired order**: 1. top-level role metadata 2. role source and permission-block summary 3. permission-block details 4. alphabetical fallback for unknown but valid keys ### RbacListFieldRules - **Type**: internal field designation rules - **Purpose**: identify which RBAC fields should intentionally use inline list diff rendering - **Initial designated fields**: - any `Permission block * > Allowed actions` - optionally other simple list-valued RBAC keys that fit the same operator model, such as denied actions or conditions, if present and still readable ## State Derivation Rules ### Row status - **Added**: key exists only on current side - **Removed**: key exists only on baseline side - **Changed**: key exists on both sides and either appears in `changed_keys` or has unequal values - **Unchanged**: key exists on both sides and values are equal without change designation ### List fragments - **Added items**: values present only in current list - **Removed items**: values present only in baseline list - **Unchanged items**: values present in both lists in shared order-preserving form ## Validation Rules - Ignore empty or non-string field keys. - Treat absent `baseline.normalized` and `current.normalized` maps as empty arrays. - Preserve explicit `null`, boolean, scalar, and list values so `ValueStringifier` can render them consistently. - Treat unknown metadata as optional and never required for row rendering. ## No Schema Change Statement - No new tables, columns, indexes, or migrations are required. - `findings.evidence_jsonb` remains the authoritative source for the RBAC consumer.