# Data Model: Request-Scoped Derived State and Resolver Memoization

This feature does not introduce persistent storage. It defines runtime-only entities that govern how deterministic presenter and resolver results are reused inside one HTTP or Livewire request.

## Entities

### RequestScopedDerivedStateStore

- **Purpose**: Holds resolved derived-state values for the lifetime of one request so repeated consumers can reuse deterministic results.
- **Lifecycle**: Created at request start through the Laravel container and discarded at request end.

#### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `request_scope_id` | string | yes | Internal identifier for the active request-local store instance |
| `entries` | map<string, DerivedStateResolutionRecord> | yes | Resolved entries indexed by deterministic derived-state key |
| `invalidations` | list<string> | no | Keys or family scopes explicitly invalidated during the request |

#### Validation Rules

- The store must never be serialized or persisted.
- The store must never survive beyond the current request lifecycle.
- Each key in `entries` must be unique within the request.

### DerivedStateKey

- **Purpose**: Defines what counts as “the same derivation” for request-local reuse.
- **Contract naming note**: The runtime model uses internal snake_case field names. The logical OpenAPI contract uses camelCase transport names for request and response payloads and must normalize back to this runtime key shape.

#### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `family` | enum | yes | Covered family such as `artifact_truth`, `operation_ux_guidance`, `operation_ux_explanation`, `related_navigation_primary`, `related_navigation_detail`, or `related_navigation_header` |
| `record_class` | string | yes | Concrete model class or logical source type used by the family |
| `record_key` | string | yes | Stable string form of the source record identity |
| `variant` | string | yes | Surface mode or derivation variant such as `list_row`, `detail_page`, `expanded`, or `header_action` |
| `workspace_id` | int nullable | no | Workspace scope when relevant to the derivation |
| `tenant_id` | int nullable | no | Tenant scope when relevant to the derivation |
| `context_hash` | string nullable | no | Stable hash of any additional scope-sensitive inputs such as capability-sensitive visibility or consumer options |

#### Validation Rules

- `family` must be one of the explicitly supported family identifiers.
- `record_class` and `record_key` must be non-empty.
- `variant` must be non-empty and stable for the consumer path.
- `workspace_id`, `tenant_id`, and `context_hash` must be included whenever omitting them could change the result.

### DerivedStateResolutionRecord

- **Purpose**: Represents one resolved request-local entry stored under a `DerivedStateKey`.

#### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `key` | DerivedStateKey | yes | Deterministic key for the stored result |
| `value` | mixed | yes | The resolved presenter or resolver result |
| `negative_result` | bool | yes | Whether the stored value represents a stable negative result such as `null`, no entry, or no next action |
| `freshness_policy` | enum(`request_stable`,`invalidate_after_mutation`,`no_reuse`) | yes | Freshness behavior for the stored result |
| `resolved_at` | string | yes | Internal timestamp or sequence marker for testable store behavior |

#### Validation Rules

- `negative_result = true` is allowed only when the result is deterministic for the current scope.
- `freshness_policy = no_reuse` means the record must not be stored or reused.
- `freshness_policy = invalidate_after_mutation` requires an explicit invalidation path on covered mutation flows.

### DerivedStateFamilyContract

- **Purpose**: Documents the supported family-level rules for key composition, negative-result reuse, and freshness.

#### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `family` | enum | yes | Covered family identifier |
| `source_method` | string | yes | Existing presenter or resolver entry point used to resolve the family |
| `allows_negative_result_cache` | bool | yes | Whether deterministic negative results may be reused within the request |
| `default_freshness_policy` | enum | yes | Default freshness behavior for the family |
| `required_scope_inputs` | list<string> | yes | Key fields that must be present when the family depends on scope or capability context |

### DerivedStateConsumerDeclaration

- **Purpose**: Declares how one UI consumer is allowed to adopt the shared request-scoped contract and provides the metadata used by the automated guardrail.
- **Contract naming note**: This declaration uses the same camelCase field names as the logical consumer-validation contract because the automated guard and onboarding path treat that contract as the published declaration surface.

#### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `surface` | string | yes | Stable surface identifier such as `reviews.register.table` or `operations.run.detail` |
| `family` | enum | yes | Covered family identifier used by the consumer |
| `variant` | string | yes | Stable variant identifier such as `list_row`, `detail_page`, or `header_action` used by the consumer |
| `accessPattern` | enum(`row_safe`,`page_safe`,`direct_once`) | yes | Supported consumer access pattern |
| `scopeInputs` | list<string> | yes | Scope or capability inputs that must be declared for the consumer |
| `freshnessPolicy` | enum(`request_stable`,`invalidate_after_mutation`,`no_reuse`) | yes | Freshness behavior required for this consumer |
| `guardScope` | list<string> | yes | Source paths or helper seams the automated guard uses when validating adoption |
| `mutationSensitive` | bool | no | Advisory flag used when the consumer's visible result changes after in-request mutation and requires explicit freshness handling |
| `capabilitySensitive` | bool | no | Advisory flag used when capability context changes the result and the guard should require explicit scope inputs |

#### Validation Rules

- `family` must exist in a supported `DerivedStateFamilyContract`.
- `variant` must be explicit and stable for the guarded consumer path.
- `accessPattern` must be one of the supported consumer patterns.
- `scopeInputs` must be explicit when capability, workspace, tenant, or route context can affect the result.
- `guardScope` must be narrow enough to produce actionable failures with file and snippet output.
- `mutationSensitive` and `capabilitySensitive` are advisory guard hints and must never replace explicit `freshnessPolicy` or `scopeInputs` declaration.

## Relationships

- One `RequestScopedDerivedStateStore` contains many `DerivedStateResolutionRecord` objects.
- Each `DerivedStateResolutionRecord` is uniquely identified by one `DerivedStateKey`.
- Each `DerivedStateKey` belongs to one `DerivedStateFamilyContract`.
- Each `DerivedStateConsumerDeclaration` references one `DerivedStateFamilyContract` and is validated by the automated adoption guard before new consumers rely on the shared store.

## State Transitions

### Derived State Lifecycle

1. **Miss**: No `DerivedStateResolutionRecord` exists for the requested `DerivedStateKey`.
2. **Resolved**: The existing presenter or resolver computes the result and stores one `DerivedStateResolutionRecord` when reuse is allowed.
3. **Reused**: Additional consumers in the same request retrieve the same stored record without a new full derivation.
4. **Invalidated**: A covered mutation explicitly invalidates affected keys or family scopes when business truth changes.
5. **Recomputed**: The next access after invalidation resolves a fresh record under the same or updated key.

## Notes

- No database migrations, model tables, or persisted read models are introduced.
- The feature must not add a generic cross-request cache abstraction.
- Existing presenter envelopes and navigation entry objects remain the business-visible payloads; the new model only governs reuse of those outputs within one request.
- The automated guardrail uses `DerivedStateConsumerDeclaration` metadata to block undeclared or unsupported adoption patterns in CI.
