Skip to content

Open where the doctor is, keyboard shortcuts, quiet motion and one offline line - #3499

Merged
gitar-bot[bot] merged 17 commits into
mainfrom
claude/site-nav-motion-xk2j9i
Oct 13, 2026
Merged

gitar-bot[bot] merged 17 commits into
mainfrom
claude/site-nav-motion-xk2j9i

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

User description

🤖 Generated with Claude Code

https://claude.ai/code/session_01Mws6schjKQbpCQqQzPMKSL

Summary

Before: the installed app always opened on Clinical Answer; the desktop Work rail had no way back to Clinical; "/" and Ctrl K did not work on the Psychiatry and Medicines homes and there was no shortcuts list; tabs swapped instantly; the offline notice did not say how old the page was.

After:

  • Opening the app (or a fresh tab on a bare "/") goes to the last Work or Clinical page used on this device, or to My Day when a real roster shift is on now. A reload, Back, a "/" with a query, an in-app arrival or a set Default landing view keep today's behaviour, and it gives up as soon as the doctor taps or types.
  • The desktop and tablet Work rail has a Clinical button, matching My Day on the Clinical rail.
  • "/" and Ctrl K work on the Psychiatry and Medicines homes; "?" opens a short Keyboard shortcuts list on Clinical pages, also linked from Work Help. Pointer screens only, never while typing.
  • Tab content fades in over 150 ms and a tapped Work row releases its highlight softly. All off under reduced motion. The Clinical composer is never faded.
  • The offline notice reads "Offline, showing what was saved at HH:MM" (Perth time, the last time the page was opened online), the same card in Work and Clinical. On Call's saved-copy banner uses the same wording.

How: last-page memory is a bare path on the device only. The manifest and its start address are unchanged; the decision happens on the device and uses a replace navigation. public/sw.js is untouched.

Areas touched: App experience, Personal practice, Design system (plus 15 files not yet placed in any area)

Verification

  • eslint on changed files: clean. Typecheck: pass. Prettier: formatted. check:design-system-contract: pass.
  • npm run test:focused: 23 files, 347 tests passed.
  • Screenshots before and after: Work rail at 768 and 1440, shortcuts list, offline line in Work and Clinical at 320, 390 and 1440, cold open.
  • Full browser suite (including Firefox, Safari and phone) to be run on this draft by a manual browser-matrix dispatch.

Risk and rollout

  • No clinical wording, crisis lines, ranking, migration or service worker change.
  • On a cold open, Clinical can show for up to about 2.5 seconds before the move to the remembered page.
  • My Day's own offline card and the Clinical dashboard's offline drawer still show alongside the new line; reconciling them is a follow-up.
  • Rollback: revert this PR.

Notes

Site-wide recommendations 1, 5, 9 and 10 (12 Oct 2026). Offline copies of On Call numbers and crisis lines need a service worker change and are not in this PR.

Generated by Claude Code


Summary by cubic

Opens a cold start where the doctor left off instead of always on Clinical Answer: a bare / in a fresh tab or the installed app goes to the last Work or Clinical page used on this device, or to My Day while a real rostered shift runs. The Work rail gains a Clinical button, / and Ctrl K reach a page's own search box, ? opens a keyboard shortcuts list on a computer, tab content fades in quietly, and the offline notice names when the saved copy was taken.

  • Only a cold open of a bare / moves: reloads, Back, in-app arrivals, any query or hash, a tab already used, and a set Default landing view keep today's behaviour. Only bare page paths are remembered (never token, setup, or search-result pages), and the move gives up the moment the doctor taps or types — the roster probe is deferred so the home page stays within its download budget.
  • The Clinical rail button always returns to Clinical even if the last mode was a Work one; fades touch only tab and Work content, never the composer, and switch off under reduced motion. The offline line names the work-clock time only for the page on screen when the signal dropped — the Clinical home and any page opened offline or switched by query after the loss say "saved earlier", and a failed first load of the wording helper is retried when the signal returns.

Written for commit d5b6320. Summary will update on new commits.

View guided diff Turn on auto-fix


CodeAnt-AI Description

Resume the last-used page and make navigation and offline status clearer.

What Changed

  • A fresh launch or new tab opened at the home address returns to the last Clinical or Work page used on this device, or opens My Day during an active shift. Query links, reloads, in-app navigation, and an explicitly chosen default keep their existing behavior; interacting with the page cancels the redirect.
  • Desktop and tablet Work navigation now has a Clinical link that returns to the last Clinical mode.
  • On computers, / and Ctrl/Command+K focus an available search box, and ? opens the shortcut list on Clinical pages. The list is also available from Work Help.
  • Page and tab content fades in briefly, and pressed Work-row highlights fade out gently. Reduced-motion settings disable these effects.
  • Offline notices show when the current page was last opened online; On Call notices show when its saved copy was taken. Older copies include the date, and failed refreshes are distinguished from lost connectivity.

Impact

✅ Fewer steps back to the last-used page
✅ Faster keyboard search on Clinical pages
✅ Clearer age of offline copies and refresh failures

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

…k rail

A cold open of a bare "/" (the installed app's start address or a typed
visit) now goes to the last Work or Clinical page used, or to My Day while
a real rostered shift is running. The page is remembered on this device
only, as a bare path (no query string, no hash). Any "/" with a query,
a reload, Back, an arrival from inside the app, or a set Default landing
view keeps today's behaviour. The move uses replace, and it gives up the
moment the doctor taps or types.

