# Research: Request-Scoped Derived State and Resolver Memoization

## Decision 1: Use a dedicated request-scoped in-memory store bound through the Laravel container

- **Decision**: Introduce one dedicated request-scoped derived-state store with request-local lifecycle semantics instead of static arrays or persistent cache stores.
- **Rationale**: The feature needs explicit reuse within one HTTP or Livewire request and explicit isolation across requests. A request-local container binding makes that boundary visible and testable while avoiding new persistence and avoiding cross-request staleness.
- **Alternatives considered**:
  - Static caches inside presenters or resources: rejected because they hide scope boundaries, duplicate behavior across families, and make invalidation inconsistent.
  - `Cache::remember()` or Redis-backed caching: rejected because the spec explicitly excludes cross-request caching and because stale semantic reuse would become much harder to reason about.

## Decision 2: Key derivations by family, record identity, variant, and scope-sensitive context

- **Decision**: Define one deterministic key contract that includes the derived-state family, stable record identity, variant or surface mode, and any workspace, tenant, or visibility-sensitive context required to produce the correct result.
- **Rationale**: Existing repeated work happens because the same deterministic question is asked multiple times. Correct reuse therefore depends on a stable definition of “same question.” Model-object identity alone is insufficient because the same record can appear through different model instances or under different scopes.
- **Alternatives considered**:
  - Model ID only: rejected because it cannot distinguish list vs detail variants or capability-sensitive outputs.
  - `spl_object_hash()` only: rejected because it prevents convergence across separate model instances representing the same record.

## Decision 3: Integrate through the existing family entry points, not by adding a new presentation framework

- **Decision**: Route reuse through `ArtifactTruthPresenter`, `OperationUxPresenter`, and `RelatedNavigationResolver` entry points instead of creating a generic presenter base class, a universal decorator, or a new UI taxonomy layer.
- **Rationale**: The business semantics already live in these families. The feature's goal is to reduce repeated deterministic work beneath them, not to redesign how operator meaning is modeled.
- **Alternatives considered**:
  - New cross-domain presentation framework: rejected because it would layer new semantics on top of already-correct families and violate the spec's narrow foundation intent.
  - Surface-only fixes per page: rejected because the same repeated-cost pattern already spans multiple domains and would continue to reappear elsewhere.

## Decision 4: Converge existing hidden caches into the shared contract and keep negative results reusable

- **Decision**: Standardize existing local request-like caches, such as the finding primary related-entry cache, behind the shared contract and allow deterministic negative results like “no related entry” or “no next action” to be reused within one request.
- **Rationale**: The repo already contains evidence that request-local reuse is useful, but it is unevenly applied. Converging on one contract avoids parallel caching patterns and still prevents repeated work when the correct result is the absence of a link or action.
- **Alternatives considered**:
  - Leave existing local caches untouched and optimize only the worst pages: rejected because it would preserve multiple hidden patterns and make future adoption harder.
  - Cache only positive results: rejected because deterministic negative results can also drive repeated work and should be equally reusable when scope-stable.

## Decision 5: Treat mutation freshness as an explicit family rule

- **Decision**: Covered mutating flows must explicitly invalidate or bypass request-local reuse after business state changes within the same request.
- **Rationale**: The spec requires “no stale within request ambiguity.” A clear family-level freshness rule is safer than assuming the existing code path order will always avoid stale derived values.
- **Alternatives considered**:
  - Cache for the full request without exceptions: rejected because post-action state could become stale and misleading.
  - Disable reuse on every Livewire action: rejected because many actions still have deterministic pre- and post-action read phases where request-local reuse remains valuable.

## Decision 6: Test derivation-count behavior directly instead of proxying everything through query-count assertions

- **Decision**: Validate the feature with focused unit and feature tests that prove one full derivation per request for representative covered families, plus explicit scope-safety and mutation-path tests.
- **Rationale**: The repeated-cost problem is not just SQL chatter. It is repeated presenter and resolver work across closures and page fragments. Query-count assertions alone would miss important non-query work and would not prove freshness rules.
- **Alternatives considered**:
  - Measure only query counts: rejected because the problem is broader than SQL and includes repeated in-memory translation and navigation assembly.
  - Rely on manual profiling only: rejected because this feature needs regression protection against future local cache drift.
