# Quickstart: Findings Intake & Team Queue V1 ## Goal Validate that `/admin/findings/intake` gives the current user one trustworthy shared queue for visible unassigned findings, that `Needs triage` remains the strict `new` and `reopened` subset, and that `Claim finding` moves eligible work into `/admin/findings/my-work` through a lightweight preview and explicit confirmation without silent overwrite. ## Prerequisites 1. Start Sail if it is not already running. 2. Use a test user who is a member of one workspace and at least two tenants inside that workspace. 3. Seed or create findings for these cases: - unassigned `new` finding in tenant A - unassigned `reopened` finding in tenant B - unassigned `triaged` finding in tenant A - unassigned `in_progress` finding in tenant B - unassigned finding with owner set but no assignee - already-assigned open finding - `acknowledged` finding with no assignee - terminal finding - unassigned finding in a hidden tenant - unassigned finding in a tenant where the acting user can view findings but a second acting user lacks assign capability - one claim-race fixture where another operator can successfully claim after the first queue render 4. Ensure `/admin/findings/my-work` already works for the acting workspace user. ## Focused Automated Verification Run formatting first: ```bash cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent ``` Then run the focused proving set: ```bash cd apps/platform && ./vendor/bin/sail artisan test --compact \ tests/Feature/Findings/FindingsIntakeQueueTest.php \ tests/Feature/Authorization/FindingsIntakeAuthorizationTest.php ``` ```bash cd apps/platform && ./vendor/bin/sail artisan test --compact \ tests/Feature/Findings/FindingsClaimHandoffTest.php ``` ## Manual Validation Pass ### 1. Canonical intake route Open `/admin/findings/intake`. Confirm that: - the page title and copy use findings-intake vocabulary, - rows show tenant, finding summary, severity, lifecycle, due urgency, owner when present, and queue reason, - the page is clearly fixed to shared unassigned work, - a workspace member with no currently viewable findings scope receives `403` instead of a pseudo-empty queue, - and already-assigned, `acknowledged`, terminal, hidden-tenant, and capability-blocked rows do not appear. ### 2. Fixed queue views On the same page: Confirm that: - `Unassigned` shows all visible unassigned open findings, - `Needs triage` shows only visible `new` and `reopened` findings, - `triaged` and `in_progress` findings disappear from `Needs triage`, - and already-assigned `reopened` findings never re-enter intake. ### 3. Active tenant prefilter Set an active tenant context before opening the intake queue. Confirm that: - the queue defaults to that tenant, - the fixed intake scope and selected queue view remain intact, - a `Clear tenant filter` affordance is available, - summary state stays consistent with the visible rows, - and clearing the tenant filter returns the queue to all visible tenants without widening beyond intake truth. ### 4. Ordering and urgency With overdue, reopened, new, and undated unassigned findings: Confirm that: - overdue rows appear first, - reopened rows appear ahead of new rows, - new rows appear ahead of the remaining triaged or in-progress unassigned backlog, - rows with due dates sort ahead of rows without due dates inside the same bucket, - and tie breaks remain deterministic. ### 5. Claim happy path Claim an eligible row as a user with assign capability. Confirm that: - the preview clearly summarizes the tenant, finding, and assignee change before execution, - the claim succeeds only after explicit confirmation, - assignee becomes the current user, - owner and workflow status stay unchanged, - the row disappears from intake immediately, - and the success path points clearly into `Open my findings` while row-open detail remains available for deeper context. ### 6. Claim forbidden path Use a workspace member who can inspect findings but lacks assign capability. Confirm that: - intake rows remain inspectable, - claim is not successfully executable, - the server rejects direct claim attempts with `403`, - and the queue remains honest after the failed attempt. ### 7. Stale-row conflict path Load intake as operator A, then claim the same finding as operator B before operator A clicks `Claim finding`. Confirm that: - operator A does not overwrite operator B, - the system reports the conflict honestly, - the queue refreshes so the stale row disappears, - and the audit trail reflects only the successful claim. ### 8. Detail continuity Open a row from intake. Confirm that: - the destination is the existing tenant finding detail route, - tenant scope is correct, - and the page offers `Back to findings intake` continuity. ### 9. Empty-state behavior Validate two empty states: - no visible intake work anywhere - no rows only because the active tenant prefilter narrows the queue Confirm that: - the zero-visible-work branch stays calm and offers `Open my findings`, - the tenant-prefilter branch explains the narrowing honestly instead of claiming the intake queue is globally empty, - the tenant-prefilter branch offers only `Clear tenant filter`, - and neither branch leaks hidden tenant information. ## Final Verification Notes - The queue remains the shared pre-assignment surface; deeper workflow mutations stay on tenant finding detail and tenant findings list. - Claim is not destructive, but it still uses a lightweight preview/confirmation step because write/change flows in this repo require explicit confirmation. - If a reviewer can infer hidden tenant work, or if stale claim attempts can overwrite another operator's success, treat that as a release blocker.