# Feature Specification: 098 — Settings Slices v1 (Backup + Drift + Operations) **Feature Branch**: `098-settings-slices-v1-backup-drift-ops` **Created**: 2026-02-16 **Status**: Draft **Input**: Workspace-level settings slices for Backup, Drift severity mapping, and Operations retention/thresholds with safe defaults. ## Spec Scope Fields *(mandatory)* - **Scope**: workspace - **Primary Routes**: Workspace Settings screen (admin UI) - **Data Ownership**: workspace-owned settings values (key/value) + audit log entries for setting changes - **RBAC**: workspace membership required; view vs manage capability-gated; deny-as-not-found for non-members ## Clarifications ### Session 2026-02-16 - Q: Which “Reset to default” scope do you want on the Workspace Settings UI? → A: Per-setting reset (each key individually). - Q: When an admin clicks “Save” and multiple settings change at once, how should audit logging behave? → A: One audit log entry per key changed. - Q: Should we enforce a validation constraint between `backup.retention_keep_last_default` and `backup.retention_min_floor`? → A: Allow any values; effective retention is always clamped to `backup.retention_min_floor`. - Q: For settings that are currently unset (so the system uses defaults), how should the UI present them? → A: Leave input unset, show helper text with the default/effective value. - Q: In `drift.severity_mapping`, should severity values be case-sensitive? → A: Case-insensitive; normalize to lowercase on save. ## User Scenarios & Testing *(mandatory)* ### User Story 1 - Configure backup retention defaults (Priority: P1) As a workspace admin, I want to configure workspace-wide defaults for backup retention so that enterprise workspaces can tune policy without code/config changes. **Why this priority**: Backup retention is a common enterprise requirement and impacts storage cost and governance. **Independent Test**: Can be tested by setting/unsetting workspace settings and verifying backup retention behavior remains unchanged by default and changes deterministically when configured. **Acceptance Scenarios**: 1. **Given** no workspace settings exist for backup retention, **When** a backup retention decision is made, **Then** behavior matches the current baseline (no change). 2. **Given** a workspace default retention value is configured, **When** a backup retention decision is made without a more specific override, **Then** the configured default is used. 3. **Given** a retention “floor” value is configured, **When** any calculated retention value is below the floor, **Then** the effective retention is clamped up to the floor. 4. **Given** a per-schedule override is configured, **When** that override is below the configured floor, **Then** the override is clamped up to the floor. --- ### User Story 2 - Configure drift severity mapping (Priority: P2) As a workspace admin, I want to map drift finding types to severities so that findings align with enterprise risk posture and triage practices. **Why this priority**: Severity directly affects how teams triage drift; a one-size-fits-all default is too rigid for enterprise. **Independent Test**: Can be tested by saving a mapping, generating findings for mapped/unmapped types, and verifying severities are assigned correctly. **Acceptance Scenarios**: 1. **Given** no drift severity mapping exists, **When** a drift finding is produced, **Then** its severity defaults to “medium”. 2. **Given** a mapping exists for a specific finding type, **When** a drift finding with that type is produced, **Then** the mapped severity is applied. 3. **Given** a mapping contains an unknown/unsupported severity value, **When** an admin attempts to save it, **Then** the save is rejected and no invalid values are persisted. --- ### User Story 3 - Configure operations retention and stuck threshold (Priority: P3) As a workspace admin, I want to configure retention for operations/run records and store a “stuck run” threshold so that data lifecycle and operational heuristics are workspace-tunable. **Why this priority**: Retention policies and operational thresholds vary widely between organizations and audit requirements. **Independent Test**: Can be tested by saving retention/threshold settings and verifying the retention cutoff used by pruning changes accordingly while no new automatic actions occur. **Acceptance Scenarios**: 1. **Given** no operations retention setting exists, **When** operations/run pruning is executed, **Then** the cutoff matches the current baseline (no change). 2. **Given** an operations retention setting exists, **When** pruning is executed, **Then** the cutoff is derived from the configured retention days. 3. **Given** a stuck threshold is configured, **When** the Workspace Settings screen is re-opened, **Then** the configured value is shown exactly as saved. 4. **Given** a stuck threshold is configured, **When** operations/run behavior is observed, **Then** no automatic remediation or auto-handling is performed in this feature scope. ### Edge Cases - Attempting to save invalid numeric ranges (too low/high) is rejected and does not persist. - Attempting to save invalid JSON (malformed) for drift mapping is rejected. - Attempting to save drift mapping with non-string keys is rejected. - Two admins editing settings concurrently results in deterministic persisted state (last write wins) and both attempts are auditable. - A user without manage capability can view settings (read-only) but cannot submit changes. - A non-member cannot discover the Workspace Settings screen or any values (deny-as-not-found). ## Requirements *(mandatory)* **Constitution alignment (required):** This feature MUST remain DB-only for screen rendering and MUST NOT introduce Microsoft Graph calls as part of rendering or saving these settings. Any setting mutation MUST be auditable. ### Dependencies & Assumptions - This feature depends on an existing workspace settings foundation that provides: workspace-scoped storage, consistent defaults, centralized validation, RBAC capability enforcement, and audit logging for changes. - No tenant-specific override UI is included in v1; only workspace-wide configuration is in scope. - The default values for all settings keys match the current baseline behavior at the time this feature ships. **Constitution alignment (RBAC-UX):** - Authorization planes involved: workspace-scoped admin UI. - Non-member / not entitled to workspace scope → 404 (deny-as-not-found). - Member but missing manage capability → 403 on mutation attempts; UI remains read-only. **Constitution alignment (OPS/observability):** This feature does not introduce a new long-running operation type; it changes which configuration values are used by existing behavior. All admin-initiated mutations MUST produce audit log entries. ### Functional Requirements - **FR-001**: System MUST support workspace-level configuration for the following setting keys: - `backup.retention_keep_last_default` - `backup.retention_min_floor` - `drift.severity_mapping` - `operations.operation_run_retention_days` - `operations.stuck_run_threshold_minutes` - **FR-002**: System MUST preserve existing behavior when none of the above settings are configured (defaults MUST match the current baseline). - **FR-003**: System MUST validate and reject invalid setting values, ensuring no invalid configuration is silently persisted. - **FR-004**: Workspace Settings UI MUST present the above keys grouped into three sections (Backup, Drift, Operations) and MUST be fully functional without any external API calls. - **FR-004a**: For any setting key that is currently unset, the UI MUST keep the input in an “unset” state and MUST display helper text indicating the default (currently effective) value. - **FR-005**: Users with view capability MUST be able to view current effective settings but MUST NOT be able to change them. - **FR-006**: Users with manage capability MUST be able to change settings and reset individual settings back to defaults. - **FR-007**: Resetting a setting to default MUST be a confirmed (destructive-like) action. - **FR-008**: System MUST write audit log entries for each settings update and reset-to-default event including: workspace identity, actor identity, setting key, old value, new value, and timestamp. - **FR-008a**: When a single save operation changes multiple keys, the system MUST write one audit log entry per key changed. #### Backup slice requirements - **FR-009**: `backup.retention_keep_last_default` MUST be an integer between 1 and 365. - **FR-010**: `backup.retention_min_floor` MUST be an integer between 1 and 365. - **FR-011**: Effective backup retention MUST never be lower than `backup.retention_min_floor` (applies to defaults and any more specific overrides). - **FR-011a**: The system MUST NOT reject configuration solely because `backup.retention_min_floor` exceeds `backup.retention_keep_last_default`; instead, the effective retention MUST be clamped to the floor. #### Drift slice requirements - **FR-012**: `drift.severity_mapping` MUST be a JSON object mapping `finding_type` (string) → severity. - **FR-013**: Allowed severity values MUST be limited to: `low`, `medium`, `high`, `critical`. - **FR-013a**: Severity values MUST be accepted case-insensitively and normalized to lowercase when persisted. - **FR-014**: If a finding type has no mapping entry, severity MUST default to `medium`. #### Operations slice requirements - **FR-015**: `operations.operation_run_retention_days` MUST be an integer between 7 and 3650. - **FR-016**: Pruning of operations/run records MUST use the configured retention days when set; otherwise it MUST behave as the baseline. - **FR-017**: `operations.stuck_run_threshold_minutes` MUST be an integer between 0 and 10080. - **FR-018**: `operations.stuck_run_threshold_minutes` MUST be a stored configuration value only; it MUST NOT introduce auto-remediation or auto-handling behavior in this feature scope. ## UI Action Matrix *(mandatory when Filament is changed)* | Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions | |---|---|---|---|---|---|---|---|---|---|---| | Page | Workspace Settings (admin UI) | Save; Reset setting to default (per-setting, confirmed) | N/A | N/A | N/A | N/A | N/A | Save + Cancel | Yes | View capability: read-only fields; Manage capability: editable + submit; Non-member: 404 | ### Key Entities *(include if feature involves data)* - **Workspace Setting**: A workspace-owned key/value configuration item with validation rules and a default. - **Audit Log Entry**: An immutable record of a settings update or reset-to-default event. - **Drift Finding Type**: A classification string used to identify the type of drift finding for severity mapping. ## Success Criteria *(mandatory)* ### Measurable Outcomes - **SC-001**: When no settings are configured for these keys, backup retention behavior, drift severity behavior, and operations pruning behavior match the baseline in automated regression tests. - **SC-002**: An authorized workspace admin can update each of the 5 settings and observe the new effective value reflected in the Workspace Settings screen immediately after save. - **SC-003**: 100% of settings updates and reset-to-default actions produce an audit log entry with key, old value, and new value. - **SC-004**: Invalid configuration attempts (out-of-range numbers, invalid JSON, unsupported severities) are rejected and do not change persisted settings.