Skip to content

feat(differentials): adopt the default in-page navigation template - #1715

Merged
BigSimmo merged 10 commits into
mainfrom
claude/differentials-inpage-navigation-h2u8fq
Aug 8, 2026
Merged

feat(differentials): adopt the default in-page navigation template#1715
BigSimmo merged 10 commits into
mainfrom
claude/differentials-inpage-navigation-h2u8fq

Conversation

@BigSimmo

@BigSimmoBigSimmo commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Migrates Differential detail to the default in-page navigation template that PR docs: default in-page navigation to DocumentViewer chrome #1688 codified in docs/search-chrome-behaviour.md. That PR explicitly left this page behind as a legacy special case ("Existing simpler collapse headers (for example Differential detail) remain special cases"); this closes that gap and makes the page the template's second adopter after DocumentViewer.
  • The page previously owned the phone collapse slot while putting almost nothing in it — a back chevron on the left, a + on the right, and empty space between. The real navigation was a separate in-flow tab strip that scrolled away with the content and clipped "Source" off the right edge at phone width. The header now carries all four template slots: back control, page title with the active section on line two behind a chevron disclosure, ellipsis page actions, and a weighted segment track pinned to the bottom edge.
  • Adds src/components/differentials/detail-section-index.ts, which shapes the five tabs as DocumentSections so the existing DocumentSectionTrack and DocumentSectionList render them unchanged rather than growing a parallel implementation. Segment weights derive from real panel content — clinical-review section count, related-diagnosis count, overlap links — and are normalised, so the track reads as proportion rather than as "which of five". The Source segment is deliberately the smallest on every record because it is a governance footer, not a body of content.
  • Keeps the labelled Overview/Compare/Map/Related/Source strip from sm up, and hides it below. Phones navigate from the header disclosure and its sheet, which is one affordance per breakpoint and leaves nothing to clip at 320px.
  • Deliberately uses no scroll spy. These are discrete tab panels rather than scroll positions, so the active section is simply the active tab and useDocumentSectionSpy is not involved.
  • Both sheets are rendered as siblings of PhoneHeaderCollapsePortal, never as children, so they are not carried away when the shared chrome scroll-hides. DocumentSectionSheet is intentionally not reused because it hard-requires the document-only compact/density toggle; the section sheet composes the shared Sheet around DocumentSectionList instead.
  • Moves the header from max-sm:static to relative, matching DocumentViewer. This is load-bearing rather than cosmetic: the segment track is absolutely positioned against the header, and a static phone header would let it escape to whichever ancestor happens to be positioned.
  • Names the tab panel with aria-label instead of aria-labelledby. Below sm the strip is display:none, and assistive technology ignores a hidden labelling element, which would have left the panel unnamed on phones.
  • Moves "New differentials search" out of the bare + and into the actions sheet, alongside Save, Copy after review, and Compare.
  • Not in scope, and unchanged: the DSM differentials page, the presentation/compare workflow page, and MobilePrimaryActions. That last one is a content call-to-action rather than navigation chrome, and removing it would drop the prominent "Compare (n)" button.

