Nest Identify/Auto-Match/Modify under /people with redirects; reject
blur/extreme pose at Process; Name-cluster on Identify; axe smoke tests;
helpers to rotate DEV admin password and seed match_decisions.
Add light/dark toggle, navy gold-accented sidebar, skip link, and
clearer titles so admin reads as the same JRCC brand; document UX
review and next priorities in ROADMAP.
Port viewer design tokens to admin shell/login with JRCC branding; add max recognition distance, next-best person margin, stricter detection floor, and tighter auto-accept distance.
Match each person against up to three trusted refs (best distance wins), document DEV accuracy metrics, and replace the collapsing histogram calibrator with a rolling-mean fitter.
Support distance→confidence knots from identified pairs and match_decisions, keep legacy curve until a knots file is applied, and re-score face quality without re-detecting.
Raise reference quality floor to 0.5, align browse/run/auto-accept defaults with UI copy, and persist match_decisions for later confidence calibration.
Sharpness previously used variance of the kernel constant, so every face
got ~0 sharpness weight. Compute Laplacian variance on the grayscale crop;
add unit tests and an error-tagging checklist for follow-on accuracy work.
Logged-out favorite/report share a reason-aware SignInRequiredDialog so
favorites no longer show report messaging. Replace misplaced text-secondary
(light wash token) with foreground/primary on labels, auth, and menus.
Capture optional contact fields on identify/approve, add Select All and
Approve Next 10 on User Identified Faces, and email admins when the
pending queue grows (ADMIN_NOTIFY_EMAIL via existing noreply SMTP).
Closes three items from the outstanding e2e/CI gap list:
- Timing budgets: timings.measure() only ever recorded durations for the
(still-unwired) Pushgateway export — nothing failed CI when a step got
slow. Add e2e/timing-budgets.ts (expectWithinBudget + shared BUDGET_MS
buckets) and wire it into every measure() call site across the suite.
Mail-wait steps are deliberately left unbudgeted (external mail-trap
delivery latency, not a code performance signal).
- actions/upload-artifact@v4 doesn't work against this Gitea/act runner's
artifact backend — pin to v3 for the e2e failure-report upload.
- Shared act_runner npm cache has corrupted platform-native tarballs before
(@next/swc-linux-x64-musl) and reds viewer-unit/admin-unit/e2e with no
product bug involved. All three npm ci steps now retry once after
`npm cache clean --force` on first failure.
Verified: full local suite green against DEV (37 passed, 6 skipped, no
budget assertion failures) before wiring into CI.
- Wire E2E_API_USERNAME/PASSWORD (admin) + E2E_API_VIEWER_USERNAME/PASSWORD
(viewer) into the Gitea Actions e2e job so FastAPI-authed specs run in CI.
- Add api.role-permissions.spec.ts: viewer 403 vs admin 200/200/200 on
/api/v1/users, /api/v1/role-permissions, and /api/v1/photos/bulk-delete
(safe no-op via a non-existent photo id — proves the gate, not deletion).
- Add gallery.search-filters.spec.ts: tag_id and person_id filters on the
public /api/search route return correct subsets, combined filters narrow
results, and the /search UI tag-filter interaction updates the URL/count.
- Update ROADMAP/README/.env.example for the new env vars and coverage.