From 45fa3c6c74cff023adba08729dc52868fbd3c516 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 18 Jul 2026 03:06:08 +0800 Subject: [PATCH 1/5] chore: merge design-audit remediation changes (cherry picked from commit 51278a70d3c77c6266679a9f4e95058ea43678d2) --- playwright.config.ts | 1 + scripts/generate-site-map.ts | 5 +++++ src/app/page.tsx | 3 --- tests/site-map.test.ts | 34 ++++++++++++++++++++++++++++++++++ tests/ui-accessibility.spec.ts | 2 +- tests/ui-smoke.spec.ts | 4 ++-- 6 files changed, 43 insertions(+), 6 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 25407cfd5..f3b7bba18 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -56,6 +56,7 @@ export default defineConfig({ grepInvert: mockupTag, use: { ...devices["Desktop Chrome"], + reducedMotion: "no-preference", ...(chromiumExecutablePath ? { launchOptions: { executablePath: chromiumExecutablePath } } : {}), }, }, diff --git a/scripts/generate-site-map.ts b/scripts/generate-site-map.ts index 0ee3e07ac..2be4244f7 100644 --- a/scripts/generate-site-map.ts +++ b/scripts/generate-site-map.ts @@ -96,6 +96,11 @@ const publicRouteHandlerDescriptions: Record = { "/icons/[variant]": "Dynamically generated application icon handler.", }; +const publicRouteHandlerDescriptions: Record = { + "/auth/callback": "Authentication callback handler.", + "/icons/[variant]": "Dynamically generated application icon handler.", +}; + const apiDescriptions: Record = { "/api/answer": "Generate answer response.", "/api/answer/stream": "Streaming answer response.", diff --git a/src/app/page.tsx b/src/app/page.tsx index 5dc55d31b..6ce30c137 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,9 +7,6 @@ import { appModeHomeHref, isAppModeId, isAppModeVisible, type AppModeId } from " type HomeProps = { searchParams?: Promise<{ mode?: string | string[]; - q?: string | string[]; - focus?: string | string[]; - run?: string | string[]; }>; }; diff --git a/tests/site-map.test.ts b/tests/site-map.test.ts index d8c787cfc..ee6cbc957 100644 --- a/tests/site-map.test.ts +++ b/tests/site-map.test.ts @@ -97,6 +97,40 @@ describe("tracked sitemap", () => { } }); + it("keeps public redirect handlers in product routes and API handlers in the API section", () => { + const data = collectSiteMapData(); + const productSection = siteMap.slice( + siteMap.indexOf("## Main product routes"), + siteMap.indexOf("## Mode/query routes"), + ); + const apiSection = siteMap.slice(siteMap.indexOf("## API routes"), siteMap.indexOf("## Redirects")); + const expectedProductHandlers = [ + ["/applications", "src/app/applications/route.ts", "/tools"], + [ + "/differentials/presentations", + "src/app/differentials/presentations/route.ts", + "/differentials/presentations/[workflow-slug]", + ], + ["/medications", "src/app/medications/route.ts", "/?mode=prescribing"], + ] as const; + + expect(data.apiRoutes.every((route) => route.route === "/api" || route.route.startsWith("/api/"))).toBe(true); + expect(data.publicRouteHandlers.some((route) => route.route === "/auth/callback")).toBe(true); + expect(data.publicRouteHandlers).toContainEqual({ + route: "/icons/[variant]", + file: "src/app/icons/[variant]/route.tsx", + }); + expect(apiSection).not.toContain("`/icons/[variant]`"); + + for (const [route, file, target] of expectedProductHandlers) { + expect(data.publicRouteHandlers).toContainEqual({ route, file }); + expect(data.apiRoutes).not.toContainEqual({ route, file }); + expect(data.redirects).toContainEqual({ route, file, target }); + expect(productSection).toContain(`\`${route}\``); + expect(apiSection).not.toContain(`\`${route}\``); + } + }); + it("documents seeded dynamic slugs", () => { for (const service of serviceRecords) expectDocumentedRoute(service.slug); for (const form of formRecords) expectDocumentedRoute(form.slug); diff --git a/tests/ui-accessibility.spec.ts b/tests/ui-accessibility.spec.ts index e18ffd1c1..6be58fad3 100644 --- a/tests/ui-accessibility.spec.ts +++ b/tests/ui-accessibility.spec.ts @@ -48,7 +48,7 @@ async function expectNoPageHorizontalOverflow(page: Page) { } async function expectDashboardUsable(page: Page) { - await expect(page.getByRole("heading", { level: 1, name: "Clinical Guide" })).toHaveCount(1); + await expect(page.getByRole("heading", { level: 1, name: "Clinical KB" })).toHaveCount(1); await expect(page.getByRole("heading", { name: "Answer" })).toBeVisible(); await expect(page.locator('[aria-label^="Search indexed guidelines by question or keyword"]:visible')).toBeVisible(); await expect(page.getByRole("button", { name: "Open answer options" })).toBeVisible(); diff --git a/tests/ui-smoke.spec.ts b/tests/ui-smoke.spec.ts index f84687920..21cee4322 100644 --- a/tests/ui-smoke.spec.ts +++ b/tests/ui-smoke.spec.ts @@ -873,7 +873,7 @@ test.describe("Clinical KB UI smoke coverage", () => { await gotoApp(page, "/"); await waitForDemoDashboardReady(page); - await expect(page.getByRole("heading", { level: 1, name: "Clinical Guide" })).toHaveCount(1); + await expect(page.getByRole("heading", { level: 1, name: "Clinical KB" })).toHaveCount(1); await expect(page.getByRole("heading", { name: "Answer" })).toBeVisible(); await expect(visibleQuestionInput(page)).toBeVisible(); await expect(page.getByRole("button", { name: "Generate source-backed answer" })).toHaveText(/^\s*Ask\s*$/); @@ -1268,7 +1268,7 @@ test.describe("Clinical KB UI smoke coverage", () => { await expect(page.getByRole("button", { name: "Generate source-backed answer" })).toBeEnabled(); await expect(page.getByTestId("answer-grounding-chip")).toHaveCount(0); expect(answerRequests).toEqual([]); - await expect(page.getByRole("heading", { level: 1, name: "Clinical Guide" })).toBeVisible(); + await expect(page.getByRole("heading", { level: 1, name: "Clinical KB" })).toBeVisible(); await expectDomIntegrity(page, { mobileNav: true, mobileFabReady: false }); await expectNoPageHorizontalOverflow(page); }); From 14a0a898c1f2c24f992cded447ff5464444268e7 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 18 Jul 2026 21:16:04 +0800 Subject: [PATCH 2/5] fix: resolve design audit merge regressions --- scripts/generate-site-map.ts | 5 ----- tests/site-map.test.ts | 9 +++------ tests/ui-accessibility.spec.ts | 2 +- tests/ui-smoke.spec.ts | 4 ++-- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/scripts/generate-site-map.ts b/scripts/generate-site-map.ts index 2be4244f7..0ee3e07ac 100644 --- a/scripts/generate-site-map.ts +++ b/scripts/generate-site-map.ts @@ -96,11 +96,6 @@ const publicRouteHandlerDescriptions: Record = { "/icons/[variant]": "Dynamically generated application icon handler.", }; -const publicRouteHandlerDescriptions: Record = { - "/auth/callback": "Authentication callback handler.", - "/icons/[variant]": "Dynamically generated application icon handler.", -}; - const apiDescriptions: Record = { "/api/answer": "Generate answer response.", "/api/answer/stream": "Streaming answer response.", diff --git a/tests/site-map.test.ts b/tests/site-map.test.ts index ee6cbc957..345f15be8 100644 --- a/tests/site-map.test.ts +++ b/tests/site-map.test.ts @@ -61,13 +61,10 @@ describe("tracked sitemap", () => { for (const redirect of data.redirects) expectDocumentedRoute(redirect.route); }); - it("keeps public redirect handlers in product routes and API handlers in the API section", () => { + it("keeps public redirect handlers out of API routes and records their redirects", () => { const data = collectSiteMapData(); - const productSection = siteMap.slice( - siteMap.indexOf("## Main product routes"), - siteMap.indexOf("## Mode/query routes"), - ); const apiSection = siteMap.slice(siteMap.indexOf("## API routes"), siteMap.indexOf("## Redirects")); + const redirectsSection = siteMap.slice(siteMap.indexOf("## Redirects"), siteMap.indexOf("## Known caveats")); const expectedProductHandlers = [ ["/applications", "src/app/applications/route.ts", "/tools"], [ @@ -126,8 +123,8 @@ describe("tracked sitemap", () => { expect(data.publicRouteHandlers).toContainEqual({ route, file }); expect(data.apiRoutes).not.toContainEqual({ route, file }); expect(data.redirects).toContainEqual({ route, file, target }); - expect(productSection).toContain(`\`${route}\``); expect(apiSection).not.toContain(`\`${route}\``); + expect(redirectsSection).toContain(`\`${route}\``); } }); diff --git a/tests/ui-accessibility.spec.ts b/tests/ui-accessibility.spec.ts index 6be58fad3..e18ffd1c1 100644 --- a/tests/ui-accessibility.spec.ts +++ b/tests/ui-accessibility.spec.ts @@ -48,7 +48,7 @@ async function expectNoPageHorizontalOverflow(page: Page) { } async function expectDashboardUsable(page: Page) { - await expect(page.getByRole("heading", { level: 1, name: "Clinical KB" })).toHaveCount(1); + await expect(page.getByRole("heading", { level: 1, name: "Clinical Guide" })).toHaveCount(1); await expect(page.getByRole("heading", { name: "Answer" })).toBeVisible(); await expect(page.locator('[aria-label^="Search indexed guidelines by question or keyword"]:visible')).toBeVisible(); await expect(page.getByRole("button", { name: "Open answer options" })).toBeVisible(); diff --git a/tests/ui-smoke.spec.ts b/tests/ui-smoke.spec.ts index 21cee4322..f84687920 100644 --- a/tests/ui-smoke.spec.ts +++ b/tests/ui-smoke.spec.ts @@ -873,7 +873,7 @@ test.describe("Clinical KB UI smoke coverage", () => { await gotoApp(page, "/"); await waitForDemoDashboardReady(page); - await expect(page.getByRole("heading", { level: 1, name: "Clinical KB" })).toHaveCount(1); + await expect(page.getByRole("heading", { level: 1, name: "Clinical Guide" })).toHaveCount(1); await expect(page.getByRole("heading", { name: "Answer" })).toBeVisible(); await expect(visibleQuestionInput(page)).toBeVisible(); await expect(page.getByRole("button", { name: "Generate source-backed answer" })).toHaveText(/^\s*Ask\s*$/); @@ -1268,7 +1268,7 @@ test.describe("Clinical KB UI smoke coverage", () => { await expect(page.getByRole("button", { name: "Generate source-backed answer" })).toBeEnabled(); await expect(page.getByTestId("answer-grounding-chip")).toHaveCount(0); expect(answerRequests).toEqual([]); - await expect(page.getByRole("heading", { level: 1, name: "Clinical KB" })).toBeVisible(); + await expect(page.getByRole("heading", { level: 1, name: "Clinical Guide" })).toBeVisible(); await expectDomIntegrity(page, { mobileNav: true, mobileFabReady: false }); await expectNoPageHorizontalOverflow(page); }); From 1d8b0617ca7d60f757f66405ffa16c122ad24405 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 18 Jul 2026 21:20:53 +0800 Subject: [PATCH 3/5] docs: record safe design audit merge review --- docs/branch-review-ledger.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index c151ce902..e32eb1be7 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -602,3 +602,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-18 | claude/clinical-kb-pwa-review-asi3wb (PR #826) | 3d9ee5f44dea9edb1ef5af28f5f265d88d8b9f29 | PWA hardening implementation (plan Phase 1) | Implemented the three open findings from the 2026-07-17 PWA setup review with zero cache-semantics change: committed the rule-6 retirement worker `public/sw-kill-switch.js` with a five-test lock (`tests/pwa-kill-switch.test.ts`), bound the `offline.html` sha256 to the sw.js `CACHE_VERSION` pairing in `tests/pwa-manifest.test.ts` (drift trap closed), added the `?pwa-dev=0` local teardown to `pwa-lifecycle.tsx` with a dom test proving foreign workers and caches stay untouched, and updated `docs/pwa.md` rules 1 and 6 plus the local-dev cleanup step. Phase 0 of the approved plan (pr-policy `base_ref` checkout fix + the Set-Cookie worker-test case) was found already merged to main and skipped. | Focused Vitest 53/53. `verify:cheap` and the `verify:pr-local` unit stage green except `tests/pdf-extraction-budget.test.ts`, which fails identically on clean main in this container (child-process semantics; baselined twice). `verify:ui` 218 passed with 2 container-baselined pre-existing failures: the `ui-pwa` installability test (Chromium `in-incognito` artifact, reproduced from a clean-main detached worktree with its own server) and the `ui-smoke` document-viewer PDF-canvas mobile test (also fails on clean main `54229f0`; flagged as possible upstream regression). `format:check` clean for repo files. Conditional build/bundle stages deferred to the blocking hosted CI Build job on PR #826. No provider-backed checks run. | | 2026-07-18 | claude/clinical-kb-pwa-review-asi3wb (PR #835) | d46f381ac27b53b1bd5ac0ef77962fbd48cf3aa7 | PWA manifest and install-UX polish (plan Phase 2) | Implemented Phase 2 of the PWA plan with cache semantics untouched: `launch_handler` navigate-existing/auto and `display_override` standalone/minimal-ui in `manifest.ts`; `monochrome-192/512` icon variants rendered as a white alpha-only silhouette from the shared brand mark via `BRAND_MONOCHROME`; a one-time iOS/iPadOS Add to Home Screen hint in `pwa-lifecycle.tsx` (30-day dismissal key, never in standalone, timer-deferred eligibility for the set-state-in-effect lint rule). Docs Installability section updated; manifest screenshots remain deferred per the production-capture precondition. Phase 2 re-scout confirmed zero upstream drift before implementation. | Focused Vitest 55/55. `verify:cheap` 2773 passed/1 failed and `verify:pr-local` unit stage identical — the lone failure is the known container-only `pdf-extraction-budget` artifact (clean-main baselined; hosted CI green on #826). `test:e2e:pwa`: privacy journey passed; icon probes validated both new monochrome PNGs; sole installability error remains the container `in-incognito` artifact. `verify:ui` 219 passed/2 failed — exactly the two clean-main-baselined container artifacts, no new failures. `format:check` clean. Build/bundle stages deferred to the blocking hosted CI Build job on PR #835. No provider-backed checks run. | | 2026-07-18 | codex/rag-merge-final-20260718-655a | 20e5964bbfdcac0311b89c96931a43544be545a6 | RAG recovery, grounding, and latency merge closure | Reviewed the recovered historical RAG fix series against fresh `origin/main`. No additional source change was needed: current main already contains the stricter source-scoped numeric grounding, blocked-retrieval-only extractive recovery, generic LAI deterministic recovery, per-case answer latency diagnostics, and agitation lexical-path protections. The only residual branch diff was proven unreachable because every medication-chart trigger yields explicit search terms; it was intentionally not carried forward. | Full local Vitest: 301 files / 2,779 tests passed. Offline RAG fixture and production-contract validation: 36 golden cases, 21 suites, 294 tests passed. Prettier and `git diff --check` passed. `verify:cheap` reached its lint stage after all preceding static guards passed, but was blocked twice by active heavyweight jobs in other registered worktrees; it was not retried. No Supabase, OpenAI, live retrieval, production-readiness, deployment, or hosted CI command was run. | +| 2026-07-18 | codex/main-merge-51278-final-20260718-late | 45fa3c6c7, 14a0a898c | merge integration of 51278a70d onto fresh origin/main | Replayed the requested historical design-audit commit onto fresh `origin/main`. Kept current-main versions for five conflicts, including the regenerated drift manifest and current schema assertions. Fixed the duplicate sitemap-generator declaration, corrected redirect-section coverage, and restored the current `Clinical Guide` UI contract. | `git diff --check` and `npm run sitemap:check` passed. `npm run test` was attempted twice but blocked by the repository-wide heavy-command lock held by a separate Playwright worktree; no provider-backed checks ran. | From 18872f7d09e1ed2d835ddad638db2330fb8234ea Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 18 Jul 2026 21:26:07 +0800 Subject: [PATCH 4/5] fix: clear merge verification regressions --- playwright.config.ts | 1 - tests/site-map.test.ts | 35 ----------------------------------- 2 files changed, 36 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index f3b7bba18..25407cfd5 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -56,7 +56,6 @@ export default defineConfig({ grepInvert: mockupTag, use: { ...devices["Desktop Chrome"], - reducedMotion: "no-preference", ...(chromiumExecutablePath ? { launchOptions: { executablePath: chromiumExecutablePath } } : {}), }, }, diff --git a/tests/site-map.test.ts b/tests/site-map.test.ts index 345f15be8..290fbe554 100644 --- a/tests/site-map.test.ts +++ b/tests/site-map.test.ts @@ -64,7 +64,6 @@ describe("tracked sitemap", () => { it("keeps public redirect handlers out of API routes and records their redirects", () => { const data = collectSiteMapData(); const apiSection = siteMap.slice(siteMap.indexOf("## API routes"), siteMap.indexOf("## Redirects")); - const redirectsSection = siteMap.slice(siteMap.indexOf("## Redirects"), siteMap.indexOf("## Known caveats")); const expectedProductHandlers = [ ["/applications", "src/app/applications/route.ts", "/tools"], [ @@ -94,40 +93,6 @@ describe("tracked sitemap", () => { } }); - it("keeps public redirect handlers in product routes and API handlers in the API section", () => { - const data = collectSiteMapData(); - const productSection = siteMap.slice( - siteMap.indexOf("## Main product routes"), - siteMap.indexOf("## Mode/query routes"), - ); - const apiSection = siteMap.slice(siteMap.indexOf("## API routes"), siteMap.indexOf("## Redirects")); - const expectedProductHandlers = [ - ["/applications", "src/app/applications/route.ts", "/tools"], - [ - "/differentials/presentations", - "src/app/differentials/presentations/route.ts", - "/differentials/presentations/[workflow-slug]", - ], - ["/medications", "src/app/medications/route.ts", "/?mode=prescribing"], - ] as const; - - expect(data.apiRoutes.every((route) => route.route === "/api" || route.route.startsWith("/api/"))).toBe(true); - expect(data.publicRouteHandlers.some((route) => route.route === "/auth/callback")).toBe(true); - expect(data.publicRouteHandlers).toContainEqual({ - route: "/icons/[variant]", - file: "src/app/icons/[variant]/route.tsx", - }); - expect(apiSection).not.toContain("`/icons/[variant]`"); - - for (const [route, file, target] of expectedProductHandlers) { - expect(data.publicRouteHandlers).toContainEqual({ route, file }); - expect(data.apiRoutes).not.toContainEqual({ route, file }); - expect(data.redirects).toContainEqual({ route, file, target }); - expect(apiSection).not.toContain(`\`${route}\``); - expect(redirectsSection).toContain(`\`${route}\``); - } - }); - it("documents seeded dynamic slugs", () => { for (const service of serviceRecords) expectDocumentedRoute(service.slug); for (const form of formRecords) expectDocumentedRoute(form.slug); From 72aac0bf31585772ff2addf76cdb9da9873d090b Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 18 Jul 2026 21:29:57 +0800 Subject: [PATCH 5/5] fix: restore redirect query contracts --- src/app/page.tsx | 3 +++ tests/site-map.test.ts | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/app/page.tsx b/src/app/page.tsx index 6ce30c137..5dc55d31b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,6 +7,9 @@ import { appModeHomeHref, isAppModeId, isAppModeVisible, type AppModeId } from " type HomeProps = { searchParams?: Promise<{ mode?: string | string[]; + q?: string | string[]; + focus?: string | string[]; + run?: string | string[]; }>; }; diff --git a/tests/site-map.test.ts b/tests/site-map.test.ts index 290fbe554..cd97ca309 100644 --- a/tests/site-map.test.ts +++ b/tests/site-map.test.ts @@ -63,6 +63,10 @@ describe("tracked sitemap", () => { it("keeps public redirect handlers out of API routes and records their redirects", () => { const data = collectSiteMapData(); + const productSection = siteMap.slice( + siteMap.indexOf("## Main product routes"), + siteMap.indexOf("## Mode/query routes"), + ); const apiSection = siteMap.slice(siteMap.indexOf("## API routes"), siteMap.indexOf("## Redirects")); const expectedProductHandlers = [ ["/applications", "src/app/applications/route.ts", "/tools"],