# Research: Shared Test Fixture Slimming

## Decision 1: Reuse the existing `createUserWithTenant()` seam instead of introducing a new fixture framework

- Decision: The rollout should build on the existing helper surface in `apps/platform/tests/Pest.php`, with `createUserWithTenant()` and `createMinimalUserWithTenant()` remaining the primary entry points for shared tenant-user setup.
- Rationale: The repo already has named fixture profiles and a dedicated helper used by roughly 607 callers. The problem is hidden cost and incomplete slimming, not the absence of a fixture abstraction.
- Alternatives considered:
  - Create a new generic fixture registry or DSL: rejected because it would add abstraction cost without solving the immediate hidden-side-effect problem better than the existing seam.
  - Push all setup inline into each test: rejected because it would duplicate setup logic and weaken shared guard coverage.

## Decision 2: Normalize the profile model around `minimal`, `standard`, and `full` or `integration-heavy`

- Decision: The plan should use the spec-facing profile vocabulary of `minimal`, `standard`, and `full` or `integration-heavy`, while mapping current explicit variants such as `provider-enabled`, `credential-enabled`, and `ui-context` as named heavy opt-ins or temporary transition aliases with declared removal triggers.
- Rationale: The specification requires a clear three-level model for authors and reviewers. The current profile set is useful, but it is helper-centric and does not yet present a consistent suite-wide vocabulary.
- Alternatives considered:
  - Keep only the current helper-specific profile names: rejected because they do not express a unified fixture discipline across helpers and factories.
  - Collapse everything into `minimal` and `heavy`: rejected because a bounded middle path is useful for common setup that is more than bare minimum but still not full integration context.

## Decision 3: Audit tenant workspace provisioning at both the factory and model-event layers

- Decision: The tenant cascade audit must treat `TenantFactory` and the `Tenant` model boot hook as one coupled hotspot, and lean tenant creation must disable both layers when the test requests minimal behavior.
- Rationale: `TenantFactory::minimal()` already tries to suppress workspace creation, but the `Tenant` model still has test-only workspace provisioning logic in `booted()`. Slimming only one layer leaves hidden graph inflation in place.
- Alternatives considered:
  - Slim only the factory: rejected because the model event can still recreate the hidden workspace relationship.
  - Remove all test-only workspace provisioning immediately without transition handling: rejected because some callers still rely on the historical behavior and need an explicit heavy path.

## Decision 4: Treat `OperationRunFactory`, `ProviderConnectionFactory`, and `BackupSetFactory` as first-class cascade-audit targets

- Decision: The first factory audit pass should cover `OperationRunFactory`, `ProviderConnectionFactory`, and `BackupSetFactory` in addition to `TenantFactory`.
- Rationale: These factories still create or repair extra workspace, tenant, credential, or backup-item context through attribute callbacks or `afterCreating()` hooks, and they appear in common test-support flows.
- Alternatives considered:
  - Restrict the audit to `TenantFactory` only: rejected because several heavy test paths start from factories that hide cost even after tenant setup is slimmed.
  - Attempt to audit every factory in one pass: rejected because the first slice should focus on high-usage or high-cost factories that materially affect the standard lanes.

## Decision 5: Keep concern builders explicit and heavy by intent

- Decision: Multi-record builders such as `BuildsBaselineCompareMatrixFixtures` should remain explicit heavy helpers, but their cost should be surfaced through naming, parameters, or guard documentation rather than being treated like ordinary default fixtures.
- Rationale: These builders exist to create deliberately rich graphs for matrix, portfolio, or governance scenarios. The correct fix is to announce cost, not to pretend they are minimal.
- Alternatives considered:
  - Force concern builders into the minimal profile model: rejected because it would blur the difference between narrow test setup and intentionally broad scenario construction.
  - Leave them undocumented: rejected because hidden heavy setup in support traits still harms review clarity.

## Decision 6: Reuse Spec 206 lane tooling for before and after measurement

- Decision: Lane impact should be measured through the existing `TestLaneManifest`, `TestLaneBudget`, `TestLaneReport`, `scripts/platform-test-lane`, and `scripts/platform-test-report` seams introduced by Spec 206.
- Rationale: The repository already has budgeted fast-feedback and confidence lanes plus artifact output under `storage/logs/test-lanes`. Creating a second performance harness would duplicate governance and weaken comparability.
- Alternatives considered:
  - Measure ad hoc with one-off local scripts: rejected because it would not create stable, reviewable evidence.
  - Introduce a dedicated new profiling subsystem: rejected because the repo already has lane reporting and budget evaluation contracts.

## Decision 7: Use a backwards-compatible transition layer rather than a hard cutover

- Decision: The rollout should keep a visible transition path for legacy heavy callers, mark aliases as temporary, and retire them once the first migration packs and guard coverage are complete rather than forcing a suite-wide cutover.
- Rationale: Existing tests may depend on historical side effects. A staged migration gives the suite time to expose hidden dependencies while keeping cost visible instead of silently restoring old defaults or preserving a permanent second vocabulary.
- Alternatives considered:
  - Rewrite all callers in one pass: rejected because it creates too much review noise and raises breakage risk.
  - Freeze legacy behavior permanently: rejected because it would blunt the cost reduction that the spec exists to achieve.

## Decision 8: Guard coverage must assert both absence and presence of context

- Decision: Fixture guard tests should verify that minimal paths do not create hidden provider, credential, workspace, session, or cache side effects, and that explicit heavy paths create only the promised additional context.
- Rationale: Slimming work regresses easily when helpers or factories gain new callbacks. Both negative and positive assertions are needed to keep the support layer honest.
- Alternatives considered:
  - Test only the lean path: rejected because heavy profiles also need a stable contract.
  - Rely only on wall-clock improvements: rejected because runtime improvements alone do not prove that the correct context is being created.

## Decision 9: Migrate high-usage caller packs by business need, not by file ownership

- Decision: The first migration packs should target high-usage callers in console, authorization, navigation, and narrow findings or baseline tests where provider-heavy or full integration context is usually unnecessary.
- Rationale: These packs sit closest to the fast-feedback and confidence lanes and provide early lane impact without forcing speculative rewrites of already heavy-by-intent suites.
- Alternatives considered:
  - Start with the most complex multi-tenant builders: rejected because their business need often justifies heavy context and they are a weaker first proof of lane impact.
  - Pick callers only by directory ownership: rejected because fixture cost and lane importance do not align neatly with team or folder boundaries.