The desktop and tablet work rail gains a Clinical button in the place the
Clinical rail keeps My Day, opening the Clinical mode used last.

The manifest keeps start_url "/" (its id is "/", so identity would not
change either way); the decision is made on the client.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mws6schjKQbpCQqQzPMKSL
On a computer (a mouse or trackpad screen), never while typing in a field
and never over an open dialog:
- "/" and Ctrl K (Command K on a Mac) now reach the page's own search box
  on the Psychiatry and Medicines homes, where the shared composer is not
  on screen. Elsewhere the composer's existing shortcut and Work's AI
  Search shortcut keep doing this; a key a page has handled is left alone.
- "?" on a Clinical page shows a short "Keyboard shortcuts" list. Work
  pages keep their AI Search list.
- The Work Help page gains an "On a computer" row that opens the list.

Esc already closes every sheet and dialog (the shared Sheet owns it), so
nothing changed there. The composer's position and behaviour are unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mws6schjKQbpCQqQzPMKSL
One small motion set in src/app/motion.css, on the design system's motion
tokens, all off under prefers-reduced-motion and the in-app "reduced"
Motion setting (the in-app "full" opts back in):
- Tab content fades in over --duration-quick (150 ms) when a role="tab"
  control switches, and when moving between two Work pages (Work's tab
  row is pages). The Work band (title and tabs) stays put; only opacity
  moves, so nothing shifts position. Clinical routes and anything holding
  the search composer are never faded.
- A tapped Work list row lights at once and lets go over
  --duration-deliberate, so the highlight is still visible as the next
  page opens.
Bottom sheets already rise with a soft settle (the shared Sheet's
sheet-up), so nothing is added there. The number count-up was skipped.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mws6schjKQbpCQqQzPMKSL
The app-wide offline notice now reads "Offline, showing what was saved at
19:02": the work-clock (Perth by default) time the page on screen was last
opened online, which can understate how fresh the page is but never
overstates it. A copy from an earlier day names the day; an unknown time
says "saved earlier". It is the same card in Work and Clinical: Work's
squeezed one-row variant broke once the line named a time, so it now draws
the Clinical card (keeping Work's glass ground). The "needs a connection"
sentence stays for screen readers.

On Call's saved-copy banner uses the same wording (a server that could not
be reached reads "Couldn't refresh, showing what was saved at ...", since
that is not lost signal), with the same offline icon.

public/sw.js is untouched, and no new offline caching was added.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mws6schjKQbpCQqQzPMKSL
A tab that has already been round the app (more than its own start page
and this one in its history) keeps today's "/" exactly, so typing "/"
mid-session, or a test that visits a Work page and then "/", is never
moved. The installed app's own window still always opens where the
doctor was.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mws6schjKQbpCQqQzPMKSL
@BigSimmo BigSimmo self-assigned this Oct 12, 2026
@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 9f21ba01-fccc-468c-98bf-c9b35ad293a6
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@supabase

supabase Bot commented Oct 12, 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 ↗︎.

@codeant-ai

codeant-ai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

🏁 CodeAnt Quality Gate Results

Commit: d5b63209
Scan Time: 2026-10-13 03:13:38 UTC

✅ Overall Status: PASSED

Quality Gate Details

Quality Gate Status Details
Secrets ✅ PASSED 0 secrets found
Duplicate Code ✅ PASSED 0.0% duplicated
SAST ✅ PASSED No security issues
Bugs ✅ PASSED Rating S: No bugs
IAC ✅ PASSED No IAC issues

View Full Results

@codspeed

codspeed Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ 1 benchmark spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

✅ 8 untouched benchmarks


Comparing claude/site-nav-motion-xk2j9i (d5b6320) with main (2f928bd)

Open in CodSpeed

Comment thread src/components/pwa-lifecycle.tsx Resolved
A page reached after the signal drops comes from a saved copy of unknown
age, so the offline line now says "saved earlier" instead of keeping the
previous page's time.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mws6schjKQbpCQqQzPMKSL
gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 12, 2026

@gitar-bot gitar-bot 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.

Gitar has auto-approved this PR (configure)

Copy link
Copy Markdown
Owner Author

Full browser suite on this draft (run 38260010530, failed jobs re-run once): Chromium, Firefox, desktop Safari and iPad passed.

The one failure that looked specific to this PR, ui-on-call-service.spec.ts:81 on iPhone ("element is not attached"), passed on the re-run, so it was a timing flake. What still fails after the re-run is main's known iPhone Safari backlog (ledger #9Z197J): ui-on-call-boards.spec.ts:558 (Admin Help Support anchor) on both iPhone projects, and ui-phone-scroll-assessments.spec.ts:19, which also fails on #3498. None of those pages are changed here. Not this PR's; marking ready.


Generated by Claude Code

@BigSimmo
BigSimmo marked this pull request as ready for review October 12, 2026 15:58
@codeant-ai

codeant-ai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed ac2ff90 Oct 13, 2026 · 02:39 02:40
✅ Incremental review completed f17b9de Oct 13, 2026 · 01:29 01:30
✅ Incremental review completed 24b5480 Oct 12, 2026 · 21:04 21:05
✅ Incremental review completed e19c206 Oct 12, 2026 · 19:22 19:23
✅ Incremental review completed 247daaa Oct 12, 2026 · 17:03 17:04

@codeant-ai

codeant-ai Bot commented Oct 12, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

