# Research — External Support Desk / PSA Handoff **Date**: 2026-04-29 **Spec**: [spec.md](spec.md) This document records the repo-grounded decisions that make the Spec 256 plan implementation-ready without expanding into a generic helpdesk product. ## Decision 1 — Extend `support_requests` instead of adding a second support-ticket truth **Decision**: Keep `App\Models\SupportRequest` as the only persisted truth for this slice and add the external linkage fields directly to `support_requests`. **Rationale**: - The repo already has one canonical support-request model, migration, factory, and submission service. - The operator workflow needs one durable record that still carries the internal `SR-...` reference after create, link, or failure. - Constitution `PERSIST-001` and `PROP-001` reject a second lifecycle unless it solves a distinct product problem. Spec 256 does not need one. **Evidence**: - Existing model: `apps/platform/app/Models/SupportRequest.php` - Existing persistence: `apps/platform/database/migrations/2026_04_27_095518_create_support_requests_table.php` - Existing write path: `apps/platform/app/Support/SupportRequests/SupportRequestSubmissionService.php` - Candidate scope: `docs/product/spec-candidates.md` **Alternatives considered**: - Add a new `SupportTicket` or `SupportRequestLink` model. - Rejected: creates a second truth and encourages a support register or detail page the spec explicitly forbids. - Keep external linkage entirely derived from audit logs. - Rejected: the current support context must show the latest linkage on revisit, which audit-only storage cannot do safely or cheaply. ## Decision 2 — Persist a bounded failure summary on the same row; keep detailed provider failure out of product truth **Decision**: Store `external_handoff_failure_summary` on `support_requests` and keep detailed provider payloads or raw errors out of persisted support-request truth. **Rationale**: - The spec requires explicit, revisitable failure handling in the same support context. - A purely audited failure would satisfy compliance but fail the operator need to reopen the action and see what happened. - A bounded human-readable summary is enough for revisit. Provider-specific payloads remain provider-owned and redaction-sensitive. **Evidence**: - Existing audit path is already separate from product truth: `apps/platform/app/Services/Audit/WorkspaceAuditLogger.php` - Current support-request row has no external linkage or failure fields, so the revisit contract is impossible without row-level extension. **Alternatives considered**: - Audit failure only. - Rejected: failure becomes invisible in the current support context. - Persist raw provider response JSON. - Rejected: violates the spec’s minimal neutral truth and increases leakage risk. ## Decision 3 — Keep the flow synchronous, preserve internal durability, and document the one bounded finalization write **Decision**: Preserve the existing synchronous submit flow, move any external create call outside the current internal-request creation transaction, enforce a five-second outbound timeout, and explicitly allow one bounded post-create finalization write on the same `SupportRequest` row. **Rationale**: - The current service wraps internal create plus audit in a transaction. - Spec 256 explicitly requires the internal support request to survive external create failure. - Spec 246 declared the row immutable after creation, so Spec 256 must make its one bounded finalization exception explicit instead of mutating the row silently. - Holding a database transaction open across remote HTTP is unnecessary and increases latency and failure risk. - A hard timeout budget is needed so the operator-visible submit path stays bounded and timeout behavior is testable. - The repo truth does not require `OperationRun`, queueing, or retry scheduling for this slice. **Evidence**: - Existing transaction structure in `SupportRequestSubmissionService` - Existing synchronous page actions on `TenantDashboard` and `TenantlessOperationRunViewer` - The spec’s explicit non-goal for queues, retries, and `OperationRun` - Spec 246 FR-246-011 immutability contract **Alternatives considered**: - Perform external HTTP inside the current DB transaction. - Rejected: risks long transactions and makes internal request durability harder to guarantee. - Introduce queue work or `OperationRun`. - Rejected: broader than current-release truth and not required for one synchronous target. - Keep Spec 246 immutability unchanged and infer final handoff state only from audit. - Rejected: the current support context must show revisitable success or failure on the canonical `SupportRequest`, so the one bounded finalization write has to be explicit. ## Decision 4 — Keep external linkage visibility inside the existing support request actions only **Decision**: Show the latest linkage summary inside the existing `Request support` slide-overs and in submit feedback. Do not add a new support page, dashboard card, or run-detail history section. **Rationale**: - The spec says visibility must stay attached to the existing tenant and run support contexts. - The acceptance criteria require reopening the action and seeing the latest linkage summary for that same context. - A broader always-visible history surface would deepen support-product scope and duplicate truth. **Evidence**: - Existing support-aware surfaces: `apps/platform/app/Filament/Pages/TenantDashboard.php` and `apps/platform/app/Filament/Pages/Operations/TenantlessOperationRunViewer.php` - No existing `SupportRequest` resource, list, or detail page exists in the repo today. **Alternatives considered**: - Add a support-request resource or detail page. - Rejected: explicitly out of scope. - Add a new page-level widget or card for support linkage. - Rejected: broader than the acceptance requirement and would create duplicate visible truth. ## Decision 5 — Add one minimal application config contract; do not hide target resolution behind an undefined prerequisite **Decision**: Bring one minimal application config contract into scope through `apps/platform/config/support_desk.php` and environment-backed values for the single supported target. Do not add workspace settings UI, a support settings domain, or provider-connection product work. **Rationale**: - The repo has no existing `support` settings domain, so leaving target resolution as an external prerequisite would create hidden implementation work. - The product contract only needs one target for v1, so an application config contract is the narrowest explicit source of truth. - Pulling workspace administration into Spec 256 would still expand scope from handoff to setup and administration. **Evidence**: - Existing repo truth has no support-target config seam yet, so a new app config file is the explicit minimal source of truth for one target. **Alternatives considered**: - Add a new `support` settings domain and UI in the same spec. - Rejected: becomes a second feature slice. - Reuse `ProviderConnection` as the support target model. - Rejected: not justified by current repo truth for one external desk handoff target. - Leave target resolution as an undefined prerequisite. - Rejected: the tasks and plan already depend on a concrete resolution seam, so the config contract must be explicit inside the package. ## Decision 6 — Use one concrete provider-owned handoff service, not a registry or interface framework **Decision**: Add one concrete provider-owned handoff service under the support-request path for the single real external target. **Rationale**: - Both existing support surfaces need the same create-or-normalize behavior. - Constitution `ABSTR-001` rejects a provider registry or interface framework before two real targets exist. - Page-local HTTP logic would duplicate failure handling, normalization, and audit shape. **Evidence**: - One configured target only in the spec and roadmap candidate - Existing shared write path already centralizes support-request submission across both surfaces **Alternatives considered**: - Add a provider interface plus registry. - Rejected: future-proofing without current-release variance. - Duplicate HTTP logic inside both Filament pages. - Rejected: immediate drift risk and weaker audit consistency. ## Decision 7 — Keep queries context-scoped and avoid new search or indexing semantics **Decision**: Derive the latest visible linkage from the latest support request for the same primary context, using the existing context indexes. Do not add cross-scope lookup or search by external ticket reference. **Rationale**: - Tenant summary and run summary have different scope rules in the spec. - Existing indexes already support latest-by-tenant and latest-by-run queries. - Cross-scope lookup by external reference is explicitly out of scope and would create a new leakage risk. **Evidence**: - Existing indexes on `support_requests(tenant_id, created_at)` and `support_requests(operation_run_id, created_at)` - Context scoping in `SupportRequest::PRIMARY_CONTEXT_TENANT` and `SupportRequest::PRIMARY_CONTEXT_OPERATION_RUN` **Alternatives considered**: - Add an index and lookup flow for external ticket reference. - Rejected: no current surface needs it, and it would conflict with the no-cross-scope-shortcuts rule. ## Decision 8 — Proof stays in Unit + Feature lanes with manual smoke only **Decision**: Keep the proving strategy in focused Pest unit and feature suites, then use a narrow manual smoke path after implementation. **Rationale**: - Business truth is server-side: branching, persistence, audit, and authorization. - Existing support-request tests already cover the same two Filament entry surfaces. - Browser coverage would mostly duplicate the existing action-form semantics. **Evidence**: - Existing test family: - `apps/platform/tests/Feature/SupportRequests/TenantSupportRequestActionTest.php` - `apps/platform/tests/Feature/SupportRequests/OperationRunSupportRequestActionTest.php` - `apps/platform/tests/Feature/SupportRequests/SupportRequestAuthorizationTest.php` - `apps/platform/tests/Feature/SupportRequests/SupportRequestAuditTest.php` **Alternatives considered**: - Add browser tests in the first slice. - Rejected: not required to prove the current business truth.