TenantAtlas/specs/222-findings-intake-team-queue/quickstart.md
Ahmed Darrazi a2e855bd81
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 49s
feat: add findings intake queue and stabilize follow-up regressions
2026-04-22 00:51:18 +02:00

158 lines
5.7 KiB
Markdown

# 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.