BigSimmo has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-12T16:04:43.433243Z 0532f0c Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@gitar-bot
gitar-bot Bot enabled auto-merge (squash) October 12, 2026 15:59
@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Oct 12, 2026
@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Restore last place on cold open and improve shortcuts, motion, and offline notices

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Open fresh app visits on the last page, or My Day during a real shift.
• Add a Clinical return link and fill keyboard shortcut gaps across the app.
• Soften tab transitions and show when offline content was last opened online.
Diagram

graph TD
  A["Open home"] --> B{"Cold open?"} -->|yes| C["Check roster"] --> D{"Shift now?"} -->|yes| E["My Day"]
  B -->|no| G["Keep current view"]
  D -->|no| F{"Remembered page?"} -->|yes| H["Last page"]
  F -->|no| G
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Server-side landing redirects
  • ➕ Could avoid briefly displaying Clinical before navigation.
  • ➖ Would require sending the device-only last-page preference to the server or changing how it is stored.
  • ➖ Would complicate the unchanged installed-app start address and roster-dependent decision.

Recommendation: Keep the client-side replace navigation: it preserves device-only storage, existing deep links, and the installed-app identity. Review the brief initial Clinical display and the roster timeout as deliberate trade-offs.

Files changed (25) +1395 / -28

Enhancement (14) +817 / -14
layout.tsxMount app-wide navigation and interaction helpers +9/-0

Mount app-wide navigation and interaction helpers

• Loads motion styles and mounts last-place navigation, keyboard shortcuts, and motion handling outside the shared search shell.

src/app/(search-app)/layout.tsx

motion.cssDefine reduced-motion-aware fades and row transitions +60/-0

Define reduced-motion-aware fades and row transitions

• Adds token-based content fades and Work-row highlight transitions, respecting system and in-app motion preferences.

src/app/motion.css

keyboard-shortcuts-sheet.tsxPresent the keyboard shortcuts list +51/-0

Present the keyboard shortcuts list

• Displays platform-specific key combinations in a shared Sheet loaded when first requested.

src/components/keyboard-shortcuts/keyboard-shortcuts-sheet.tsx

keyboard-shortcuts.tsxHandle unclaimed search and help shortcuts +81/-0

Handle unclaimed search and help shortcuts

• Focuses a page-owned search box where the shared composer is absent and opens shortcut help on fine-pointer screens. Leaves typing, dialogs, and already-handled keys alone.

src/components/keyboard-shortcuts/keyboard-shortcuts.tsx

last-place.tsxChoose a landing page on eligible cold opens +196/-0

Choose a landing page on eligible cold opens

• Remembers eligible paths locally and checks the real roster before replacing a fresh home visit. Stops the decision after a timeout or user interaction.

src/components/last-place/last-place.tsx

motion-enter.tsxMark newly shown tab and Work content for fading +118/-0

Mark newly shown tab and Work content for fading

• Triggers content-only fades after tab changes or Work-page navigation while avoiding the Clinical composer.

src/components/motion/motion-enter.tsx

on-call-offline-banner.tsxAlign On Call saved-copy messaging +8/-9

Align On Call saved-copy messaging

• Uses the shared saved-time wording and distinguishes an offline signal from a failed refresh.

src/components/on-call/on-call-offline-banner.tsx

pwa-lifecycle.tsxShow the online-open time in the offline notice +20/-4

Show the online-open time in the offline notice

• Tracks when the displayed page was opened online and shows that time after connectivity drops. Avoids claiming a known time after offline navigation.

src/components/pwa-lifecycle.tsx

pwa-offline-line.cssUnify Work and Clinical offline-card layout +37/-0

Unify Work and Clinical offline-card layout

• Removes Work-specific compact styling from the offline card so the longer saved-time line uses the same layout in both modes.

src/components/pwa-offline-line.css

work-rail.tsxAdd a Clinical return link to the Work rail +28/-1

Add a Clinical return link to the Work rail

• Links to the most recently used Clinical mode from the desktop and tablet rail.

src/components/work-frame/work-rail.tsx

work-help-page.tsxLink shortcut help from Work Help +23/-0

Link shortcut help from Work Help

• Adds a computer-only row that opens the shared keyboard shortcuts sheet.

src/components/work-help/work-help-page.tsx

keyboard-shortcuts.tsDefine shared shortcut rules and help rows +41/-0

Define shared shortcut rules and help rows

• Centralizes key recognition, typing-target detection, and platform-specific shortcut labels.

src/lib/keyboard-shortcuts.ts

last-place.tsDefine safe remembered-path and cold-open rules +108/-0

Define safe remembered-path and cold-open rules

• Filters stored paths, excludes unsuitable destinations, and resolves cold-open landing priority without persisting queries or hashes.

src/lib/last-place.ts

offline-line.tsFormat a shared saved-copy notice +37/-0

Format a shared saved-copy notice

• Formats known saved times in the work time zone, names earlier days, and falls back when the time is unknown.

src/lib/offline-line.ts

Tests (9) +575 / -13
keyboard-shortcuts.dom.test.tsxCover shortcut recognition and browser behavior +115/-0

Cover shortcut recognition and browser behavior

• Tests key combinations, focus handling, handled keys, pointer gating, and both ways to open shortcut help.

tests/keyboard-shortcuts.dom.test.tsx

last-place.dom.test.tsxCover client-side cold landing +146/-0

Cover client-side cold landing

• Tests remembered-page and active-shift landings, excluded visits, interaction cancellation, and path storage.

tests/last-place.dom.test.tsx

last-place.test.tsCover pure landing and path rules +107/-0

