Skip to content

fix: harden Therapy Compass recovery and error accessibility#758

Closed
BigSimmo wants to merge 3 commits into
mainfrom
codex/resolve-design-audit-findings-and-merge
Closed

fix: harden Therapy Compass recovery and error accessibility#758
BigSimmo wants to merge 3 commits into
mainfrom
codex/resolve-design-audit-findings-and-merge

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Motivation

  • Make the Therapy Compass mockup fail visibly and recoverably when its large client dataset cannot be loaded instead of rendering empty or fabricated content.
  • Prevent an unimplemented Favourite control from appearing interactive and misleading users about persistence.
  • Improve route/global error fallbacks by moving focus to the error heading and making the global fallback resilient to system/forced-colour modes.

Description

  • Added a retry mechanism to the Therapy Compass data hook (src/components/therapy-compass/data/use-therapy-data.ts) and exposed a retryData binding through the provider (src/components/therapy-compass/bindings.tsx).
  • Render an explicit alert/retry UI when the Therapy Compass dataset fails, preventing the tool from showing empty/fabricated results (src/components/therapy-compass/therapy-compass-page.tsx).
  • Mark the Therapy Compass Favourite control as unavailable by disabling the button, updating title/aria-label, and styling it as non-interactive (src/components/therapy-compass/therapy-card.tsx).
  • Move keyboard focus into the route error heading and the global fallback heading and replace hard-coded light-mode colours with system colour tokens to improve dark/forced-colour behaviour (src/components/route-error-boundary.tsx, src/app/global-error.tsx).
  • Created a local branch codex/design-audit-remediation-20260717 and committed the changes with message fix: harden therapy compass recovery and error access.

Testing

  • Ran git diff --cached --check which passed before committing the changes.
  • Attempted npm run test:focused -- --files <paths> but the repository wrapper refused focused execution and instructed running the full suite instead, so the focused run was skipped.
  • Attempted npm run test for the two targeted tests but the run failed because node_modules is not present (missing vitest module), so unit tests could not be executed in this checkout.
  • Verified git commit succeeded and the worktree is clean on codex/design-audit-remediation-20260717; pushing and merging were not performed because this checkout has no Git remote configured and remote/merge actions require an operator to configure and authorize them.

Codex Task

Summary by CodeRabbit

  • New Features
    • Added a Retry option when the therapy catalogue cannot be loaded.
    • Error messages now automatically receive focus for improved accessibility.
  • Bug Fixes
    • Updated error screens to use system colors for better theme compatibility.
  • Style
    • Disabled the favourites control until favourites functionality is available, with updated labeling and visual styling.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Error accessibility

Layer / File(s) Summary
Focus error headings and apply system colors
src/app/global-error.tsx, src/components/route-error-boundary.tsx
Error headings become programmatically focusable and receive focus when errors change; the global error screen uses system color tokens.

Therapy Compass recovery

Layer / File(s) Summary
Retry therapy data loading
src/components/therapy-compass/data/use-therapy-data.ts, src/components/therapy-compass/bindings.tsx
Therapy data exposes a retry callback that resets cached state, triggers refetching, and is published through retryData.
Render recovery and disabled favourites
src/components/therapy-compass/therapy-compass-page.tsx, src/components/therapy-compass/therapy-card.tsx
Therapy Compass displays an alert with a Retry button on load errors, while the favourites button is disabled and marked unavailable.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TherapyCompassShell
  participant TcProvider
  participant useTherapyData
  TherapyCompassShell->>TcProvider: invoke retryData
  TcProvider->>useTherapyData: invoke retry
  useTherapyData->>useTherapyData: clear cache and reset loading state
  useTherapyData->>useTherapyData: increment attempt and refetch dataset
Loading

Possibly related PRs

Suggested reviewers: claude

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the change and testing, but it misses the template's required Summary, Verification, Risk and rollout, Notes, and governance sections. Reformat it to the repo template, add a Summary, the required Verification checklist or 'not run' notes, and complete Risk/Rollback and Notes sections.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the PR's main focus on Therapy Compass recovery and error accessibility.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/resolve-design-audit-findings-and-merge

Comment @coderabbitai help to get the list of available commands.

@supabase

supabase Bot commented Jul 17, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@BigSimmo
BigSimmo marked this pull request as ready for review July 17, 2026 19:37
@BigSimmo
BigSimmo enabled auto-merge July 17, 2026 19:37
@BigSimmo

