200 lines
7.3 KiB
Markdown
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. |