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

5.7 KiB

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:

cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent

Then run the focused proving set:

cd apps/platform && ./vendor/bin/sail artisan test --compact \
  tests/Feature/Findings/FindingsIntakeQueueTest.php \
  tests/Feature/Authorization/FindingsIntakeAuthorizationTest.php
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.