# 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 | yes | Resolved entries indexed by deterministic derived-state key | | `invalidations` | list | 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 | 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 | 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 | 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.