Verification

  • npm run verify:pr-local — reaches the full unit suite and stops only at tests/pr-handoff-stop.test.ts, a pre-existing failure unrelated to this change. Confirmed by stashing the whole diff and re-running on the clean base, where it fails identically; it is also already recorded as pre-existing in docs/branch-review-ledger.md (PR refactor(navigation): remove the vestigial one-button mode strip #1679 row). Everything else is green: Test Files 1 failed | 522 passed (523), Tests 1 failed | 5557 passed | 4 skipped (5562).
  • npm run verify:phone-chrome — the gate AGENTS.md names for phone-chrome changes. check:installed-lock-parity PASS (playwright 1.62.1 parity), check:runtime PASS, static/unit contracts 119 passed (9 files), changed-browser tests/ui-tools.spec.ts passed, focused-browser 7 passed (26.1s). Its smart selector reported "Focused ownership and journey coverage is sufficient for this page-local scope" and did not escalate to the full Chromium gate.
  • npx tsc --noEmit — exit 0, no output.
  • npm run lint — clean at --max-warnings 0.
  • Focused browser proof of the changed journey: tests/ui-tools.spec.ts --grep "diagnosis detail actions stay tappable"1 passed.
  • New unit coverage: tests/differential-section-nav.dom.test.tsx9 passed; combined with the updated contract test, 40 passed (2 files) re-run after npm run format.

UI verification beyond the above: manual browser proof against the running dev server at 320px, 390px and 768px. Zero horizontal overflow at all three widths. The section sheet opens from the header disclosure, selecting Map sets ?tab=map and updates the header subtitle, the actions sheet opens, and Escape restores focus to its trigger. The phone collapse contract was checked side by side against the reference implementation: after real wheel scrolling, both /differentials/diagnoses/delirium and the document viewer report data-scroll-hidden="true" with the collapse stack at bottom: 0, and the differentials header sits inside universal-header-collapse, so a single owner still moves both. No second scroll-hide hook was added.

npm run verify:release not run: not a release or handoff-confidence claim. Retrieval, ranking, answer-generation and production-readiness gates not run: none of those surfaces are touched by this diff.

Risk and rollout

  • Risk: Low–moderate, and confined to one route's chrome. This is presentation and navigation only — no clinical content, retrieval, ranking, answer generation, source governance, privacy, auth or data access is touched, and no route is added or removed. The ?tab= query-param sync and the static-generation-safe read-on-mount are unchanged, so deep links such as ?tab=map from the presentation workflow page keep working. The main regression surface is phone chrome, which is why verify:phone-chrome and the side-by-side collapse comparison are the primary evidence.
  • Rollback: Revert the single commit. The new module is additive and has no other consumers.
  • Provider or production effects: None. No OpenAI, Supabase, hosted CI or deployment call was made at any point.

Notes

  • One generated-manifest change worth a reviewer's attention. The regenerated docs/design-system/adoption-manifest.json drops tests/ui-tools.spec.ts from the design-system Tabs component's testFiles. This is not lost coverage. scripts/generate-design-system-adoption.mjs associates tests with components by matching \bTabs\b against file text, and the only match in that spec was a capital-T word in a comment (// Tabs: no page overflow …) that this change rewrote. The differentials strip is a local function Tabs inside the page and never imports @/components/ui/tabs, so the association was coincidental and the manifest is now more accurate. Tabs retains its two genuine proofs. docs/design-system/COMPONENTS.md moves Sheet usage from 20 to 21, reflecting the new section sheet.
  • docs/codebase-index.md was not edited. Nothing in it describes the differentials header at a granularity this change alters, so there was no accurate line to update.
  • The tests/mode-nav-addon-slot.dom.test.tsx enumeration guard, which hard-codes the set of components allowed to claim the phone collapse slot, passes unchanged: the page already claimed the slot and still does.
  • Environment note for anyone reproducing the browser gates locally: this container ships Chromium build 1194 against Playwright 1.62.1's expected 1234, so the browser stages need PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/opt/pw-browsers/chromium. That is a container gap, not a product signal.

Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added responsive in-page navigation for differential detail sections.
    • Added mobile sheets for section selection and diagnosis actions.
    • Added actions to compare, copy, save or remove, and start a new search.
    • Improved section metadata, active-section context, and accessible tab labeling.
  • Documentation

    • Updated design-system adoption records and review documentation.
  • Tests

    • Expanded coverage for navigation ordering, responsive layouts, accessibility, and header behavior.

PR #1688 codified the DocumentViewer header as the default in-page
navigation template for every mode page, but deliberately left
Differential detail as a legacy special case. This migrates it.
The detail page owned the phone collapse slot and put almost nothing in
it: a back chevron on the left, a `+` on the right, and empty space
between. The real navigation was a separate in-flow tab strip that
scrolled away with the content and clipped "Source" off the right edge
at phone width.
The header now carries the four template slots: back control, title with
the active section on line two behind a chevron disclosure, ellipsis page
actions, and a weighted segment track pinned to the bottom edge. The
labelled strip is retained from `sm` up; phones navigate from the header
disclosure and its sheet, so there is nothing left to clip at 320px.
- New `detail-section-index.ts` builds the five tabs as `DocumentSection`s
so `DocumentSectionTrack` and `DocumentSectionList` render them
unchanged. Weights derive from real panel content — review-section
count, related count, overlap links — normalised so the track reads as
proportion rather than "which of five".
- No scroll spy: these are discrete panels, not scroll positions, so the
active id is just the active tab.
- Both sheets are siblings of `PhoneHeaderCollapsePortal`, never children,
so they are not carried away when the shared chrome scroll-hides.
- The header moves from `max-sm:static` to `relative`, matching
DocumentViewer. The track is absolutely positioned against the header,
and a static phone header would let it escape to another ancestor.
- The tab panel is now named by `aria-label` rather than `aria-labelledby`:
below `sm` the strip is `display:none`, and assistive tech ignores a
hidden labelling element.
- "New differentials search" moves from the bare `+` into the actions
sheet, alongside Save, Copy and Compare.
The regenerated adoption manifest drops `tests/ui-tools.spec.ts` from the
design-system `Tabs` component's `testFiles`. That association came from a
capital-T word in a comment this change rewrote; the differentials strip is
a local `function Tabs`, not the design-system component, so the manifest
is now more accurate rather than less.
Verification: typecheck clean; lint clean at --max-warnings 0; unit suite
5556 passed with the one pre-existing pr-handoff-stop failure confirmed by
stashed re-run on the clean base; verify:phone-chrome green through
lock-parity, runtime, 119 contract tests, changed-browser ui-tools and
focused-browser 7 passed; live browser proof shows zero horizontal overflow
at 320/390/768px and the same collapse behaviour as DocumentViewer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VnXJpp8BpZSYychgi18EnN
@supabase

supabaseBot commented Aug 8, 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 ↗︎.

@coderabbitai

coderabbitaiBot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in:44 minutes

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d1d10b1c-2706-4997-97fb-51741c6ec88e

📥 Commits

Reviewing files that changed from the base of the PR and between 1a9b6ac and 21a47a1.

📒 Files selected for processing (4)
  • docs/branch-review-ledger.md
  • src/components/differentials/detail-section-index.ts
  • src/components/differentials/differential-detail-page.tsx
  • tests/differential-section-nav.dom.test.tsx
📝 Walkthrough

Walkthrough

The differential detail page now uses a five-section index, responsive phone sheets, desktop tabs, diagnosis actions, and updated accessibility behavior. Tests cover section metadata, navigation, header contracts, and responsive URL state. Design-system adoption records and review ledger entries were updated.

Changes

Differential detail navigation

Layer / File(s)Summary
Section index contract
src/components/differentials/detail-section-index.ts
Adds five fixed differential sections with content-based weights, labels, icons, source-status details, and non-collapsible metadata.
Responsive page integration
src/components/differentials/differential-detail-page.tsx
Adds section tracking, phone navigation and action sheets, desktop tabs, diagnosis actions, active-section state, and accessible panel labels.
Navigation validation and adoption
tests/differential-section-nav.dom.test.tsx, tests/header-scroll-hide-contract.test.ts, tests/ui-tools.spec.ts, docs/design-system/adoption-manifest.json, docs/design-system/COMPONENTS.md, docs/branch-review-ledger.md
Adds coverage for indexing, weighted rendering, responsive navigation, header contracts, and URL state. Updates Sheet adoption records and review records.

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

Sequence Diagram(s)

sequenceDiagram
participant User
participant DifferentialDetailPage
participant SectionIndex
participant NavigationSheet
User->>DifferentialDetailPage: Open differential detail page
DifferentialDetailPage->>SectionIndex: Build section metadata
SectionIndex-->>DifferentialDetailPage: Return ordered sections and weights
User->>DifferentialDetailPage: Open phone section navigation
DifferentialDetailPage->>NavigationSheet: Render section choices
NavigationSheet-->>DifferentialDetailPage: Return selected section
DifferentialDetailPage-->>User: Update active panel and tab URL
Loading

Possibly related PRs

Suggested labels:codex

Suggested reviewers:claude

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 25.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly identifies the main change: adopting the default in-page navigation template for differentials.
Description check✅ PassedThe description covers the change, verification results, risks, rollback, production effects, scope exclusions, and conditional gate decisions.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/differentials-inpage-navigation-h2u8fq

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

@BigSimmo

Copy link
Copy Markdown
OwnerAuthor

@cursoragent Work the current open PR end-to-end. Confirm the PR number and GitHub head first from context. If more than one open PR could apply, stop and say which one you would use and why.

Fetch and start from the remote tip that matches that GitHub head. If the named branch ref is missing or stale, use the PR head ref. Preserve unrelated local WIP, including any local-only ledger commits; do not discard dirty work, and do not treat a local-ahead commit as the reviewed tip. Do not merge the PR, force-push, rebase, or arm auto-merge unless I explicitly ask. No provider-backed gates without separate approval. If you cannot push or resolve threads, diagnose and comment only; if inline replies fail, resolve when possible and put dispositions in the summary comment. If auto-merge is already armed, push only for a real blocker, and avoid pushes that would cancel in-flight required CI unless the push itself clears that blocker.

If the PR is already merged or closed: confirm the head and merge commit, note required-CI outcome, post one summary, and stop.

Goal: deep review plus Bugbot, fix actionable issues with the smallest correct changes, clear merge / required-CI / thread blockers, run strong local offline verification, push fixes, append the review ledger, and post one PR summary. Prefer thoroughness over speed. Regenerate large assets only when a fix requires it; then run the asset check and keep compatibility aliases byte-identical where the repo uses them.

Snapshot the GitHub head SHA: tip, base, behind/ahead, mergeable state, merge-tree versus origin/main (real conflict versus behind-but-clean), required checks on that tip including Production UI when selected, advisory separately, unresolved actionable threads. Missing checks while dirty are not green. If the tip moves mid-work, re-snapshot and continue from the new head.

Ledger-lookup against that GitHub head under the heavy review-and-fix scope for this PR. Already reviewed at this head with clean merge-tree, green required checks, and no new actionable threads → summarize, comment, stop unless I asked for a fresh superseding pass. Follow the repo review protocol.

Unblock once: real conflict → merge origin/main (prefer main’s shared queues; keep this PR’s notes); behind-but-clean → one sync, late if required CI is in flight; clean → leave. Labels like skip-branch-sync do not block a manual sync needed to clear a real blocker. No sync thrash. After any sync or push, re-snapshot tip, merge-tree, and required checks before declaring done. Dedupe the ledger if a merge touched it.

Review high-confidence delta risks only. Separate PR-introduced defects from pre-existing re-emitted debt. For generated assets, review contracts, aliases, cache, and manifests—not every generated line. If protected RAG or ranking surfaces are touched, say so before editing; fix PR-body policy text only when wrong or missing. Ignore bot noise. No nit spam or broad rewrites. Escalate verification by touched risk: clinical / RAG / privacy / migrations / auth → domain check plus production-readiness when warranted; UI / phone-chrome / routing / styling → ensure plus phone-chrome or UI gates when warranted; generated assets or docs inventory/links → asset or docs checks when warranted.

Fix P0/P1 always; clear scoped P2 when locally provable; else disposition and resolve. Required-check failures on this tip only; ignore advisory. Prefer reverting a bad autofix commit. After fixes: format and commit before push; smallest targeted proof; repo cheap gate; repo PR-local gate. No release, lighthouse, live eval, or live provider gates without approval.

Push only this PR’s fix commits. Append ledger for the final GitHub head under the heavy scope. Never push a ledger-only tip—include ledger in a real fix push, or leave a no-change ledger append local and unpushed.

One PR comment: tip, sync/merge-tree, fixed versus dispositioned, threads, required CI, decisive local gate lines, residual risks; merge left to me. Inline only for remaining human-needed P0/P1.

Stop when merge-tree is clean on the current GitHub tip, actionable threads are clear, required checks are green or clearly in progress, heavy gates for scope passed, summary posted, merge left to me.

@cursor

cursorBot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

PR #1715 — end-to-end pass complete

PR:#1715feat(differentials): adopt the default in-page navigation template
Branch:claude/differentials-inpage-navigation-h2u8fq
Tip now:9f4f6efa (merge sync f0b27ec8 + ledger append)

Blocker cleared

GitHub reported CONFLICTING / DIRTY because docs/branch-review-ledger.md conflicted with main (both sides had appended rows). I merged origin/main once; git's merge=ledger driver resolved it cleanly. No product-code conflicts.

  • Before:da90be01, 4 commits behind main, PR mergeability FAILURE, no pull_request CI
  • After: merge-tree clean, GitHub MERGEABLE, CI re-triggered on push

Review

Ledger lookup at da90be01 was NOT REVIEWED; reviewed the full delta and found no P0/P1 issues. Zero unresolved review threads. No RAG/ranking surfaces touched.

Verification (on f0b27ec8)

verify:phone-chrome — contracts 119 passed (9 files); focused-browser 7 passed (19.4s)
verify:pr-local — Test Files 523 passed (523)
Tests 5547 passed | 4 skipped (5551)

Lint, typecheck, format, build, and RAG fixtures all green.

Pushed commits

  1. f0b27ec8merge origin/main into claude/differentials-inpage-navigation-h2u8fq
  2. 9f4f6efa — ledger record for the heavy review-and-fix scope

A summary comment is on the PR. Required CI was in progress on the new tip when I finished (Change scope, Gitleaks, Semgrep, PR policy, PR mergeability queued/in progress) — not assumed green yet. Merge is left to you.

Open in WebOpen in Cursor

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

@chatgpt-codex-connectorchatgpt-codex-connectorBot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:c67c4927d8

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment threadsrc/components/differentials/detail-section-index.ts Outdated
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
@cursor

cursorBot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Cursor Cloud review-and-fix summary (PR #1715)

PR:#1715feat(differentials): adopt the default in-page navigation template
Branch:claude/differentials-inpage-navigation-h2u8fq
Tip (post-fix):9f4f6efa (merge sync f0b27ec8 + ledger 9f4f6efa)
Base:main (383fe910 at sync time)

Snapshot (before → after)

ItemBefore (da90be01)After (9f4f6efa)
Merge-tree vs origin/mainClean locally, but 4 commits behindClean after one origin/main merge
GitHub mergeableCONFLICTING / DIRTYMERGEABLE (CI re-triggered on push)
Required blockerPR mergeability FAILURE — real ledger conflict blocked refs/pull/1715/mergeConflict cleared; pull_request CI now running
Review threads0 unresolved0 unresolved
Ledger lookup (heavy scope)NOT REVIEWED at da90be01Appended at f0b27ec8

Blocker fixed

  • Real merge conflict in docs/branch-review-ledger.md only (both sides appended rows). Merged origin/main once (f0b27ec8); git's merge=ledger driver auto-merged cleanly. No product-code conflict.

Review findings (delta)

No P0/P1 defects found in the PR delta. Spot-check of high-risk areas:

  • Phone collapse ownership preserved (PhoneHeaderCollapsePortal); sheets are siblings, not portal children.
  • Header relative positioning is load-bearing for the absolutely-positioned segment track.
  • aria-label on tabpanel (not aria-labelledby) is correct because the sm+ strip is display:none on phones.
  • DocumentSectionTrack is decorative (aria-hidden) — matches DocumentViewer; navigation via header sheet + sm+ strip.
  • No RAG/ranking/clinical-generation surfaces touched.

Pre-existing / out of scope: CodeRabbit rate-limited; no actionable human or Bugbot threads on this tip.

Local verification (offline, on f0b27ec8)

verify:phone-chrome — lock-parity PASS; runtime PASS; contracts 119 passed (9 files);
changed-browser ui-tools passed; focused-browser 7 passed (19.4s)
verify:pr-local — Test Files 523 passed (523)
Tests 5547 passed | 4 skipped (5551)
(+ lint, typecheck, format, build, client-bundle scan, RAG fixtures green)

Not run: verify:release, live eval, provider-backed gates (not requested).

Residual risks

  • Low–moderate, confined to /differentials/diagnoses/[slug] chrome. Deep links via ?tab= unchanged.
  • Hosted Production UI and full pr-required aggregate were in progress at comment time on the new tip — not assumed green yet.
  • Tip may show briefly behindmain until the next base advance; merge-tree was clean immediately post-sync.

Merge left to you. No auto-merge armed by this pass.

@BigSimmo

Copy link
Copy Markdown
OwnerAuthor

@copilot resolve the merge conflicts on this branch.

…inpage-navigation-h2u8fq
# Conflicts:
#	docs/branch-review-ledger.md
Co-authored-by: BigSimmo <87357024+BigSimmo@users.noreply.github.com>

CopilotAI commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts on this branch.

Merge conflicts resolved. There was one real conflict in docs/branch-review-ledger.md — two sets of new rows added on both sides at the same table positions. Resolved using the union strategy (kept all rows from both sides in chronological order), finalised the merge commit, and confirmed git merge-tree returns a clean single-SHA tree with no conflict output. Branch is now ahead of origin/main with a clean merge state.

@coderabbitaicoderabbitaiBot 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: 1

🧹 Nitpick comments (4)
tests/header-scroll-hide-contract.test.ts (1)

368-384: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Match structure, not exact JSX formatting.

Lines 368 and 382-384 assert exact source literals. The formatter controls both. Adding one utility class to the nav pushes the className past the print width, and Prettier then splits the attribute across lines. The assertion fails although the behaviour is unchanged. The same applies to the single-line <DocumentSectionTrack ... /> call.

Assert the individual tokens instead.

♻️ Proposed change
- expect(differentialDetailSource).toContain("<DocumentSectionTrack sections={sections} activeId={activeTab} />");+ expect(differentialDetailSource).toMatch(/<DocumentSectionTrack\b[\s\S]*?activeId=\{activeTab\}/);
expect(differentialDetailSource).toContain("<DocumentSectionList");
@@
- expect(differentialDetailSource).toContain(- 'className="hidden border-b border-[color:var(--border)] text-sm font-bold text-[color:var(--text-muted)] sm:flex"',- );+ const tabStripClasses = /role="tablist"[\s\S]{0,400}?className="([^"]+)"/.exec(differentialDetailSource)?.[1] ?? "";+ expect(tabStripClasses.split(/\s+/)).toEqual(expect.arrayContaining(["hidden", "sm:flex"]));
🤖 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 `@tests/header-scroll-hide-contract.test.ts` around lines 368 - 384, Update the
source-structure assertions in the header scroll contract test to match JSX
semantics rather than exact formatting: replace the single-line
DocumentSectionTrack and labelled-strip className string checks with assertions
for their individual required tokens, while preserving the existing portal
sibling and Sheet/DocumentSectionList checks.
src/components/differentials/detail-section-index.ts (1)

74-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared "expandable section" predicate.

counts.reviewSections repeats the exact filter used by expandableSectionIds in src/components/differentials/differential-detail-page.tsx (lines 1086-1090). The comment states the two must match. A change to one site will silently desynchronise the Overview segment weight and the N sections detail from the rendered panel.

Export one helper from src/lib/differential-detail.ts and call it from both places.

♻️ Suggested shape
// src/lib/differential-detail.tsexportfunctionexpandableSectionIds(record: DifferentialRecord): string[]{returnrecord.sections.filter((section)=>visibleSectionItems(section,record).length>0).map((s)=>s.id);}
- reviewSections: record.sections.filter((section) => visibleSectionItems(section, record).length > 0).length,+ reviewSections: expandableSectionIds(record).length,
🤖 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/differentials/detail-section-index.ts` around lines 74 - 80,
Extract the shared expandable-section logic into an exported
expandableSectionIds helper in differential-detail.ts, using visibleSectionItems
to filter sections with items and returning their IDs. Update the
counts.reviewSections calculation in the detail section and the existing
expandableSectionIds usage in differential-detail-page.tsx to call this helper,
keeping both the Overview count and rendered panel synchronized.
tests/ui-tools.spec.ts (1)

2062-2078: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add phone coverage for the actions sheet.

This block covers the section disclosure well. The PR also moves "New differentials search" from the header row into the ellipsis actions sheet, and that path has no browser coverage at 320px. A regression that hides or mis-sizes differential-actions-trigger would pass this gate.

Add a short assertion for the actions trigger and sheet.

💚 Suggested addition after line 2078
 await expect(page).toHaveURL(/[?&]tab=map/);
++ const actionsTrigger = page.getByTestId("differential-actions-trigger");+ await expect(actionsTrigger).toBeVisible();+ await expectMinTouchTarget(actionsTrigger);+ await actionsTrigger.click();+ const actionsSheet = page.getByTestId("differential-actions-sheet");+ await expect(actionsSheet).toBeVisible();+ await expect(actionsSheet.getByRole("link", { name: "New differentials search" })).toBeVisible();+ await page.keyboard.press("Escape");+ await expect(actionsSheet).toBeHidden();
As per path instructions: "Use Playwright for end-to-end tests and run the appropriate Chromium UI gate, starting the project with npm run ensure rather than assuming a port."
🤖 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 `@tests/ui-tools.spec.ts` around lines 2062 - 2078, Extend the 320px viewport
test after the existing section-sheet assertions to cover the differential
actions flow: assert differential-actions-trigger is visible and has the minimum
touch target, click it, and assert the actions sheet becomes visible. Use the
existing page/test-id locators and Playwright assertions without changing the
section disclosure coverage.

Source: Path instructions

src/components/differentials/differential-detail-page.tsx (1)

1261-1267: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use sectionMeta as the single label source

detailTabs and sectionMeta currently use the same labels. Derive tab labels from sectionMeta to prevent future drift.

🤖 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/differentials/differential-detail-page.tsx` around lines 1261
- 1267, Update the tab-label construction in the differential detail page to
derive labels from sectionMeta rather than duplicating label values in
detailTabs. Keep sectionMeta as the single source of truth and preserve the
existing activeSection aria-label fallback behavior.
🤖 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 `@tests/differential-section-nav.dom.test.tsx`:
- Around line 30-46: Update buildContext so ...overrides is merged before
reconstructing source, then spread the default source values with
overrides.source last. Preserve all default source fields when callers provide
partial source overrides, while allowing complete source values to replace them.
---
Nitpick comments:
In `@src/components/differentials/detail-section-index.ts`:
- Around line 74-80: Extract the shared expandable-section logic into an
exported expandableSectionIds helper in differential-detail.ts, using
visibleSectionItems to filter sections with items and returning their IDs.
Update the counts.reviewSections calculation in the detail section and the
existing expandableSectionIds usage in differential-detail-page.tsx to call this
helper, keeping both the Overview count and rendered panel synchronized.
In `@src/components/differentials/differential-detail-page.tsx`:
- Around line 1261-1267: Update the tab-label construction in the differential
detail page to derive labels from sectionMeta rather than duplicating label
values in detailTabs. Keep sectionMeta as the single source of truth and
preserve the existing activeSection aria-label fallback behavior.
In `@tests/header-scroll-hide-contract.test.ts`:
- Around line 368-384: Update the source-structure assertions in the header
scroll contract test to match JSX semantics rather than exact formatting:
replace the single-line DocumentSectionTrack and labelled-strip className string
checks with assertions for their individual required tokens, while preserving
the existing portal sibling and Sheet/DocumentSectionList checks.
In `@tests/ui-tools.spec.ts`:
- Around line 2062-2078: Extend the 320px viewport test after the existing
section-sheet assertions to cover the differential actions flow: assert
differential-actions-trigger is visible and has the minimum touch target, click
it, and assert the actions sheet becomes visible. Use the existing page/test-id
locators and Playwright assertions without changing the section disclosure
coverage.
🪄 Autofix

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

Run ID: 4bd152d4-3ae7-4672-b717-dbce79ad5b22

📥 Commits

Reviewing files that changed from the base of the PR and between 2675e6e and 1a9b6ac.

📒 Files selected for processing (8)
  • docs/branch-review-ledger.md
  • docs/design-system/COMPONENTS.md
  • docs/design-system/adoption-manifest.json
  • src/components/differentials/detail-section-index.ts
  • src/components/differentials/differential-detail-page.tsx
  • tests/differential-section-nav.dom.test.tsx
  • tests/header-scroll-hide-contract.test.ts
  • tests/ui-tools.spec.ts

Comment threadtests/differential-section-nav.dom.test.tsx Outdated
@BigSimmo
BigSimmo enabled auto-merge (squash) August 8, 2026 06:23
cursoragentand others added 4 commits August 8, 2026 06:28
Pass live sourceStatus into buildDifferentialSectionIndex so the
in-page nav Source row matches FooterStatus when owner governance
differs from the bundled snapshot. Fix test buildContext merge order
so partial source overrides keep required metadata fields.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Resolve the sole merge conflict in docs/branch-review-ledger.md via the
merge=ledger driver (append-only union). Other incoming changes from main
(lighthouse budget pin, specifiers breadcrumb removal) merge cleanly with
no product overlap.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
…gation-h2u8fq' into claude/differentials-inpage-navigation-h2u8fq
@github-actions

Copy link
Copy Markdown
Contributor

CI triage

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

  • Static PR checksneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • Lighthouse budget (advisory)needs 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 #9022 (cancelled).

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

@BigSimmo

Copy link
Copy Markdown
OwnerAuthor

@cursoragent Work the current open PR end-to-end. Confirm the PR number and GitHub head first from context. If more than one open PR could apply, stop and say which one you would use and why.

Fetch and start from the remote tip that matches that GitHub head. If the named branch ref is missing or stale, use the PR head ref. Preserve unrelated local WIP, including any local-only ledger commits; do not discard dirty work, and do not treat a local-ahead commit as the reviewed tip. Do not merge the PR, force-push, rebase, or arm auto-merge unless I explicitly ask. No provider-backed gates without separate approval. If you cannot push or resolve threads, diagnose and comment only; if inline replies fail, resolve when possible and put dispositions in the summary comment. If auto-merge is already armed, push only for a real blocker, and avoid pushes that would cancel in-flight required CI unless the push itself clears that blocker.

If the PR is already merged or closed: confirm the head and merge commit, note required-CI outcome, post one summary, and stop.

Goal: deep review plus Bugbot, fix actionable issues with the smallest correct changes, clear merge / required-CI / thread blockers, run strong local offline verification, push fixes, append the review ledger, and post one PR summary. Prefer thoroughness over speed. Regenerate large assets only when a fix requires it; then run the asset check and keep compatibility aliases byte-identical where the repo uses them.

Snapshot the GitHub head SHA: tip, base, behind/ahead, mergeable state, merge-tree versus origin/main (real conflict versus behind-but-clean), required checks on that tip including Production UI when selected, advisory separately, unresolved actionable threads. Missing checks while dirty are not green. If the tip moves mid-work, re-snapshot and continue from the new head.

Ledger-lookup against that GitHub head under the heavy review-and-fix scope for this PR. Already reviewed at this head with clean merge-tree, green required checks, and no new actionable threads → summarize, comment, stop unless I asked for a fresh superseding pass. Follow the repo review protocol.

Unblock once: real conflict → merge origin/main (prefer main’s shared queues; keep this PR’s notes); behind-but-clean → one sync, late if required CI is in flight; clean → leave. Labels like skip-branch-sync do not block a manual sync needed to clear a real blocker. No sync thrash. After any sync or push, re-snapshot tip, merge-tree, and required checks before declaring done. Dedupe the ledger if a merge touched it.

Review high-confidence delta risks only. Separate PR-introduced defects from pre-existing re-emitted debt. For generated assets, review contracts, aliases, cache, and manifests—not every generated line. If protected RAG or ranking surfaces are touched, say so before editing; fix PR-body policy text only when wrong or missing. Ignore bot noise. No nit spam or broad rewrites. Escalate verification by touched risk: clinical / RAG / privacy / migrations / auth → domain check plus production-readiness when warranted; UI / phone-chrome / routing / styling → ensure plus phone-chrome or UI gates when warranted; generated assets or docs inventory/links → asset or docs checks when warranted.

Fix P0/P1 always; clear scoped P2 when locally provable; else disposition and resolve. Required-check failures on this tip only; ignore advisory. Prefer reverting a bad autofix commit. After fixes: format and commit before push; smallest targeted proof; repo cheap gate; repo PR-local gate. No release, lighthouse, live eval, or live provider gates without approval.

Push only this PR’s fix commits. Append ledger for the final GitHub head under the heavy scope. Never push a ledger-only tip—include ledger in a real fix push, or leave a no-change ledger append local and unpushed.

One PR comment: tip, sync/merge-tree, fixed versus dispositioned, threads, required CI, decisive local gate lines, residual risks; merge left to me. Inline only for remaining human-needed P0/P1.

Stop when merge-tree is clean on the current GitHub tip, actionable threads are clear, required checks are green or clearly in progress, heavy gates for scope passed, summary posted, merge left to me.

@cursor

cursorBot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

❌ Unable to add follow-up after multiple attempts. The agent may be experiencing issues.

Please try again later or Open in Web to view the status.

Open in WebOpen in Cursor

Learn more about Cursor Agents

The live-governance fix passes `{ source: { sourceStatus } }` into the test
helper, but `Partial<DifferentialDetailContext>` only makes `source` optional
as a whole — once supplied it still demands every field, so the three call
sites failed typecheck and took Static PR checks / PR required red with them.
Type the override one level deeper so a partial `source` is actually legal,
which is what the helper's own rebuild-the-object logic already assumed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VnXJpp8BpZSYychgi18EnN
@BigSimmo
BigSimmo merged commit d136991 into mainAug 8, 2026
24 of 25 checks passed
@BigSimmo
BigSimmo deleted the claude/differentials-inpage-navigation-h2u8fq branch August 8, 2026 07:15
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@BigSimmo@claude@cursoragent