# 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.