Cover pure landing and path rules

• Tests safe stored paths, cold-open eligibility, landing priorities, and route-visibility fallback.

tests/last-place.test.ts

motion-enter.dom.test.tsxCover motion gating and Work content targeting +93/-0

Cover motion gating and Work content targeting

• Checks motion preferences, animation cleanup, and that Work content—but not its band—is marked on navigation.

tests/motion-enter.dom.test.tsx

offline-line.test.tsCover saved-copy time wording +32/-0

Cover saved-copy time wording

• Tests Perth time, earlier-day labels, failed refreshes, and unknown timestamps.

tests/offline-line.test.ts

on-call-compliance.test.tsRefresh the On Call notice reference +1/-1

Refresh the On Call notice reference

• Updates a test comment to reflect the new saved-copy wording.

tests/on-call-compliance.test.ts

on-call-contacts.dom.test.tsxAssert the revised On Call offline banner +5/-3

Assert the revised On Call offline banner

• Checks the shared saved-time wording and its accessible announcement.

tests/on-call-contacts.dom.test.tsx

pwa-lifecycle.dom.test.tsxCover offline notice age and lifecycle behavior +42/-9

Cover offline notice age and lifecycle behavior

• Tests the online-open timestamp, unknown age after offline navigation, and existing notice transitions under the revised wording.

tests/pwa-lifecycle.dom.test.tsx

work-rail-clinical.dom.test.tsxCover the Work rail's Clinical destination +34/-0

Cover the Work rail's Clinical destination

• Checks both the default Clinical Answer link and a remembered Clinical mode.

tests/work-rail-clinical.dom.test.tsx

Documentation (2) +3 / -1
COMPONENTS.mdRefresh Sheet usage count +1/-1

Refresh Sheet usage count

• Updates the generated component inventory to account for the new shortcuts sheet.

docs/design-system/COMPONENTS.md

adoption-manifest.jsonRegister the shortcuts sheet +2/-0

Register the shortcuts sheet

• Adds the new sheet to the design-system adoption inventory.

docs/design-system/adoption-manifest.json

@qodo-code-review

Copy link
Copy Markdown
Contributor

Qodo Fixer

No findings are available for this PR yet. Findings appear here once Qodo has reviewed the PR.

@claude

claude Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Claude encountered an error after 2s —— View job


I'll analyze this and get back to you.

@qodo-code-review

qodo-code-review Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

No findings for this group


Remediation recommended

No findings for this group


Informational

1. Fallback offline wording is a hand-copied string 🟡 Low 🐞 Bug ⚙ Maintainability
Description
OFFLINE_LINE_FALLBACK repeats by hand the unknown-time sentence that savedLine builds as
${lead}, showing what was saved earlier. If someone later changes the wording in
offline-line.ts, the first-load fallback and the deferred line will say different things in the
same notice, and no type check or test links the two.
Code

src/components/pwa-lifecycle.tsx[R25-26]

+/** savedLine's own wording when the save time is unknown. */
+const OFFLINE_LINE_FALLBACK = "Offline, showing what was saved earlier";
Relevance

●●● Strong

Deterministic wording-drift prevention aligns with recent accepted consistency and maintainability
fixes.

PR-#3495

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The constant matches the template literal in savedLine but is written separately. The only thing
tying them together is a comment.

src/components/pwa-lifecycle.tsx[23-26]
src/lib/offline-line.ts[29-31]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The offline notice's fallback text is copied by hand from savedLine's unknown-time wording.

## Fix Focus Areas
- src/components/pwa-lifecycle.tsx[23-26]
- src/lib/offline-line.ts[29-31]

## Recommended Fix
Move the wording into a tiny dependency-free module, for example `src/lib/offline-line-copy.ts`, that exports `savedEarlierLine(lead)` or the constant. Import it statically in both `offline-line.ts` and `pwa-lifecycle.tsx` so the bundle stays small. Alternatively, add a unit test asserting `savedLine({ savedAt: null }) === OFFLINE_LINE_FALLBACK`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


Grey Divider


Resolved findings

1. Offline notice never regains its time ✓ Resolved
Description
PwaLifecycle attempts to import savedLine only once and silently discards a failed chunk load,
leaving savedLineFn null for the rest of the mount. If the chunk is unavailable during an offline
start or a connection failure, reconnecting does not retry the import, and later offline notices
show “saved earlier” even when offlineSavedAt contains a valid time.
Code

src/components/pwa-lifecycle.tsx[R360-364]

+    import("@/lib/offline-line")
+      .then((module) => {
+        if (live) setSavedLineFn(() => module.savedLine);
+      })
+      .catch(() => {});
Relevance

●●● Strong

Recent lifecycle precedent explicitly accepted reconnect retries after failed dynamic imports.

PR-#3458

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The mount effect runs once, updates savedLineFn only when the dynamic import succeeds, and has an
empty rejection handler, so a failed load is neither logged nor retried. The notice uses the
recorded time only when savedLineFn is available; otherwise it renders the fixed fallback, and
cache-first handling of Next assets does not guarantee that an uncached helper chunk is available
during a connection failure.

src/components/pwa-lifecycle.tsx[353-368]
src/components/pwa-lifecycle.tsx[636-636]
src/components/pwa-lifecycle.tsx[357-368]
src/components/pwa-lifecycle.tsx[384-410]
src/components/pwa-lifecycle.tsx[633-636]
public/sw.js[400-418]
Skill: review

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A failed one-shot import of the offline wording helper leaves later offline notices on a generic fallback even when a saved time is available.