Copy link
Copy Markdown
Owner Author

@copilot resolve the merge conflicts in this pull request

…audit-findings-and-merge

# Conflicts:
#	src/components/therapy-compass/therapy-card.tsx
auto-merge was automatically disabled July 17, 2026 19:40

Head branch was pushed to by a user without write access

Copilot AI commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. There was a single conflict in src/components/therapy-compass/therapy-card.tsx — main had bumped the favourite button's touch target to 44×44 px while our branch had disabled it with cursor:not-allowed; opacity:.65. I kept the larger touch target from main and preserved the disabled styling from our branch, then merged origin/main into the PR branch (merge commit 1019292e).

@BigSimmo
BigSimmo enabled auto-merge July 17, 2026 19:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/global-error.tsx`:
- Line 49: Restore a visible focus indicator on the error headings by replacing
the outline removal in src/app/global-error.tsx lines 49-49 with a visible
outline style, and update the focused heading in
src/components/route-error-boundary.tsx lines 59-61 to remove focus:outline-none
and provide an equivalent visible outline. Keep the existing heading focus
behavior unchanged.

In `@src/components/therapy-compass/data/use-therapy-data.ts`:
- Around line 41-45: Update the retry and promise rejection flow around retry
and cache handling so an older request only clears cache when it still owns the
cached promise; guard the cache reset by comparing the relevant
promise/reference before assigning null, preserving newer in-flight requests.

In `@src/components/therapy-compass/therapy-compass-page.tsx`:
- Around line 47-55: Update the error/retry flow around b.retryData so focus is
preserved when retry clears b.error and unmounts the Retry button. Move focus to
a stable loading or content container after retry begins, or keep the error
panel mounted with the button disabled and updated during loading; ensure
keyboard and screen-reader users retain a logical focus position throughout
recovery.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f54bdb20-30c0-4c23-96c5-7313b30ca1b6

📥 Commits

Reviewing files that changed from the base of the PR and between b04c95f and 1019292.

📒 Files selected for processing (6)
  • src/app/global-error.tsx
  • src/components/route-error-boundary.tsx
  • src/components/therapy-compass/bindings.tsx
  • src/components/therapy-compass/data/use-therapy-data.ts
  • src/components/therapy-compass/therapy-card.tsx
  • src/components/therapy-compass/therapy-compass-page.tsx

Comment thread src/app/global-error.tsx
>
<h1 style={{ margin: "0 0 0.5rem", fontSize: "1.125rem", fontWeight: 600 }}>Something went wrong</h1>
<p style={{ margin: "0 0 1.25rem", fontSize: "0.875rem", lineHeight: 1.6, color: "#5b6069" }}>
<h1 ref={headingRef} tabIndex={-1} role="alert" style={{ margin: "0 0 0.5rem", fontSize: "1.125rem", fontWeight: 600, outline: "none" }}>Something went wrong</h1>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== file list ==\n'
git ls-files 'src/app/global-error.tsx' 'src/components/route-error-boundary.tsx' 'src/**/error*.tsx' 'src/**/error*.ts' 'src/**/global-error.tsx'

printf '\n== outline global-error ==\n'
ast-grep outline src/app/global-error.tsx --view expanded || true

printf '\n== outline route-error-boundary ==\n'
ast-grep outline src/components/route-error-boundary.tsx --view expanded || true

printf '\n== relevant snippets ==\n'
sed -n '1,140p' src/app/global-error.tsx
printf '\n---\n'
sed -n '1,180p' src/components/route-error-boundary.tsx

Repository: BigSimmo/Database

Length of output: 8716


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== search for focus styles in error boundaries ==\n'
rg -n "focus:outline-none|outline:\s*\"none\"|tabIndex=\{-1\}|role=\"alert\"|headingRef" src/app src/components src -g '!**/node_modules/**'

printf '\n== search for visible focus token usage ==\n'
rg -n "var\(--focus\)|focus-visible|focus:outline|outline-offset|outline-" src/app src/components src -g '!**/node_modules/**' | sed -n '1,200p'

Repository: BigSimmo/Database

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
for p in [Path('src/app/global-error.tsx'), Path('src/components/route-error-boundary.tsx')]:
    print(f"\n## {p}")
    text = p.read_text()
    for needle in ['outline: "none"', 'focus:outline-none', 'tabIndex={-1}', 'role="alert"']:
        print(needle, text.find(needle))
PY

Repository: BigSimmo/Database

Length of output: 386


Restore a visible focus style on the error headings.

Both boundaries move focus to the <h1>, but outline: "none" / focus:outline-none removes the only visible focus indicator. Add a visible outline instead.

  • src/app/global-error.tsx#L49
  • src/components/route-error-boundary.tsx#L59-L61
📍 Affects 2 files
  • src/app/global-error.tsx#L49-L49 (this comment)
  • src/components/route-error-boundary.tsx#L59-L61
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/global-error.tsx` at line 49, Restore a visible focus indicator on
the error headings by replacing the outline removal in src/app/global-error.tsx
lines 49-49 with a visible outline style, and update the focused heading in
src/components/route-error-boundary.tsx lines 59-61 to remove focus:outline-none
and provide an equivalent visible outline. Keep the existing heading focus
behavior unchanged.

