Problem
Bench Review's growth loop — visitor reads reviews, signs up, follows judges, gets pulled back when new reviews publish, and judges claim profiles to respond — is broken at nearly every link. For a platform hosting negative reviews of named judges, the right-of-reply path being undiscoverable is a fairness/legal-optics problem, and with zero re-engagement or analytics, every visitor is one-and-done.
Findings
- Settings profile save is a no-op.
saveProfileonly rewrites the cookie-cached user and shows "Saved." — comment admits "No /api/me PATCH endpoint yet" (resources/components/Bench/Settings/SettingsView.stx:51-69);auth.ts:305-313fetchMe clobbers the edit on next load. "Change photo" (SettingsView.stx:232) has no handler; routes/api.ts has no PATCH /me. - Judge-claim funnel is orphaned. /judges/signup (JudgeSignup.stx, ClaimJudgeProfileAction) has zero inbound links — header, footer (BenchFooter.stx:17-39), and judge profiles lack any "Claim this profile" CTA — and resources/views/faq.stx:27 says claims are "on the way." The page is also absent from the pre-rendered dist/.
- No notification on review publish. UpdateReviewStatusAction.ts:72-153 notifies only the author; the claimed judge and judge_follows rows are never fanned out, so Follow is a dead-end (NotificationType is only 'like'|'approved'|'rejected', app/Helpers/notifications.ts:3) and CommentSubmitAction never notifies authors.
- No mobile navigation. All header nav is
hidden lg:flex(BenchHeader.stx:276,283,371); no hamburger exists; MobileMenu.stx is dead code with zero includes. - Feed capped at 20, no pagination. LatestReviewsAction.ts:16-17 (MAX_LIMIT=20, no page param) + ReviewsFeed.stx fetchLatest(20); JudgeIndexAction uses Judge.all(); Comments.stx:46 single page of 50.
- 'Most helpful' sort missing despite full likes infra — ReviewsByJudgeAction.ts:57 and LatestReviewsAction.ts:31 hardcode created_at desc; no sort control in any component.
- Notification preferences unwired. Framework table + filter layer exist (storage/framework/core/notifications/src/index.ts:204) but no UI, no API route, and all mailers send unconditionally.
- API failures render as misleading empty states. Stores swallow errors (judges.ts:81-85, reviews.ts:80-94); a down API shows "No reviews yet" with no retry; ArticleView has no branch for 5xx (renders blank).
- No 500 page in dist/ — only 404.html; the SSG auto-emits 500.html if views/500.stx exists.
- Zero analytics — no snippet, no events, JudgeSearchAction discards queries (zero-result searches = judge-import backlog).
- No re-engagement loop — subscribe UI only on BenchComingSoon.stx:51; Scheduler runs only the demo Inspire job; framework's SendCampaignJob is never invoked.
Acceptance criteria
- PATCH /api/me (auth-gated) persists
name; saveProfile calls it; email input and photo button removed or fully implemented (email change resets verification) - "Are you Judge {name}? Claim this profile" link on Judge/ProfileHeader.stx, a footer "For Judges" link, and faq.stx points to /judges/signup
- Publishing a review notifies the verified claimed judge (in-app + email) and fans out in-app notifications to judge_follows; comments notify the review author (skip self)
- lg:hidden hamburger wires up MobileMenu.stx (fix isOpen binding, dead links, missing Icon refs); mobile users can navigate, search, and log in
- /reviews feed and Comments support paging via the existing paginate helper with a "Load more" control
- ?sort=helpful supported on review lists with a UI toggle
- Email-notification toggle in Settings, enforced before author/judge/follower emails
- Public stores expose error state; feed/directory/article render "Couldn't load — Retry" instead of empty/blank
- views/500.stx exists so dist/500.html is emitted
- Privacy-friendly analytics snippet in the default layout; JudgeSearchAction logs {query, result_count}
- Newsletter capture on live pages with a scheduled digest send — or the capture is removed
From the 2026-06-10 production-readiness audit.