## Fix Focus Areas
- src/components/pwa-lifecycle.tsx[353-368]
- src/components/pwa-lifecycle.tsx[633-636]

## Recommended Fix
Keep the helper out of the initial bundle, but move its import into a reusable function called at mount and again from the existing `online` handler if `savedLineFn` is still null. Prevent duplicate in-flight imports, guard against updates after unmount, and clean up listeners on unmount. Retain the generic fallback until the import succeeds, and log a `console.warn` in development when it fails. Add a focused test where the first import fails, connectivity returns, and a subsequent offline notice renders the recorded time.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Doctors can be redirected after tapping ✓ Resolved
Description
AppHelpersDeferred lazy-loads LastPlace, so its pointerdown and keydown cancellation
listeners are absent until that chunk mounts. If a doctor uses a control on the freshly opened
Clinical home before then, particularly one that changes the view without leaving /, the later
cold-open decision can still replace the page with My Day or a remembered page.
Code

src/components/app-helpers-deferred.tsx[R10-12]

+const LastPlace = dynamic(() => import("@/components/last-place/last-place").then((m) => m.LastPlace), {
+  ssr: false,
+});
Relevance

●●● Strong

Deferred cancellation listeners can miss early interaction, matching recent acceptance of pre-import
listener preservation.

PR-#3458

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The deferred import delays mounting LastPlace. Its cancellation listeners are installed only while
checking in an effect, while finish can subsequently navigate to the stored target. Clinical
mode selection can change the view through onSearchModeChange without changing the / pathname,
so checking that pathname does not establish that the doctor has not interacted.

src/components/app-helpers-deferred.tsx[10-12]
src/components/last-place/last-place.tsx[133-154]
src/components/clinical-dashboard/master-search-header.tsx[983-1012]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Lazy-loading LastPlace creates a window in which the home is interactive but the cold-open cancellation listeners are not installed. An interaction during that window can be followed by an unwanted redirect.

## Fix Focus Areas
- src/components/app-helpers-deferred.tsx[10-12]
- src/components/last-place/last-place.tsx[142-164]

## Recommended Fix
Install a lightweight capture-phase interaction guard with the initial app client code, before deferring the roster and landing logic. Have LastPlace consult that guard before starting or completing a cold-open navigation, including after a same-path view change.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Clinical return forgets the last mode ✗ Dismissed
Description
WorkRailClinical substitutes DEFAULT_APP_MODE when the single stored last mode is a Work mode,
because selecting Work overwrites the preceding Clinical selection. If a doctor selects DSM and then
My Day from the mode menu, clicking Clinical on the Work rail opens Answer instead of returning to
DSM.
Code

src/components/work-frame/work-rail.tsx[R57-60]

+  const [storedMode] = useLastAppMode();
+  // The mode menu also remembers Work modes (My Day, Roster), which must never
+  // turn this button into a link to another Work page.
+  const lastMode = modeMenuSideForMode(storedMode) === "clinical" ? storedMode : DEFAULT_APP_MODE;
Relevance

●●● Strong

The shared last-mode value loses prior Clinical selection after Work navigation, contradicting the
stated return-to-last-Clinical intent.

PR-#3462
PR-#2378

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The mode-selection handler writes both Clinical and Work selections to one stored last-mode value,
and My Day is classified as a Work mode. The Work rail converts a stored Work mode to Answer, so
after My Day overwrites DSM, it has no previous Clinical selection to restore; this is distinct from
choosing the wrong Work-page destination.

src/components/work-frame/work-rail.tsx[56-64]
src/components/clinical-dashboard/use-last-app-mode.ts[64-78]
src/components/clinical-dashboard/master-search-header.tsx[956-970]
src/components/clinical-dashboard/use-last-app-mode.ts[18-19]
src/components/clinical-dashboard/use-last-app-mode.ts[66-82]
src/components/clinical-dashboard/global-search-shell.tsx[785-805]
src/lib/phone-mode-groups.ts[104-113]
src/components/work-frame/work-rail.tsx[56-67]
Skill: review
Skill: frontend-architecture-review

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Selecting a Work mode overwrites the only remembered mode, so the Work rail cannot return to the doctor’s previous Clinical mode.

## Fix Focus Areas
- src/components/work-frame/work-rail.tsx[56-64]
- src/components/clinical-dashboard/use-last-app-mode.ts[18-82]
- src/components/clinical-dashboard/global-search-shell.tsx[785-805]
- tests/work-rail-clinical.dom.test.tsx[27-41]

## Recommended Fix
Persist the most recently selected Clinical mode separately from the overall last mode when modes are selected. Have the Work rail use that Clinical-only selection when the stored last mode is Work, falling back to Answer only when no Clinical selection exists. Test the sequence Clinical mode → Work mode → Clinical rail.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View resolved (6)
4. Offline roster shows a false save time ✓ Resolved
Description
offlineSavedAt excludes / but still treats /roster?view=hours and /roster as the same page
because it compares only their pathname. If a doctor opens Hours online and switches to the month
roster after losing connectivity, the notice assigns the Hours page’s online-open time to month
content that may be older.
Code

src/components/pwa-lifecycle.tsx[R331-334]

+  // The Clinical home "/" switches what it shows by query (?mode=…) without a new
+  // path, so there a matching path proves nothing and the line says "saved earlier".
+  const offlineSavedAt =
+    offlineSaved && pathname !== "/" && offlineSaved.pathname === pathname ? offlineSaved.at : null;
Relevance

