TenantAtlas/specs/149-queued-execution-reauthorization/data-model.md
2026-03-17 22:48:57 +01:00

200 lines
7.3 KiB
Markdown

# Phase 1 Data Model: Queued Execution Reauthorization and Scope Continuity
## Overview
This feature does not require a new database table in its first implementation slice. The data-model work is the formalization of existing persisted records plus new derived support-layer objects that express queued execution legitimacy consistently across job families.
## Persistent Domain Entities
### OperationRun
**Purpose**: Canonical workspace-owned observability record for queued tenant-affecting work.
**Key fields**:
- `id`
- `workspace_id`
- `tenant_id` nullable for workspace-scoped runs
- `user_id` nullable for scheduled or system runs
- `initiator_name`
- `type`
- `status`
- `outcome`
- `run_identity_hash`
- `context`
- `summary_counts`
- `failure_summary`
**Relationships**:
- Belongs to one workspace
- May belong to one tenant
- May belong to one human initiator
**Validation rules relevant to this feature**:
- `workspace_id` and `tenant_id` must remain authoritative for scope continuity checks.
- `status` and `outcome` remain service-owned through `OperationRunService`.
- `context` may gain additional execution-authority metadata, but it must remain sanitized and serializable.
**State transitions relevant to this feature**:
- `queued``running` only after legitimacy passes
- `queued` → terminal status with blocked outcome when execution is refused before work begins, using the canonical `OperationRunService` transition path
- retry attempts re-evaluate legitimacy from the current state, not from the original queued truth
### Tenant
**Purpose**: Tenant-owned execution target whose current scope, entitlement, and operability determine whether queued work may begin.
**Key fields**:
- `id`
- `workspace_id`
- lifecycle or operability-related state already consumed by `TenantOperabilityService`
- provider and RBAC-health fields already used by hardening gates
**Relationships**:
- Belongs to one workspace
- Has many provider connections, restore runs, inventory records, and operation runs
**Validation rules relevant to this feature**:
- Must still belong to the expected workspace when the job starts
- Must remain entitled and operable for the requested execution class
### User
**Purpose**: Human initiator for actor-bound queued runs.
**Key fields**:
- `id`
- membership and role relationships already used by capability resolution
**Relationships**:
- May initiate many `OperationRun` records
- May or may not still be entitled to the tenant when execution starts
**Validation rules relevant to this feature**:
- Actor-bound execution must re-check current workspace membership, tenant membership, and required capability
### ProviderConnection
**Purpose**: Provider-backed execution prerequisite for queued provider operations.
**Key fields**:
- `id`
- `tenant_id`
- `provider`
- `status`
- `consent_status`
- `verification_status`
- `entra_tenant_id`
**Relationships**:
- Belongs to one tenant
- May be referenced in `OperationRun.context`
**Validation rules relevant to this feature**:
- Provider-backed jobs must re-check that the connection still matches tenant scope and is still valid before execution side effects occur
## New Derived Domain Objects
### ExecutionAuthorityMode
**Purpose**: Declares whose authority the queued job is executing under.
**Canonical values**:
- `actor_bound`
- `system_authority`
**Behavior**:
- `actor_bound` requires current actor membership, entitlement, and capability checks at execution time
- `system_authority` requires current tenant operability plus explicit system-allowed execution semantics, but not a human capability check
- `system_authority` is valid only when the operation type appears in the canonical system-execution allowlist owned by the execution legitimacy gate and sourced from trusted scheduler or system entry paths
### QueuedExecutionContext
**Purpose**: Normalized evaluation input for execution-time legitimacy.
**Fields**:
- `run`
- `operationType`
- `workspaceId`
- `tenant` nullable
- `initiator` nullable
- `authorityMode`
- `requiredCapability` nullable
- `providerConnectionId` nullable
- `targetScope` structured payload with nullable tenant- or provider-level members when not applicable
- `prerequisiteClass` nullable or list-based
**Validation rules**:
- `workspaceId` must match the resolved workspace of the run and target tenant
- actor-bound context requires an initiator reference or a safe failure path
- target-scope metadata may inform evaluation, but authoritative truth is always re-resolved from current records
### QueuedExecutionLegitimacyDecision
**Purpose**: Structured answer to whether queued work may begin.
**Contract note**:
- The internal PHP DTO may use camelCase property names, but when serialized into `OperationRun.context`, failure payloads, or contract fixtures it must map directly to the schema-defined snake_case contract in `contracts/execution-legitimacy.schema.json`.
**Fields**:
- `operationType`
- `allowed`
- `authorityMode`
- `initiator` nullable
- `targetScope`
- `checks`
- `denialClass` nullable
- `reasonCode` nullable
- `retryable`
- `metadata`
**Behavior**:
- `allowed=false` means the job must not produce side effects
- `targetScope` is always present, with nullable tenant- or provider-level members when a narrower target is not applicable
- `checks` always records the canonical evaluation results for workspace scope, tenant scope, capability, tenant operability, and execution prerequisites
- `retryable` is decided centrally by denial class: `scope_denied`, `capability_denied`, and `initiator_invalid` are terminal; `tenant_not_operable` and `prerequisite_invalid` are retryable and must be re-evaluated fresh on each attempt
- `metadata` may carry safe hints for audit or Monitoring detail views
### ExecutionDenialClass
**Purpose**: High-level category of why execution was refused.
**Canonical values**:
- `scope_denied`
- `capability_denied`
- `tenant_not_operable`
- `prerequisite_invalid`
- `initiator_invalid`
### ExecutionDenialReasonCode
**Purpose**: Stable reason-code vocabulary for execution-time refusal.
**Initial values**:
- `workspace_mismatch`
- `tenant_not_entitled`
- `missing_capability`
- `tenant_not_operable`
- `tenant_missing`
- `initiator_missing`
- `initiator_not_entitled`
- `provider_connection_invalid`
- `write_gate_blocked`
- `execution_prerequisite_invalid`
## Consumer Mapping
| Consumer | Primary execution concern |
|---|---|
| Queue middleware before run start | Evaluate legitimacy before `running` transition |
| `ProviderOperationStartGate` adopters | Preserve dispatch-time gate and add execution recheck |
| Restore or write jobs | Reuse write-hardening semantics inside canonical execution contract |
| Inventory or sync jobs | Re-check actor-bound scope and tenant operability before local mutation work |
| Bulk orchestrator and worker jobs | Re-check legitimacy on orchestrator start and retry paths |
| Monitoring run detail | Render blocked execution reasons distinctly from generic failure |
## Migration Notes
- No persistence migration is required for the first slice.
- New authority metadata can live in `OperationRun.context` and sanitized failure payloads.
- Existing provider-blocked reason handling can be reused rather than replaced.
- Existing `TrackOperationRun` behavior will likely become an adapter over the new legitimacy-first flow rather than remain the earliest middleware in the chain.