Context
Full browser walkthrough of every page at localhost:3200 on branch jayzalowitz/browser-qa-test (v0.3.3.1). Reviewed as a real user would — navigated every page, opened modals, expanded toggles, switched themes.
Bugs
P1 — Approvals page has no pagination
File: apps/web/public/js/pages/approvals.js
100 pending approval cards render at once into a single container, creating a 29,210px tall scroll area. The "Recent decisions" section is buried ~29K pixels below the fold. A real user would never scroll past the first 10-20 items.
Repro: Navigate to /#/approvals with ≥50 pending items. Scroll down. The page is unusable.
Fix: Paginate or virtualize. Show 10-20 pending items with a "Load more" button, or split into tabs (Pending / History). The email triage cards are ~290px each so even 20 items would be a reasonable 5800px.
P2 — "1 THINGS" grammar bug on Twin page
File: apps/web/public/js/pages/twin.js (badge rendering)
The count badge shows "1 THINGS" (plural) when count is 1. Should be "1 THING".
Fix: ${count} thing${count === 1 ? '' : 's'} — same pattern needed for the domain sub-badges ("1 prefs" → "1 pref").
P2 — Decisions table "What happened" column shows raw type names
File: apps/web/public/js/pages/decisions.js
The "What happened" column displays raw event type strings like generic, calendar_conflict, email_triage instead of human-readable descriptions. Compare with the approvals page which shows actual email subjects — that's the quality bar.
Fix: Map type names to readable labels. generic should show the event summary/subject from the decision object. calendar_conflict → "Calendar conflict". email_triage → "Email triage needed". Ideally pull the actual subject line from the decision's signal data.
P2 — Decisions table timestamps all identical, missing dates
File: apps/web/public/js/pages/decisions.js
Every row shows "09:44 PM" with no date. For a history view spanning multiple days, the date is essential. Could be a seed data issue (all events created at the same time) combined with a formatting gap (time-only, no date).
Fix: Show relative time for recent ("2h ago") and full date+time for older ("Apr 7, 9:44 PM"). Group rows by date headers ("Today", "Yesterday", "April 7").
P3 — Home page Travel preferences show raw key=value format
File: apps/api/src/routes/twin.ts — describePreference() function (~line 278)
The "What I've learned so far" section on Home shows Travel items as:
Travel: find travel deals = i love travel deals
The describePreference() helper only has handlers for email, calendar, finance, and shopping domains. Travel, subscriptions, and general domains fall through to the generic ${domain}: ${key} = ${value} format.
Fix: Add cases for the remaining domains, or improve the generic fallback to produce natural language (e.g., "You love travel deals" instead of the raw key=value).
P3 — "How well I know you" shows 0% when 5 things are learned
File: apps/web/public/js/pages/home.js or API endpoint
The stats card says "0% — How well I know you / Just started" even though the twin has 5 learned preferences. Either the metric calculation doesn't account for preferences (only behavioral patterns?), or it's stuck at 0.
Fix: If the metric intentionally excludes explicit preferences, clarify the label ("Habits detected" vs "How well I know you"). If it should include them, fix the calculation.
P3 — Spending guardrails input uses cents
File: apps/web/public/js/pages/settings.js
Input fields are labeled "in cents" with raw values (10000, 50000). The helper text ("e.g. 10000 = $100.00") partially mitigates this but users think in dollars.
Fix: Accept dollar amounts in the input, convert to cents on save, display as "$100.00" not "10000".
P3 — "Undo" in decisions table is unstyled
File: apps/web/public/js/pages/decisions.js
The "Undo" text in the Actions column renders as plain text, indistinguishable from a label. Users can't tell it's interactive.
Fix: Style as a link or ghost button with hover state and cursor pointer.
What's working well
- Navigation, routing, sidebar, theme switching (3 themes + dark mode toggle) — all solid
- Approvals page email triage UX is genuinely good: multi-action buttons, "Your choice trains the twin" copy, expandable "If you approve" detail
- Newly shipped Edit and Correction modals on Twin page work correctly (pre-fill, auto-select, Remove option, Escape to close)
- Settings page is comprehensive: 5-tier autonomy selector, pause twin, privacy transparency, spending guardrails
- Setup page execution engine status detection is useful
- "Connected" indicator in sidebar bottom-left
Suggested priority order
- Approvals pagination (P1) — blocks real usage with any meaningful inbox volume
- Decisions table readability (P2 x2) — raw types + missing dates make history page nearly useless
- Grammar fix (P2) — quick win, 1-line change
- Home page polish (P3 x2) — raw format + misleading 0% metric
- Settings cents→dollars (P3) — UX friction
- Undo styling (P3) — minor
Context
Full browser walkthrough of every page at
localhost:3200on branchjayzalowitz/browser-qa-test(v0.3.3.1). Reviewed as a real user would — navigated every page, opened modals, expanded toggles, switched themes.Bugs
P1 — Approvals page has no pagination
File:
apps/web/public/js/pages/approvals.js100 pending approval cards render at once into a single container, creating a 29,210px tall scroll area. The "Recent decisions" section is buried ~29K pixels below the fold. A real user would never scroll past the first 10-20 items.
Repro: Navigate to
/#/approvalswith ≥50 pending items. Scroll down. The page is unusable.Fix: Paginate or virtualize. Show 10-20 pending items with a "Load more" button, or split into tabs (Pending / History). The email triage cards are ~290px each so even 20 items would be a reasonable 5800px.
P2 — "1 THINGS" grammar bug on Twin page
File:
apps/web/public/js/pages/twin.js(badge rendering)The count badge shows "1 THINGS" (plural) when count is 1. Should be "1 THING".
Fix:
${count} thing${count === 1 ? '' : 's'}— same pattern needed for the domain sub-badges ("1 prefs" → "1 pref").P2 — Decisions table "What happened" column shows raw type names
File:
apps/web/public/js/pages/decisions.jsThe "What happened" column displays raw event type strings like
generic,calendar_conflict,email_triageinstead of human-readable descriptions. Compare with the approvals page which shows actual email subjects — that's the quality bar.Fix: Map type names to readable labels.
genericshould show the event summary/subject from the decision object.calendar_conflict→ "Calendar conflict".email_triage→ "Email triage needed". Ideally pull the actual subject line from the decision's signal data.P2 — Decisions table timestamps all identical, missing dates
File:
apps/web/public/js/pages/decisions.jsEvery row shows "09:44 PM" with no date. For a history view spanning multiple days, the date is essential. Could be a seed data issue (all events created at the same time) combined with a formatting gap (time-only, no date).
Fix: Show relative time for recent ("2h ago") and full date+time for older ("Apr 7, 9:44 PM"). Group rows by date headers ("Today", "Yesterday", "April 7").
P3 — Home page Travel preferences show raw key=value format
File:
apps/api/src/routes/twin.ts—describePreference()function (~line 278)The "What I've learned so far" section on Home shows Travel items as:
The
describePreference()helper only has handlers foremail,calendar,finance, andshoppingdomains. Travel, subscriptions, and general domains fall through to the generic${domain}: ${key} = ${value}format.Fix: Add cases for the remaining domains, or improve the generic fallback to produce natural language (e.g., "You love travel deals" instead of the raw key=value).
P3 — "How well I know you" shows 0% when 5 things are learned
File:
apps/web/public/js/pages/home.jsor API endpointThe stats card says "0% — How well I know you / Just started" even though the twin has 5 learned preferences. Either the metric calculation doesn't account for preferences (only behavioral patterns?), or it's stuck at 0.
Fix: If the metric intentionally excludes explicit preferences, clarify the label ("Habits detected" vs "How well I know you"). If it should include them, fix the calculation.
P3 — Spending guardrails input uses cents
File:
apps/web/public/js/pages/settings.jsInput fields are labeled "in cents" with raw values (10000, 50000). The helper text ("e.g. 10000 = $100.00") partially mitigates this but users think in dollars.
Fix: Accept dollar amounts in the input, convert to cents on save, display as "$100.00" not "10000".
P3 — "Undo" in decisions table is unstyled
File:
apps/web/public/js/pages/decisions.jsThe "Undo" text in the Actions column renders as plain text, indistinguishable from a label. Users can't tell it's interactive.
Fix: Style as a link or ghost button with hover state and cursor pointer.
What's working well
Suggested priority order