●●● Strong

Query-driven content makes pathname-only freshness unsafe; recent precedents accept preserving state
across same-route query transitions.

PR-#3461
PR-#3462

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The changed condition accepts any matching non-home pathname. The roster uses view to select
different page components, and its Work navigation exposes the query-bearing Hours route, so an
offline view switch can retain a timestamp recorded for different content. This is a concrete
changed-behavior failure path under the review skill.

src/components/pwa-lifecycle.tsx[326-334]
src/components/roster/roster-home.tsx[8-19]
src/lib/work-frame/areas.ts[427-432]
Skill: review

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The offline timestamp can be reused for different roster content because the new eligibility check compares only pathnames.

## Fix Focus Areas
- src/components/pwa-lifecycle.tsx[326-334]
- src/components/pwa-lifecycle.tsx[374-376]
- tests/pwa-lifecycle.dom.test.tsx[224-260]

## Recommended Fix
Track the query-bearing route when recording which page was opened online, and require that route to match before showing its timestamp offline. Preserve the intentional unknown-time behavior for the Clinical home, and test an offline switch between roster views sharing `/roster`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Last-place memory can store and replay a one-time check-in token ✓ Resolved
Description
lastPlaceToRemember in src/lib/last-place.ts accepts any bare path matching SAFE_PATH that
isn't under SKIPPED_PREFIXES or ending in a skipped segment, and /teaching/c/<token> matches
neither exclusion so it is written verbatim to localStorage. The token route's own metadata
declares referrer: "no-referrer" specifically to keep the token from leaking, yet this feature
persists that same token client-side and later feeds it back into router.replace on a cold /
open, which can land the doctor on a terminal "scan again" failure screen instead of Clinical or My
Day.
Code

src/lib/last-place.ts[R32-47]