Comment on lines +41 to +45
const retry = useCallback(() => {
cache = null;
setState({ data: null, loading: true, error: null });
setAttempt((value) => value + 1);
}, []);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -P '\buseTherapyData\s*\(' src

Repository: BigSimmo/Database

Length of output: 375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== use-therapy-data.ts ==\n'
cat -n src/components/therapy-compass/data/use-therapy-data.ts | sed -n '1,240p'

printf '\n== bindings.tsx (relevant range) ==\n'
cat -n src/components/therapy-compass/bindings.tsx | sed -n '180,250p'

printf '\n== all useTherapyData references ==\n'
rg -n -P '\buseTherapyData\s*\(' src

Repository: BigSimmo/Database

Length of output: 7157


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cat -n src/components/therapy-compass/data/use-therapy-data.ts | sed -n '1,220p'

Repository: BigSimmo/Database

Length of output: 2786


Guard cache before clearing it. retry can start a new load while a previous promise is still pending, and the older rejection handler currently does cache = null unconditionally. That can wipe out the newer in-flight promise and force an unnecessary refetch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/therapy-compass/data/use-therapy-data.ts` around lines 41 -
45, Update the retry and promise rejection flow around retry and cache handling
so an older request only clears cache when it still owns the cached promise;
guard the cache reset by comparing the relevant promise/reference before
assigning null, preserving newer in-flight requests.

Comment on lines +47 to +55
{b.error ? (
<section role="alert" aria-live="assertive" style={s(`max-width:42rem;margin:40px auto;padding:24px;border:1px solid var(--danger);border-radius:16px;background:var(--danger-soft);`)}>
<h1 style={s(`margin:0 0 8px;color:var(--text-heading);font-size:20px;`)}>Therapy Compass could not load</h1>
<p style={s(`margin:0 0 16px;color:var(--text-muted);line-height:1.5;`)}>The therapy catalogue is unavailable. No results are being shown as a substitute.</p>
<button type="button" className="tc-btn" onClick={b.retryData} style={s(`padding:10px 14px;border:0;border-radius:8px;background:var(--clinical-accent);color:var(--clinical-accent-contrast);font-weight:650;`)}>
Retry
</button>
</section>
) : (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve focus when Retry starts loading.

Clicking Retry clears b.error, which immediately unmounts the focused button. Focus then falls back to the document/body, so keyboard and screen-reader users lose their place during recovery. Move focus to a stable loading/content container or keep this panel mounted and disable/update the button while the retry is in progress.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/therapy-compass/therapy-compass-page.tsx` around lines 47 -
55, Update the error/retry flow around b.retryData so focus is preserved when
retry clears b.error and unmounts the Retry button. Move focus to a stable
loading or content container after retry begins, or keep the error panel mounted
with the button disabled and updated during loading; ensure keyboard and
screen-reader users retain a logical focus position throughout recovery.

@github-actions

Copy link
Copy Markdown

CI triage

CI failed on this PR. Automated classification of the 2 failed job(s):

  • Static PR checksneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

Compared with main CI run #2979 (success).

Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger.

@BigSimmo BigSimmo closed this Jul 17, 2026
auto-merge was automatically disabled July 17, 2026 20:14

Pull request was closed

@BigSimmo
BigSimmo deleted the codex/resolve-design-audit-findings-and-merge branch July 18, 2026 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants