# Research: Operation Run Link Contract Enforcement

## Decision 1: Reuse the existing helper families instead of introducing a new link presenter

**Decision**: Treat `App\Support\OperationRunLinks` as the single admin-plane contract and `App\Support\System\SystemOperationRunLinks` as the single system-plane contract for all in-scope `OperationRun` collection and detail links.

**Rationale**: The existing helper families already own canonical nouns, labels, plane separation, and admin query semantics. The current defect is incomplete adoption, not missing capability. Reusing those helpers satisfies XCUT-001 with the smallest possible change.

**Alternatives considered**:

- Create a new cross-plane navigation presenter or registry. Rejected because the repository already has concrete helper ownership for the exact routes this feature targets.
- Fix each raw producer locally without naming a shared contract. Rejected because it would not stop the next contributor from reintroducing raw route assembly.

## Decision 2: Scope the first migration wave to the confirmed raw admin-plane producers

**Decision**: The first implementation slice migrates the currently confirmed raw admin-plane producers in `RecentOperationsSummary`, `InventoryCoverage`, `InventoryItemResource`, `ReviewPackResource`, `TenantlessOperationRunViewer`, and `RelatedNavigationResolver`.

**Rationale**: A targeted scan of `apps/platform/app` shows these files still assemble `admin.operations.index` or `admin.operations.view` links directly inside platform-owned UI or shared navigation code. They represent the smallest set of real producers needed to satisfy FR-232-003, FR-232-014, and FR-232-015.

**Alternatives considered**:

- Full opportunistic cleanup of every `admin.operations.*` string in the repository. Rejected because tests and legitimate infrastructure redirects would expand the slice into heavy-governance work.
- Migrate only one or two surfaces. Rejected because the drift is already spread across widget, page, resource, and shared-resolver layers.

## Decision 3: Keep the initial allowlist narrow and infrastructure-only

**Decision**: Seed the explicit exception boundary with bootstrapping or redirect-owned raw producers such as `AdminPanelProvider`, `TenantPanelProvider`, `EnsureFilamentTenantSelected`, and `ClearTenantContextController`, and require file-specific justification for each retained exception.

**Rationale**: These producers sit in navigation boot, middleware, or redirect code where runtime canonical navigation context is not the owning abstraction. Forcing helper usage there can fabricate the wrong dependency shape or hide a deliberate redirect contract.

**Alternatives considered**:

- Ban all raw route usage with no exceptions. Rejected because it would create false positives in infrastructure code and push the feature into a broader governance lane.
- Allow convenience-based exceptions. Rejected because convenience is exactly what created the current drift.

## Decision 4: Treat the system plane as contract lock-in, not broad migration work

**Decision**: Preserve `SystemOperationRunLinks` as the canonical system-plane path and focus the system portion of the feature on regression protection and authorization proof rather than manufactured cleanup work.

**Rationale**: The app-side scan shows current system widgets and pages already use `SystemOperationRunLinks` consistently. The feature should document and protect that convergence instead of inflating the slice with unnecessary system refactors.

**Alternatives considered**:

- Expand the scope into general system routing cleanup. Rejected because the current-release problem is not missing on the system plane in app code.
- Ignore the system plane entirely. Rejected because FR-232-002, FR-232-008, and FR-232-016 still require explicit system-plane continuity protection.

## Decision 5: The guard stays route-bounded and app-side only

**Decision**: The new guard scans only the declared platform-owned UI and shared-navigation boundary in `apps/platform/app` and fails on raw `admin.operations.*` route assembly or direct system operations page URLs outside the explicit allowlist.

**Rationale**: The proving purpose is preventing new operator-facing bypasses, not banning route literals everywhere in the repository. A route-bounded guard keeps the feature in `fast-feedback + confidence` instead of escalating it into a structural repo-governance family.

**Alternatives considered**:

- Whole-repo scanning including tests and unrelated infrastructure. Rejected because it would create noisy failures and require a much broader allowlist.
- No guard at all. Rejected because the cleanup would then be a one-time repair with no contract enforcement.

## Decision 6: Keep thin delegating wrappers out of the violation set

**Decision**: Treat `App\Support\OpsUx\OperationRunUrl` as an acceptable thin seam because it delegates directly to `OperationRunLinks` and does not introduce parallel route truth.

**Rationale**: The spec targets raw bypass of the canonical helper families, not every intermediate call site that already converges on them. Counting a delegating wrapper as a violation would add churn without improving contract safety.

**Alternatives considered**:

- Force all wrapper users to switch to direct helper calls in the same slice. Rejected because the wrapper is not the source of drift and does not block enforcement of the raw-route contract.
- Allow arbitrary wrappers. Rejected because only pure delegating seams remain acceptable; a wrapper that adds its own routing logic would reintroduce the same problem.