+const SKIPPED_LAST_SEGMENTS = new Set(["new", "edit", "search", "setup"]);
+const SKIPPED_PREFIXES = ["/safety-plan", "/mockups", "/api", "/auth"];
+
+/**
+ * The path to remember for a page, or null when the page should not replace
+ * the remembered one. `/` (the Clinical home) is remembered as `/`: the mode
+ * itself is already kept by `use-last-app-mode`.
+ */
+export function lastPlaceToRemember(pathname: string | null | undefined): string | null {
+  if (!pathname) return null;
+  if (pathname === "/") return "/";
+  if (pathname.length > MAX_PATH_LENGTH || !SAFE_PATH.test(pathname)) return null;
+  if (SKIPPED_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`))) return null;
+  const last = pathname.slice(pathname.lastIndexOf("/") + 1);
+  if (SKIPPED_LAST_SEGMENTS.has(last)) return null;
+  return pathname;
Relevance

●●● Strong

The team accepts findings preventing sensitive or context-dependent data from persisting in local
storage or replaying incorrectly.

PR-#3196
PR-#3245
PR-#3206

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The privacy skill requires inventorying sensitive data and tracing storage, retention and client
exposure for new persistence paths. The new last-place storage mechanism writes arbitrary
device-local paths including a referrer-sensitive, single-use token that the route itself explicitly
protects from leaking via no-referrer, and the exclusion lists added in this PR do not cover that
route.

src/lib/last-place.ts[13-47]
src/components/last-place/last-place.tsx[180-196]
src/app/(search-app)/teaching/c/[token]/page.tsx[1-17]
Skill: privacy

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`lastPlaceToRemember` in `src/lib/last-place.ts` stores any bare path not excluded by `SKIPPED_PREFIXES`/`SKIPPED_LAST_SEGMENTS`. It does not exclude `/teaching/c/<token>`, so a one-time, referrer-sensitive check-in token gets written to `localStorage` under `LAST_PLACE_STORAGE_KEY` and can later be replayed via `router.replace` on a cold open of `/`, landing the user on a dead/expired check-in screen and persisting a sensitive token longer than needed.

## Fix Focus Areas
- src/lib/last-place.ts[32-47]
- src/app/(search-app)/teaching/c/[token]/page.tsx[1-17]

## Recommended Fix
Add `/teaching/c` to `SKIPPED_PREFIXES` in `src/lib/last-place.ts` (or otherwise detect token/claim-bearing dynamic routes) so `lastPlaceToRemember` returns `null` for them, and add a regression test in `tests/last-place.test.ts` asserting `/teaching/c/<token>` is never remembered.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Work rail's Clinical button can open a Work page ✓ Resolved
Description
WorkRailClinical passes the unrestricted useLastAppMode() value to its icon, label, and
appModeHomeHref(), even though the shared mode menu also stores Work modes there. After a doctor
selects a Work mode such as My Day or Roster, the Clinical button names that mode and links to its
Work page instead of taking the doctor back to Clinical.
Code

src/components/work-frame/work-rail.tsx[R57-63]

+  const [lastMode] = useLastAppMode();
+  const Icon = appModeIcons[lastMode];
+  return (
+    <Link
+      href={appModeHomeHref(lastMode)}
+      className="work-rail__item"
+      aria-label={`Clinical, ${appModeDefinition(lastMode).label}`}
Relevance

●●● Strong

The team accepts navigation fixes when shared mode state routes users to the wrong destination or
standalone home.

PR-#2398
PR-#2378
PR-#2699

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The shared mode-selection handlers save the selected mode as the last app mode, and the store
accepts registered Work modes as well as Clinical modes. My Day and Roster are Work modes;
appModeHomeHref() resolves a stored Work mode to its own home, and WorkRailClinical uses that
stored value directly to construct the Clinical button.

src/lib/phone-mode-groups.ts[110-119]
src/components/clinical-dashboard/master-search-header.tsx[956-967]
src/components/clinical-dashboard/global-search-shell.tsx[789-803]
src/components/clinical-dashboard/use-last-app-mode.ts[66-82]
src/components/work-frame/work-rail.tsx[56-64]
src/components/clinical-dashboard/use-last-app-mode.ts[20-28]
src/components/clinical-dashboard/global-search-shell.tsx[799-804]
src/lib/app-modes.ts[775-782]
src/lib/app-modes.ts[873-892]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Clinical button in the work rail uses the last app mode without checking whether it is a Clinical mode. A stored Work mode such as My Day or Roster makes the button name that mode and link to its Work page.

## Fix Focus Areas
- src/components/work-frame/work-rail.tsx[56-74]
- src/components/clinical-dashboard/use-last-app-mode.ts[20-28]

## Recommended Fix
Before constructing the rail item, use the stored mode only when `modeMenuSideForMode(lastMode) === "clinical"`; otherwise use `DEFAULT_APP_MODE` from `use-last-app-mode`. `modeMenuSideForMode` is already imported. Use the resulting mode for the icon, href, and label. Add tests with `roster` and My Day stored as the last app mode, checking that the Clinical button links to the Clinical home.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Early shortcut presses do nothing ✗ Dismissed
Description
AppHelpersDeferred loads KeyboardShortcuts asynchronously, and that component registers its key
and help-request listeners only after mounting. On an interactive page before the chunk arrives, a
doctor’s ? press or a Help-page request to open the shortcuts list is lost rather than handled
when the component loads.
Code

src/components/app-helpers-deferred.tsx[R13-16]

+const KeyboardShortcuts = dynamic(
+  () => import("@/components/keyboard-shortcuts/keyboard-shortcuts").then((m) => m.KeyboardShortcuts),
+  { ssr: false },
+);
Relevance

●●● Strong

Deferred global listeners can lose early keyboard or custom events, matching accepted pre-import
listener preservation.

PR-#3458

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The dynamic import has no listener until KeyboardShortcuts mounts and its effect runs. That effect
is the sole registration shown for both the keydown handler and the event used by the Work Help row;
events dispatched earlier are not retained.

src/components/app-helpers-deferred.tsx[13-16]
src/components/keyboard-shortcuts/keyboard-shortcuts.tsx[52-74]
src/components/work-help/work-help-page.tsx[277-284]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The shortcuts listener is deferred along with the shortcuts interface, leaving an initial window in which key presses and Help-page requests are dropped.

## Fix Focus Areas
- src/components/app-helpers-deferred.tsx[13-16]
- src/components/keyboard-shortcuts/keyboard-shortcuts.tsx[52-74]

## Recommended Fix
Mount the lightweight key and help-request listeners with the interactive page, while continuing to lazy-load the shortcuts sheet. If listener registration must remain deferred, buffer Help-page requests until it is ready.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. My Day tab switches skip the fade ✗ Dismissed
Description
MotionEnter watches only usePathname() for Work navigation, and its other handler requires a tab
with role="tab". My Day’s On shift and My records links change only the page query parameter, so
their content switches without triggering either animation path.
Code

src/components/motion/motion-enter.tsx[R83-86]

+    previous.current = pathname;
+    if (from === pathname) return;
+    if (workAreaIdForPath(from) === null || workAreaIdForPath(pathname) === null) return;
+    markMotionEnter(workPageContent());
Relevance

●●● Strong

Recent query-state navigation findings were accepted; missing synchronization or transition handling
is a recognized correctness issue.

PR-#3480
PR-#3462

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The Work effect returns when the pathname is unchanged, while the alternate event handler looks only
for role tabs. My Day defines query-only destinations, reads that query to select its page, and
renders its Work tabs as links rather than role tabs.

src/components/motion/motion-enter.tsx[76-109]
src/lib/work-frame/areas.ts[237-249]
src/components/my-day/my-day-page.tsx[418-426]
src/components/work-frame/work-frame-header.tsx[164-179]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Work content fade does not run when a tab changes content through a query parameter without changing the pathname.

## Fix Focus Areas
- src/components/motion/motion-enter.tsx[76-109]
- src/lib/work-frame/areas.ts[237-249]

## Recommended Fix
Observe the active Work tab or relevant search parameters as well as the pathname, and mark the changed content on query-only tab navigation. Cover My Day’s On shift and My records links in a test.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Clinical home never shows its saved time ✗ Dismissed
Description
offlineSavedAt discards the recorded time whenever pathname is /, even if the doctor has not
changed modes or navigated since opening that page online. When connectivity drops on an unchanged
Clinical home, the notice says “saved earlier” instead of giving the available time; it also does so
on every other root-mode view.
Code

src/components/pwa-lifecycle.tsx[R333-334]

+  const offlineSavedAt =
+    offlineSaved && pathname !== "/" && offlineSaved.pathname === pathname ? offlineSaved.at : null;
Relevance

●● Moderate

The concern is plausible, but the PR explicitly treats root query-dependent content as
freshness-unknown; no close rejection precedent found.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The component records an online timestamp for the current pathname, but the new condition rejects it
unconditionally for /. The offline-event handler captures that timestamp, and the notice renders
the resulting value; the focused test confirms that even a root view with no intervening navigation
receives “saved earlier”.

src/components/pwa-lifecycle.tsx[326-334]
src/components/pwa-lifecycle.tsx[351-376]
src/components/pwa-lifecycle.tsx[592-598]
tests/pwa-lifecycle.dom.test.tsx[234-243]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The offline notice suppresses a known saved time on every Clinical home view, including one whose content has not changed since it was opened online.
## Fix Focus Areas
- src/components/pwa-lifecycle.tsx[326-334]
- src/components/pwa-lifecycle.tsx[351-376]
## Recommended Fix
Record the root view's mode or relevant query state alongside its path when capturing the online time. Show that time if the view is unchanged when offline, and use “saved earlier” when the content changes without a new online load.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 9 rules
✅ Skills: 4 invoked
  accessibility-review
  frontend-architecture-review
  performance-review
  code-quality-review
✅ Cross-repo context — repo relationships
✅ REVIEW.md
Review mode: Auto: 🚀 Fast: Localized CSS import and offline-loader retry changes, with contained behavioral impact.

Grey Divider

Tip of the day
💡 Did you know, you can turn these tips off under Display > Comment parts

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit d239a51

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Plan monthly usage limit reached ↗
Resets Oct 16

Get more usage

…e helper loaded, or if the home now has a search

Also adds useSearchParams to one test's navigation mock now that the offline notice reads the query.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mws6schjKQbpCQqQzPMKSL
@gitar-bot
gitar-bot Bot enabled auto-merge (squash) October 12, 2026 17:04
gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 12, 2026

@gitar-bot gitar-bot 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.

Gitar has auto-approved this PR (configure)

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 247daaa

gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 13, 2026

@gitar-bot gitar-bot 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.

Gitar has auto-approved this PR (configure)

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Cancelled. View session →

BigSimmo and others added 2 commits October 13, 2026 10:01
…ing the work clock up front

The bundle budget failed on /open-shifts, /roster/shifts and /teaching/assessments
(+~6 KiB gzip on every route from PwaLifecycle in the root layout importing
savedLine -> work-time + account-scoped-browser-state).
gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 13, 2026

@gitar-bot gitar-bot 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.

Gitar has auto-approved this PR (configure)

Comment thread src/components/pwa-lifecycle.tsx Resolved
@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit ac2ff90

…ine's helper when the signal returns

The motion styles now ride in the main stylesheet instead of a separate one on the
search-app layout. That separate sheet tipped the layout over its chunk count, so the
build copied the account code into a second chunk on every Work page. /roster/shifts
and /open-shifts are back under the 10% limit (local build: +9.7% and +9.3%).

The offline line's wording helper is tried again when the signal returns if its first
load failed, so a later offline notice can still name its time.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mws6schjKQbpCQqQzPMKSL

@gitar-bot gitar-bot 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.

Gitar has auto-approved this PR (configure)

@gitar-bot

gitar-bot Bot commented Oct 13, 2026

Copy link
Copy Markdown
Contributor
Code Review ✅ Approved 2 closed / 2 findings

🟡 Medium risk · Cold-start routing uses local history and roster state, which could send clinicians to an unintended page when either signal is stale.

Adds cold-open return to the last-used Work or Clinical page, a Clinical button on the Work rail, / and Ctrl K search focus, a ? shortcuts list, subtle tab fades, and an offline line showing when the saved page was taken. Two resolved issues: offline time no longer overstates how fresh a cached page is, and taps or keys made before the deferred LastPlace helper loads are no longer missed. No issues remain open.

✅ 2 closed
✅ Bug: Offline time can claim a cached page is fresher than it is

📄 src/components/pwa-lifecycle.tsx:323-328 📄 src/components/pwa-lifecycle.tsx:345-349 📄 src/components/pwa-lifecycle.tsx:368-370
offlineSavedAt is set only when the offline event fires, and shownOnlineAtRef updates only while navigator.onLine is true. Say the doctor opens page A online at 19:00, goes offline at 19:05, then moves to page B, which the service worker serves from yesterday's cache. The card still reads "Offline, showing what was saved at 19:00". That makes B's saved copy look fresher than it is, which contradicts the comment that the line "can understate how fresh it is but never overstate it". In a clinical app that misleads the reader about how old the data is. Fix: when the path changes while offline, set the saved time to null so the card says "saved earlier". Better still, read the cache timestamp for that page.

✅ Bug: Deferred LastPlace misses taps and keys made before its chunk loads

📄 src/components/app-helpers-deferred.tsx:10-12 📄 src/components/last-place/last-place.tsx:133-147
LastPlace is now loaded with dynamic(..., { ssr: false }), so the pointerdown/keydown listeners that end the decision are only attached after a separate chunk downloads. That can take seconds on a slow phone. bootDecision() still decides from navigation timing, so checking becomes true even when the doctor has already tapped the composer or typed on /. A search that only changed the query (/?q=…) still passes the window.location.pathname !== "/" check in finish. If the doctor then stops touching the page, the roster result or the 2.5 s timer runs router.replace and moves them off the page they were using. This breaks the documented promise that it "gives up the moment the doctor starts using the page". Fix: in bootDecision/finish, also give up when the user has already interacted (navigator.userActivation?.hasBeenActive) or when the current URL is no longer a bare /.

Verification

Rules No rules evaluated

Functional validation Not enabled

Set up

Auto-approval Approved

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Counting what did not apply, without listing it.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit d5b6320

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔴 Large blast radius size:XXL This PR changes 1000+ lines, ignoring generated files 🕐 40+ Minutes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants