#+#+#+#+markdown
# Feature Specification: SCOPE-001 Workspace ID Isolation

**Feature Branch**: `093-scope-001-workspace-id-isolation`  
**Created**: 2026-02-14  
**Status**: Draft  
**Input**: Enforce workspace isolation by binding all tenant-owned records to a workspace, with a safe staged rollout and corrected audit invariants.

## Spec Scope Fields *(mandatory)*

- **Scope**: workspace
- **Primary Routes**: No new pages/routes. Affects all create/write paths that persist tenant-owned records in the tables listed below, plus operational tooling for a one-time backfill.
- **Data Ownership**:
  - Tenant-owned tables impacted (must become explicitly workspace-bound):
    - policies
    - policy_versions
    - backup_sets
    - backup_items
    - restore_runs
    - backup_schedules
    - inventory_items
    - inventory_links
    - entra_groups
    - findings
    - entra_role_definitions
    - tenant_permissions
  - Audit trail invariants impacted: audit_logs
- **RBAC**: No user-facing permissions change. Backfill execution is an operator-only workflow (platform/ops).

## Clarifications

### Session 2026-02-14

- Q: For the 12 tenant-owned tables, how strict should deterministic workspace binding be when a caller explicitly provides a workspace binding? → A: Reject any mismatch; if a record references a tenant, its workspace binding MUST equal the tenant’s workspace.
- Q: During backfill, what should happen if a row’s tenant reference is invalid (tenant missing / cannot map tenant → workspace)? → A: Abort the backfill run and report the offending table plus sample identifiers for remediation.
- Q: Should tenant_id be allowed to change on existing rows in the 12 tenant-owned tables? → A: No; tenant_id is immutable and updates are rejected.
- Q: How should the backfill workflow be recorded for observability/audit? → A: Create/reuse an OperationRun for the backfill and also write an AuditLog summary for start/end/outcome.
- Q: Should this feature include updating existing canonical/operational queries/views to scope by workspace binding? → A: No; query/view changes are out of scope for 093 (follow-up later).

## User Scenarios & Testing *(mandatory)*

### User Story 1 - Enforce workspace ownership at the data layer (Priority: P1)

As a platform owner, I want every tenant-owned record to be explicitly bound to a workspace so that workspace isolation does not depend on application-only guardrails.

**Why this priority**: This closes a class of potential cross-workspace data leakage and makes operational reporting safer and simpler.

**Independent Test**: Can be tested by creating a tenant-owned record with a tenant reference and asserting that `workspace_id` is derived from the tenant and that any explicit mismatched `workspace_id` is rejected; backfill behavior is validated in User Story 2.

**Acceptance Scenarios**:

1. **Given** tenant-owned records exist without a workspace binding, **When** the staged rollout completes, **Then** all tenant-owned records are workspace-bound.
2. **Given** the rollout is in progress, **When** the system is used normally, **Then** there is no required downtime for administrators.

---

### User Story 2 - Safely backfill existing production data (Priority: P2)

As an operator, I want a safe, resumable way to backfill missing workspace bindings so that large datasets can be migrated without risky one-shot operations.

**Why this priority**: Without a safe backfill, enforcing data-level constraints risks outages and operational incidents.

**Independent Test**: Can be tested by seeding rows with missing workspace bindings, running the backfill workflow twice, and confirming idempotent outcomes.

**Acceptance Scenarios**:

1. **Given** a table contains rows missing workspace bindings, **When** the backfill is executed, **Then** those rows are updated to the correct workspace.
2. **Given** the backfill is interrupted and restarted, **When** it runs again, **Then** it resumes safely without corrupting already-correct rows.

---

### User Story 3 - Make audit logs unambiguous across scopes (Priority: P3)

As an auditor, I want tenant-scoped audit events to always be workspace-bound so that workspace isolation semantics are preserved in audit trails.

**Why this priority**: Audit trails are only reliable if their scope is structurally consistent and queryable.

**Independent Test**: Can be tested by attempting to store a tenant-scoped audit entry without a workspace binding and verifying it is rejected, while allowing workspace-only and platform-only entries.

**Acceptance Scenarios**:

1. **Given** an audit log entry references a tenant, **When** it is persisted, **Then** it must also reference a workspace.
2. **Given** an audit log entry is workspace-only or platform-only, **When** it is persisted, **Then** it remains valid according to the documented rules.

---

### Edge Cases

- Tenant-owned row references a tenant that no longer exists (or is otherwise invalid).
- Backfill is executed concurrently (must not produce conflicting outcomes).
- New rows are created while the backfill is in progress (must not reintroduce missing bindings).
- Partial completion: some tables are fully backfilled while others are pending.
- Mixed-scope audit events: tenant-scoped vs workspace-only vs platform-only.
- Attempt to change tenant_id on an existing tenant-owned record.

## Requirements *(mandatory)*

**Constitution alignment (required):** If this feature introduces any Microsoft Graph calls, any write/change behavior,
or any long-running/queued/scheduled work, the spec MUST describe contract registry updates, safety gates
(preview/confirmation/audit), tenant isolation, run observability (`OperationRun` type/identity/visibility), and tests.
If security-relevant DB-only actions intentionally skip `OperationRun`, the spec MUST describe `AuditLog` entries.

**Constitution alignment (RBAC-UX):** If this feature introduces or changes authorization behavior, the spec MUST:
- state which authorization plane(s) are involved (tenant/admin `/admin` + tenant-context `/admin/t/{tenant}/...` vs platform `/system`),
- ensure any cross-plane access is deny-as-not-found (404),
- explicitly define 404 vs 403 semantics:
  - non-member / not entitled to workspace scope OR tenant scope → 404 (deny-as-not-found)
  - member but missing capability → 403
- describe how authorization is enforced server-side (Gates/Policies) for every mutation/operation-start/credential change,
- reference the canonical capability registry (no raw capability strings; no role-string checks in feature code),
- ensure global search is tenant-scoped and non-member-safe (no hints; inaccessible results treated as 404 semantics),
- ensure destructive-like actions require confirmation (`->requiresConfirmation()`),
- include at least one positive and one negative authorization test, and note any RBAC regression tests added/updated.

**Constitution alignment (OPS-EX-AUTH-001):** OIDC/SAML login handshakes may perform synchronous outbound HTTP (e.g., token exchange)
on `/auth/*` endpoints without an `OperationRun`. This MUST NOT be used for Monitoring/Operations pages.

**Constitution alignment (BADGE-001):** If this feature changes status-like badges (status/outcome/severity/risk/availability/boolean),
the spec MUST describe how badge semantics stay centralized (no ad-hoc mappings) and which tests cover any new/changed values.

**Constitution alignment (Filament Action Surfaces):** If this feature adds or modifies any Filament Resource / RelationManager / Page,
the spec MUST include a “UI Action Matrix” (see below) and explicitly state whether the Action Surface Contract is satisfied.
If the contract is not satisfied, the spec MUST include an explicit exemption with rationale.

### Functional Requirements

- **FR-001 (Schema coverage)**: The system MUST represent a workspace binding for every tenant-owned record in the 12 listed tables.
- **FR-002 (No missing bindings post-rollout)**: After completion of the rollout, the system MUST prevent creation or persistence of tenant-owned records without a workspace binding.
- **FR-003 (Deterministic binding for new writes)**: For any new or updated tenant-owned record, the system MUST derive the workspace binding from the referenced tenant (not from user/session context alone).
- **FR-003a (Mismatch handling)**: If a caller provides a workspace binding that does not match the referenced tenant’s workspace, the write MUST be rejected.
- **FR-004 (Safe staged rollout)**: The system MUST support a staged rollout that allows introducing the new field, deploying write-path enforcement, backfilling existing data, and only then enforcing strict constraints.
- **FR-005 (Idempotent backfill)**: Operators MUST be able to re-run the backfill safely; repeated runs MUST not regress already-correct data.
- **FR-006 (Operational safety)**: The backfill workflow MUST be safe for large datasets (batching/resume) and MUST prevent concurrent executions.
- **FR-006a (Invalid mapping handling)**: If the backfill workflow encounters a tenant-owned row that cannot be mapped from tenant → workspace, it MUST abort and report the offending table and sample identifiers for operator remediation.
- **FR-007 (Validation)**: Operators MUST be able to validate that no tenant-owned records remain without a workspace binding before strict constraints are enforced.
- **FR-011 (Tenant immutability)**: For tenant-owned records, tenant identity MUST be immutable after creation; attempts to change tenant_id MUST be rejected.
- **FR-012 (Backfill observability and audit)**: The backfill workflow MUST be observable via an OperationRun (progress + outcome) and MUST write an audit log summary entry for start/end/outcome.
- **FR-013 (Query/view scope)**: This feature MUST NOT require broad refactors of canonical/operational queries; it MUST focus on making workspace scoping structurally correct at the data layer.
- **FR-008 (Audit log invariant)**: If an audit log entry references a tenant, it MUST also reference a workspace.
- **FR-009 (Audit scope flexibility)**: The audit log MUST continue to support workspace-only events (workspace present, tenant absent) and platform-only events (both absent).
- **FR-010 (Canonical view scoping readiness)**: After rollout, operational/canonical queries SHOULD be able to scope tenant-owned data by workspace without relying on implicit joins or assumptions.

### Assumptions & Dependencies

- Each tenant belongs to exactly one workspace, and that mapping is the source of truth for deriving workspace bindings.
- The 12 listed tables are “tenant-owned” per SCOPE-001 and are expected to remain tenant-owned.
- Any existing tooling that creates tenant-owned records has enough information to reference the tenant (directly or indirectly) at write time.

### Key Entities *(include if feature involves data)*

- **Workspace**: The top-level isolation boundary for data access and operations.
- **Tenant**: A unit of configuration/data that is owned by exactly one workspace.
- **Tenant-owned record**: Any record that must be both tenant-scoped and workspace-scoped.
- **Audit event**: An immutable entry describing an action/event, which may be tenant-scoped, workspace-scoped, or platform-scoped.
- **Backfill run**: A controlled operational execution that updates legacy data and reports progress/outcomes.

## Success Criteria *(mandatory)*

### Measurable Outcomes

- **SC-001 (Completeness)**: 100% of records in the 12 tenant-owned tables have a workspace binding after backfill and validation.
- **SC-002 (Integrity)**: After strict constraints are enabled, creating a tenant-owned record without a workspace binding is rejected.
- **SC-003 (Audit correctness)**: 100% of tenant-scoped audit events include a workspace binding; workspace-only and platform-only audit events remain valid.
- **SC-004 (Operational safety)**: The rollout requires no planned downtime for administrators.
- **SC-005 (Repeatability)**: Re-running the backfill after completion does not change already-correct records and can be used as a safety check.
