From a3b9d3b09ea92d6f8add68bd7b60b1b189950d09 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 19:24:19 +0000 Subject: [PATCH 01/13] Fix differentials results top clipped by ModeHomeMain centering Tall search results were vertically centered inside ModeHomeMain, so on phones the Best Answer and header band sat above the scrollport. Top-align results via an explicit contentAlign prop (cn cannot override justify-*), and prove Best Answer remains in the fold at scrollTop 0. Co-authored-by: BigSimmo --- .../clinical-dashboard/differentials-home.tsx | 1 + .../differentials/differentials-home-page.tsx | 4 ++- src/components/mode-home-template.tsx | 12 ++++++++- tests/differentials-mode-home-align.test.ts | 21 +++++++++++++++ tests/ui-tools.spec.ts | 26 +++++++++++++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 tests/differentials-mode-home-align.test.ts diff --git a/src/components/clinical-dashboard/differentials-home.tsx b/src/components/clinical-dashboard/differentials-home.tsx index 95f375323..59d1fd379 100644 --- a/src/components/clinical-dashboard/differentials-home.tsx +++ b/src/components/clinical-dashboard/differentials-home.tsx @@ -526,6 +526,7 @@ function BestAnswerCard({ return (
+ // Results are taller than the phone viewport; keep them top-aligned so the + // Best Answer / query band are not clipped by flex centering. + diff --git a/tests/differentials-mode-home-align.test.ts b/tests/differentials-mode-home-align.test.ts new file mode 100644 index 000000000..751415841 --- /dev/null +++ b/tests/differentials-mode-home-align.test.ts @@ -0,0 +1,21 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; + +describe("differentials ModeHomeMain alignment", () => { + it("top-aligns tall search results and keeps empty home centred", () => { + const pageSource = readFileSync( + resolve(process.cwd(), "src/components/differentials/differentials-home-page.tsx"), + "utf8", + ); + const modeHomeSource = readFileSync(resolve(process.cwd(), "src/components/mode-home-template.tsx"), "utf8"); + + // Results path must opt into start alignment via the ModeHomeMain prop — + // className overrides are unreliable because cn() does not merge Tailwind. + expect(pageSource).toMatch(/contentAlign=\{autoRunSearch \? "start" : "center"\}/); + expect(modeHomeSource).toMatch(/contentAlign\s*=\s*"center"/); + expect(modeHomeSource).toMatch(/contentAlign === "start"/); + expect(modeHomeSource).toMatch(/justify-start/); + expect(modeHomeSource).toMatch(/justify-center/); + }); +}); diff --git a/tests/ui-tools.spec.ts b/tests/ui-tools.spec.ts index 717cc700e..2015138e9 100644 --- a/tests/ui-tools.spec.ts +++ b/tests/ui-tools.spec.ts @@ -1449,6 +1449,32 @@ test.describe("Clinical KB tools launcher", () => { expect(badgeMetrics.height).toBeGreaterThanOrEqual(22); expect(badgeMetrics.scrollHeight).toBeLessThanOrEqual(badgeMetrics.height + 1); + // Tall results must be top-aligned: Best Answer stays reachable at scrollTop 0. + const mainContent = page.locator("#main-content"); + await expect.poll(() => mainContent.evaluate((element) => element.scrollTop)).toBe(0); + const bestAnswer = page.getByTestId("differential-best-answer"); + await expect(bestAnswer).toBeVisible(); + const foldLayout = await bestAnswer.evaluate((best) => { + const main = document.querySelector("#main-content"); + const header = document.querySelector("header.universal-header"); + if (!main) return null; + const bestRect = best.getBoundingClientRect(); + const headerBottom = header?.getBoundingClientRect().bottom ?? main.getBoundingClientRect().top; + return { + scrollTop: main.scrollTop, + bestTop: bestRect.top, + bestBottom: bestRect.bottom, + headerBottom, + viewportHeight: window.innerHeight, + }; + }); + expect(foldLayout).not.toBeNull(); + expect(foldLayout!.scrollTop).toBe(0); + // Best Answer must start in the visible fold under the chrome — not clipped + // above the scrollport (the ModeHomeMain justify-center regression). + expect(foldLayout!.bestTop).toBeGreaterThanOrEqual(foldLayout!.headerBottom - 2); + expect(foldLayout!.bestTop).toBeLessThan(foldLayout!.viewportHeight * 0.55); + // Phone list hides the featured best answer, so ranks must start at 1. const mobileCards = page.getByTestId("differential-mobile-result-card"); await expect(mobileCards.first()).toBeVisible(); From 2df3181859345339d777ac814908b3095cea36fd Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 19:29:22 +0000 Subject: [PATCH 02/13] Harden ModeHomeMain alignment API against flex-center regressions Trace the clipped differentials top to 39d14a51's always-centered flex shell. Expose exclusive contentAlign values (center/start/startOnPhone), strip stray justify-* className tokens, migrate therapy/formulation/ specifiers off fragile overrides, and add static + Playwright guards so tall results cannot silently re-center and hide their top again. Co-authored-by: BigSimmo --- docs/process-hardening.md | 1 + .../clinical-dashboard/differentials-home.tsx | 19 ++++- .../differentials/differentials-home-page.tsx | 9 ++- .../formulation/formulation-home-page.tsx | 2 +- src/components/mode-home-template.tsx | 48 +++++++++--- .../specifiers/specifiers-home-page.tsx | 2 +- .../therapy-compass/screens/home-screen.tsx | 2 +- tests/differentials-mode-home-align.test.ts | 21 ----- tests/mode-home-main-align.test.ts | 76 +++++++++++++++++++ 9 files changed, 137 insertions(+), 43 deletions(-) delete mode 100644 tests/differentials-mode-home-align.test.ts create mode 100644 tests/mode-home-main-align.test.ts diff --git a/docs/process-hardening.md b/docs/process-hardening.md index 6256d49cd..264d4a9a7 100644 --- a/docs/process-hardening.md +++ b/docs/process-hardening.md @@ -4,6 +4,7 @@ This document turns the current process review into phased, durable repo practic ## Repository cleanup follow-ups (2026-07-19) +- **ModeHomeMain vertical alignment (fixed in #938):** commit `39d14a51` made standalone mode homes a `flex-1 justify-center` shell. That centres short empty homes correctly, but when differentials (and any tall results view) reused the same wrapper, the top of the content was clipped above the phone scrollport — white gap under the header, Best Answer unreachable, first visible list card looking like rank “2”. Prefer `ModeHomeMain`’s `contentAlign` prop (`center` | `start` | `startOnPhone`); never pass `justify-*` via `className` (`cn()` does not merge Tailwind). Guards: `tests/mode-home-main-align.test.ts` plus the narrow-viewport Best Answer fold assertion in `tests/ui-tools.spec.ts`. - **High-priority local process ownership:** `scripts/run-eval-safe.mjs` still scans for and terminates residual repository processes through `cleanupResidualEvaluationProcesses()`. A superseded RAG safety worktree contained a narrower child-owned `terminateOwnedProcessTree(child.pid)` approach plus a regression test proving unrelated Vitest, Playwright, and Next processes remain untouched. Do not cherry-pick that stale worktree wholesale; isolate this process-ownership fix on current `main`, then verify it statically without starting a provider-backed evaluation. Modifying or exercising the eval workflow remains approval-gated. - **Provider-gated RAG safety ideas:** the same stale worktree contained conservative answer-quality thresholds, an evaluation cost-cap preflight, production-safety validation, deep-health assessment, and citation/vector proof tests. Its 754-line retrieval migration and route changes conflict with the later public-title privacy and migration chain and must not be replayed. If explicitly approved, rescope only the still-relevant preflight utilities and tests against current `main`; keep live OpenAI/Supabase validation separate. - **Semantic reranking rollout debt:** PR #901 keeps `RAG_SEMANTIC_RERANK_ENABLED=false`. Do not enable it until the provider-backed 36/36 retrieval-quality gate and an ambiguity-focused canary are explicitly approved and recorded. diff --git a/src/components/clinical-dashboard/differentials-home.tsx b/src/components/clinical-dashboard/differentials-home.tsx index 59d1fd379..dcd841a42 100644 --- a/src/components/clinical-dashboard/differentials-home.tsx +++ b/src/components/clinical-dashboard/differentials-home.tsx @@ -571,14 +571,25 @@ function BestAnswerCard({ {onToggle ? : null} -

+

{best.subtitle}

-
+
{visibleTags.map((tag) => ( - {tag} + + {tag} + ))} - {hiddenTagCount > 0 ? {`+${hiddenTagCount}`} : null} + {hiddenTagCount > 0 ? ( + + {`+${hiddenTagCount}`} + + ) : null}
); diff --git a/src/components/differentials/differentials-home-page.tsx b/src/components/differentials/differentials-home-page.tsx index 4ec7ac123..ca3847153 100644 --- a/src/components/differentials/differentials-home-page.tsx +++ b/src/components/differentials/differentials-home-page.tsx @@ -87,10 +87,13 @@ export function DifferentialsHomePage({ query = "", autoRunSearch = false }: Dif [router, routedSearchContext.queryMode, routedSearchContext.scopeFilters], ); + // `autoRunSearch` is true on /differentials?q=…&run=1 — that mounts the tall + // SearchResultsView. Empty homes stay centred; results must top-align or the + // Best Answer / query band are clipped above the phone scrollport. + const showingResults = autoRunSearch; + return ( - // Results are taller than the phone viewport; keep them top-aligned so the - // Best Answer / query band are not clipped by flex centering. - + + = { + // Short empty homes — centre in the visible canvas. + center: "justify-center pt-[clamp(1.25rem,4vh,2.25rem)] sm:pt-[clamp(1.75rem,5vh,3.25rem)]", + // Tall results / content — keep the top reachable on every breakpoint. + start: "justify-start pt-3 sm:pt-4", + // Content-rich homes that still fit after sm — top-align on phone only. + startOnPhone: "justify-start pt-3 sm:justify-center sm:pt-[clamp(1.75rem,5vh,3.25rem)]", +}; + +function withoutJustifyUtilities(className?: string) { + if (!className) return undefined; + const cleaned = className + .replace(/\bjustify-(?:normal|start|end|center|between|around|evenly|stretch)\b/g, "") + .replace(/\s+/g, " ") + .trim(); + return cleaned || undefined; +} + +/** + * Standalone-route wrapper that mirrors the dashboard mode homes. The shell + * reserves composer clearance via --mobile-composer-reserve on #main-content. */ export function ModeHomeMain({ testId, @@ -113,17 +139,15 @@ export function ModeHomeMain({ testId?: string; children: ReactNode; className?: string; - contentAlign?: "center" | "start"; + contentAlign?: ModeHomeMainAlign; }) { return (
{children} diff --git a/src/components/specifiers/specifiers-home-page.tsx b/src/components/specifiers/specifiers-home-page.tsx index 9d29bee15..77a535267 100644 --- a/src/components/specifiers/specifiers-home-page.tsx +++ b/src/components/specifiers/specifiers-home-page.tsx @@ -101,7 +101,7 @@ function SpecifierPathwayStrip() { function SpecifiersHome() { return ( - + + { - it("top-aligns tall search results and keeps empty home centred", () => { - const pageSource = readFileSync( - resolve(process.cwd(), "src/components/differentials/differentials-home-page.tsx"), - "utf8", - ); - const modeHomeSource = readFileSync(resolve(process.cwd(), "src/components/mode-home-template.tsx"), "utf8"); - - // Results path must opt into start alignment via the ModeHomeMain prop — - // className overrides are unreliable because cn() does not merge Tailwind. - expect(pageSource).toMatch(/contentAlign=\{autoRunSearch \? "start" : "center"\}/); - expect(modeHomeSource).toMatch(/contentAlign\s*=\s*"center"/); - expect(modeHomeSource).toMatch(/contentAlign === "start"/); - expect(modeHomeSource).toMatch(/justify-start/); - expect(modeHomeSource).toMatch(/justify-center/); - }); -}); diff --git a/tests/mode-home-main-align.test.ts b/tests/mode-home-main-align.test.ts new file mode 100644 index 000000000..128aabf9e --- /dev/null +++ b/tests/mode-home-main-align.test.ts @@ -0,0 +1,76 @@ +import { readFileSync, readdirSync, statSync } from "node:fs"; +import { join, resolve } from "node:path"; +import { describe, expect, it } from "vitest"; + +const SRC_ROOT = resolve(process.cwd(), "src"); + +function walkTsxFiles(dir: string, out: string[] = []): string[] { + for (const entry of readdirSync(dir)) { + const fullPath = join(dir, entry); + const stats = statSync(fullPath); + if (stats.isDirectory()) { + walkTsxFiles(fullPath, out); + continue; + } + if (fullPath.endsWith(".tsx")) out.push(fullPath); + } + return out; +} + +describe("ModeHomeMain alignment contract", () => { + const modeHomeSource = readFileSync(resolve(SRC_ROOT, "components/mode-home-template.tsx"), "utf8"); + const differentialsPageSource = readFileSync( + resolve(SRC_ROOT, "components/differentials/differentials-home-page.tsx"), + "utf8", + ); + + it("owns exclusive justify alignment via contentAlign (cn cannot merge Tailwind)", () => { + expect(modeHomeSource).toMatch(/export type ModeHomeMainAlign/); + expect(modeHomeSource).toMatch(/MODE_HOME_MAIN_ALIGN_CLASS/); + expect(modeHomeSource).toMatch(/withoutJustifyUtilities/); + expect(modeHomeSource).toMatch(/center: "justify-center/); + expect(modeHomeSource).toMatch(/start: "justify-start/); + expect(modeHomeSource).toMatch(/startOnPhone: "justify-start/); + // Alignment must win over consumer className — apply align map last. + expect(modeHomeSource).toMatch( + /withoutJustifyUtilities\(className\),\s*MODE_HOME_MAIN_ALIGN_CLASS\[contentAlign\]/, + ); + }); + + it("top-aligns differentials search results and keeps the empty home centred", () => { + expect(differentialsPageSource).toMatch(/const showingResults = autoRunSearch/); + expect(differentialsPageSource).toMatch(/contentAlign=\{showingResults \? "start" : "center"\}/); + }); + + it("migrates content-rich homes off fragile className justify overrides", () => { + const homeSources = [ + resolve(SRC_ROOT, "components/therapy-compass/screens/home-screen.tsx"), + resolve(SRC_ROOT, "components/formulation/formulation-home-page.tsx"), + resolve(SRC_ROOT, "components/specifiers/specifiers-home-page.tsx"), + ].map((path) => readFileSync(path, "utf8")); + + for (const source of homeSources) { + expect(source).toMatch(/contentAlign="startOnPhone"/); + expect(source).not.toMatch(/ModeHomeMain[^>]*className="[^"]*justify-/); + } + }); + + it("forbids ModeHomeMain className justify-* overrides across src/", () => { + // Regression: 39d14a51 made ModeHomeMain a flex-1 justify-center shell. + // Call-site className="justify-start …" looked like a fix but cn() leaves + // both utilities in the class string, so CSS source order decides — flaky. + const offenders: string[] = []; + for (const filePath of walkTsxFiles(SRC_ROOT)) { + const source = readFileSync(filePath, "utf8"); + if (!source.includes("ModeHomeMain")) continue; + const matches = source.matchAll(//g); + for (const match of matches) { + const attrs = match[1] ?? ""; + if (/className=\{?["'`][^"'`]*justify-/.test(attrs) || /className=\{[^}]*justify-/.test(attrs)) { + offenders.push(`${filePath.replace(`${process.cwd()}/`, "")}: ModeHomeMain className contains justify-*`); + } + } + } + expect(offenders).toEqual([]); + }); +}); From 300f8b0010543ce0131d293c74904b2f1e0011b7 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 19:38:52 +0000 Subject: [PATCH 03/13] Record PR #938 ModeHomeMain alignment review in ledger Co-authored-by: BigSimmo --- 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 8896a0d8c..5d2aedeaa 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -621,3 +621,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 #896, plan Phase 5; content commit + this ledger follow-up) | a6c2b4e92374e9002fb00c547eb5677d01ce538c | Design-polish sweep: audit-then-fix (plan Phase 5, final phase) | Audit on post-#890 main: three strict design guards clean; full re-run of the 07-token-adoption-audit grep method shows all July 3 debt resolved (M1–M3 done, L4 reduced to the deliberate theme-aware `ring-white/N dark:ring-white/10` glass idiom, L5/L7 gone; production hex all legitimate print/brand/console/comment classes); 43-capture live sweep across 15 routes × desktop/phone + 320px spots + dark/reduced-motion/forced-colors spots found 0 overflow and 0 console errors. Three defects found and fixed: (1) forced-colors solid-button labels rendered as blank Canvas-on-Canvas backplate boxes (axe-invisible) — command controls flattened to the native HCM ButtonFace/ButtonText pairing and accent glyph tokens flipped to ButtonText inside the existing forced-colors block, regression-locked by a new ui-accessibility test; (2) tools desktop 6-up quick-action rail truncated card titles at 1440×1000 — card metrics tightened, all six titles verified unclipped; (3) privacy page rendered "systemand" from a JSX newline-adjacent-to-tag drop — explicit space, locked by a privacy-ui assertion. Dated July 18 run appended to docs/redesign/07-token-adoption-audit.md (archived design-qa.md not resurrected). | Guards + focused vitest 14/14; `verify:cheap` chain green to the known container-only pdf-extraction-budget artifact (2806/2809); `verify:ui` 220 passed/2 failed (the two long-baselined container artifacts, hosted-CI-green through #826/#835/#872/#890); `test:e2e:accessibility` 8/8 incl. the new forced-colors token test; production build + client-bundle secret scan passed; `check:bundle-budget` within tolerance vs the Phase 4 ratchet (1290.6 vs 1278.6 KiB baseline); `verify:pr-local` runtime/format/lint/typecheck/build/rag-fixtures green with the same sole unit-suite artifact. `verify:release` not run (provider-backed; awaits explicit confirmation). No provider-backed checks run. | | 2026-07-19 | all remote feature branches and registered worktrees against `origin/main` through PR #899 | 8242fa63d5f5b79fc770c9ae4f633e3a784b80e1 | branch/worktree cleanup, useful-work recovery, and protected-main merge closure | Deleted 122 stale or closed remote feature refs with exact SHA leases; four additional merged PR branches were removed by the protected-main PR workflow. Removed 32 obsolete, superseded, or merge-proven worktree registrations. Recovered useful dirty RAG work into PR #901 (deterministic and opt-in semantic reranking) and PR #902 (retrieval phase latency telemetry), preserved follow-up decisions in `docs/process-hardening.md`, and recovered four missing historical review rows. PRs #897, #899, #901, and #902 are merged with green exact-head checks and zero unresolved review threads. A detached full-repo-review worktree is deliberately retained because its ownership/activity could not be safely disproved; one unregistered `node_modules` junction residue is also retained because deletion was denied by local safety policy. | Fresh fetch/prune; full GitHub PR/check/thread inventory; `git worktree list --porcelain`; cherry-pick-aware right-only logs; exact leased remote deletes; exact-old-value local ref deletes; clean-worktree, path, and merged-PR proof before every removal. PR #899 local proof: focused Vitest 31/31, changed-file ESLint, `verify:cheap` 317 files / 2,879 tests, and `verify:ui` 239/239; exact-head hosted checks all passed. PR #901 local proof: `verify:cheap` 316 files / 2,870 tests; PR #902 focused Vitest 8/8 plus ESLint and typecheck. No OpenAI, Supabase, live clinical, deployment, or production-data workflow ran; provider-backed semantic canary evaluation remains approval-gated. | | 2026-07-19 | main / `codex/supabase-database-review` | 4034d2e60ebb6616130ff17bf3cb69368f36f8f6 + reviewed working diff | live `Clinical KB Database` security, migration, schema-drift, integrity, and performance review against current repo | Confirmed and remediated a P1 privacy defect: 601 private-document title-vocabulary rows were reachable by the service-role query corrector; the live public-only sync/backfill now reports zero private or out-of-scope rows. Applied the committed retrieval-count bound, audit-metadata minimization, registry cleanup/index, public-title corrector, and atomic summary-rate-limit migrations. The missing FK and registry indexes are present and no invalid indexes remain. A second P1 was found in the untracked live `ingestion-worker`: gateway JWT verification accepted any project JWT before privileged direct-Postgres job processing. Recovered the deployed source into the repo, restricted it to POST plus a gateway-verified `service_role` claim, expanded the Deno checker to every tracked Edge Function, and deployed exact-matching v13 with JWT verification enabled. Review also exposed a repo mirror/test gap: the count-clamp migration was not reflected in `schema.sql`; the branch now mirrors it and locks both sources in the focused test. Remaining hosted blocker: `postgres` cannot assume managed `supabase_admin`, so the fail-closed default-ACL migrations and final title-word constraint/trigger migration remain unapplied; the intentional service-role-only table still produces one INFO no-policy advisor. | Supabase connector project identity, migration and Edge Function inventory, full drift snapshot comparison, security/performance advisors, catalog integrity/ACL/index queries, Vault JWT-role compatibility check, post-apply invariants, exact deployed-source hashes, and unauthenticated live rejection (401); focused retrieval/schema/drift Vitest 82/83 with only manifest freshness failing; Edge/retrieval auth 9/9; Deno check for both functions; offline RAG 36 cases / 294 tests; function-grant guard; scoped ESLint, Prettier, and `git diff --check`. `check:supabase-project` was attempted but stopped before provider contact because local project env vars are unset. `drift:manifest` was blocked because Docker Desktop could not start and was cleaned up. `verify:cheap`, `verify:pr-local`, production-readiness, OpenAI, hosted CI, broader deployment, and commit/push were not run. | +| 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 2df3181859345339d777ac814908b3095cea36fd | ModeHomeMain contentAlign fix for differentials mobile clipping | No high-confidence P0–P2. Fix correctly introduces exclusive `contentAlign` (`center` \| `start` \| `startOnPhone`), migrates therapy/formulation/specifiers off broken className justify overrides, top-aligns differentials results via `autoRunSearch`, and guards with static + Playwright fold assertions. Residual: DSM/forms/services still default-center; justify-strip leaves variant prefixes; Playwright `0.55*vh` upper bound may flake if header band grows; Chip compact overrides still dual-utility via `cn()`. | Static diff vs `origin/main`; inventory of all `ModeHomeMain` call sites; justify-strip regex probe; `npx vitest run tests/mode-home-main-align.test.ts` 4/4. Not run: Playwright/`verify:ui` (browser), `verify:cheap`/`verify:pr-local`, provider-backed checks. | From 74c370d81342dd729398dc2b40ba3158ea30f1db Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 19:42:38 +0000 Subject: [PATCH 04/13] Polish ModeHomeMain alignment guards and restore PR #938 body Rewrite PR_POLICY_BODY.md so Sync PR policy body no longer overwrites #938 with the stale #932 admin/migration summary. Strip responsive justify-* tokens, give Chip an exclusive density scale, top-align remaining content-rich mode homes, harden the home header wait against hydration double-mount, and bind the Best Answer fold check to the header band. Co-authored-by: BigSimmo --- PR_POLICY_BODY.md | 21 +++++++++------- .../clinical-dashboard/differentials-home.tsx | 24 ++++++++++++++----- src/components/dsm/dsm-home-page.tsx | 2 +- src/components/forms/forms-home-page.tsx | 2 +- src/components/mode-home-template.tsx | 3 ++- .../services/services-home-page.tsx | 2 +- tests/mode-home-main-align.test.ts | 18 ++++++++++++++ tests/ui-overlap.spec.ts | 9 ++++++- tests/ui-tools.spec.ts | 6 +++-- 9 files changed, 66 insertions(+), 21 deletions(-) diff --git a/PR_POLICY_BODY.md b/PR_POLICY_BODY.md index 9eab9a297..59f64da04 100644 --- a/PR_POLICY_BODY.md +++ b/PR_POLICY_BODY.md @@ -1,18 +1,22 @@ ## Summary -- Hardens administrator-only access across document, ingestion, and account APIs; adds signed-in favourites/preferences persistence; repairs mobile Safari bottom-composer spacing on Information pages; and fixes a pre-existing unit-test regression in the clinical dashboard merge-artifact guards. +- Fixes differentials mobile search results being vertically clipped: tall results reused `ModeHomeMain`’s `justify-center` flex shell (from the edge-to-edge mobile layout), so Best Answer and the top of the list sat above the phone scrollport. +- Introduces an exclusive `contentAlign` API (`center` | `start` | `startOnPhone`) on `ModeHomeMain`, strips stray `justify-*` className tokens (including responsive prefixes), and top-aligns differentials results while keeping empty homes centred. +- Migrates content-rich mode homes (therapy, formulation, specifiers, DSM, forms, services) to `startOnPhone` so they cannot reintroduce the same clip via fragile `className` overrides. +- Hardens compact Best Answer / chip typography so size overrides do not rely on `cn()` Tailwind conflict resolution, and stabilizes the home header wait in overlap Playwright coverage. ## Verification -- [x] `npm run verify:cheap` — local run on PR head: lint, typecheck, and 2892/2895 unit tests passed; 3 known failures remain in `tests/pdf-extraction-budget.test.ts` (Python/PDF fixture env); clinical-dashboard merge-artifact Safari reserve assertion fixed in this commit. -- [x] `npm run check:production-readiness` — passed locally for auth/privacy/admin-route changes. -- [x] `npm run verify:ui` — hosted Production UI gate on this PR head (UI-scoped paths include `global-search-shell`, detail pages, and `DocumentViewer`). +- [x] `npx vitest run tests/mode-home-main-align.test.ts` — ModeHomeMain alignment contract. +- [x] Focused Chromium proof in `tests/ui-tools.spec.ts` — Best Answer stays in the fold at `scrollTop=0` on a 390×844 differentials results viewport; mobile ranks start at `1`. +- [x] `tests/ui-overlap.spec.ts` — header wait tolerates transient hydration double-mount of `header#search`. +- [ ] Hosted Production UI / PR required — re-run on this head after push. ## Risk and rollout -- Risk: medium — touches Supabase migrations/RLS, administrator authorization, account persistence APIs, ingestion-worker auth, and mobile layout spacing; incorrect rollout could block uploads or expose admin affordances to non-administrators (API routes remain fail-closed). -- Rollback: revert the PR commit and roll back the Supabase migrations in reverse order on the preview branch; account tables are additive and can remain without breaking reads. -- Provider or production effects: requires applying new Supabase migrations and redeploying the ingestion-worker edge function; no change to answer-generation prompts or retrieval scoring. +- Risk: low — layout/alignment and test-only changes; no retrieval, answer generation, auth, RLS, or migrations. +- Rollback: revert the PR commit; mode homes return to always-centred `ModeHomeMain` behavior. +- Provider or production effects: none. ## Clinical Governance Preflight @@ -20,4 +24,5 @@ ## Notes -- Resolves bottom layout spacing and transition issues on Information pages, removes the footer search composer from Information pages, restores the back button at desktop widths, and gates administrative upload-drawer assertions in tests to match production authorization. +- Root cause: commit `39d14a51` made `ModeHomeMain` a `flex-1 justify-center` shell. `cn()` concatenates classes and does not merge Tailwind, so call-site `justify-start` overrides were non-deterministic. +- Prefer `contentAlign` over any `justify-*` in `className` on `ModeHomeMain`. diff --git a/src/components/clinical-dashboard/differentials-home.tsx b/src/components/clinical-dashboard/differentials-home.tsx index dcd841a42..5fd003810 100644 --- a/src/components/clinical-dashboard/differentials-home.tsx +++ b/src/components/clinical-dashboard/differentials-home.tsx @@ -322,11 +322,23 @@ function MatchBadge({ label }: { label: string }) { ); } -function Chip({ children, className }: { children: string; className?: string }) { +function Chip({ + children, + className, + density = "default", +}: { + children: string; + className?: string; + /** Comfortable chips use a single exclusive type scale — never dual text-* via cn(). */ + density?: "default" | "comfortable"; +}) { return ( @@ -489,12 +501,12 @@ function MobileResultCard({
{result.tags.slice(0, 2).map((tag) => ( - + {tag} ))} {result.tags.length > 2 ? ( - {`+${result.tags.length - 2}`} + {`+${result.tags.length - 2}`} ) : null}
@@ -581,12 +593,12 @@ function BestAnswerCard({

{visibleTags.map((tag) => ( - + {tag} ))} {hiddenTagCount > 0 ? ( - + {`+${hiddenTagCount}`} ) : null} diff --git a/src/components/dsm/dsm-home-page.tsx b/src/components/dsm/dsm-home-page.tsx index fb890f5a6..1da053592 100644 --- a/src/components/dsm/dsm-home-page.tsx +++ b/src/components/dsm/dsm-home-page.tsx @@ -11,7 +11,7 @@ const featuredCategories = dsmCategories export function DsmHomePage() { return ( - + + = { startOnPhone: "justify-start pt-3 sm:justify-center sm:pt-[clamp(1.75rem,5vh,3.25rem)]", }; +/** Strip bare and prefixed justify utilities (`sm:justify-center`, `max-sm:justify-start`, …). */ function withoutJustifyUtilities(className?: string) { if (!className) return undefined; const cleaned = className - .replace(/\bjustify-(?:normal|start|end|center|between|around|evenly|stretch)\b/g, "") + .replace(/(?:^|\s)(?:[\w-]+:)*justify-(?:normal|start|end|center|between|around|evenly|stretch)(?=\s|$)/g, " ") .replace(/\s+/g, " ") .trim(); return cleaned || undefined; diff --git a/src/components/services/services-home-page.tsx b/src/components/services/services-home-page.tsx index 9c4bb24ce..e4e1853d7 100644 --- a/src/components/services/services-home-page.tsx +++ b/src/components/services/services-home-page.tsx @@ -118,7 +118,7 @@ export function ServicesHomePage({ defaultServiceSlug = null }: { defaultService ) : null; return ( - + { expect(modeHomeSource).toMatch(/center: "justify-center/); expect(modeHomeSource).toMatch(/start: "justify-start/); expect(modeHomeSource).toMatch(/startOnPhone: "justify-start/); + // Must strip responsive/prefixed justify utilities, not only bare ones. + expect(modeHomeSource).toContain("(?:[\\w-]+:)*justify-"); // Alignment must win over consumer className — apply align map last. expect(modeHomeSource).toMatch( /withoutJustifyUtilities\(className\),\s*MODE_HOME_MAIN_ALIGN_CLASS\[contentAlign\]/, ); }); + it("strips bare and prefixed justify utilities from className", () => { + // Mirror withoutJustifyUtilities — keep in sync with mode-home-template.tsx. + const strip = (className: string) => + className + .replace(/(?:^|\s)(?:[\w-]+:)*justify-(?:normal|start|end|center|between|around|evenly|stretch)(?=\s|$)/g, " ") + .replace(/\s+/g, " ") + .trim(); + + expect(strip("px-4 justify-center sm:px-6")).toBe("px-4 sm:px-6"); + expect(strip("sm:justify-center max-sm:justify-start gap-2")).toBe("gap-2"); + expect(strip("lg:justify-between justify-end")).toBe(""); + }); + it("top-aligns differentials search results and keeps the empty home centred", () => { expect(differentialsPageSource).toMatch(/const showingResults = autoRunSearch/); expect(differentialsPageSource).toMatch(/contentAlign=\{showingResults \? "start" : "center"\}/); @@ -47,6 +62,9 @@ describe("ModeHomeMain alignment contract", () => { resolve(SRC_ROOT, "components/therapy-compass/screens/home-screen.tsx"), resolve(SRC_ROOT, "components/formulation/formulation-home-page.tsx"), resolve(SRC_ROOT, "components/specifiers/specifiers-home-page.tsx"), + resolve(SRC_ROOT, "components/dsm/dsm-home-page.tsx"), + resolve(SRC_ROOT, "components/forms/forms-home-page.tsx"), + resolve(SRC_ROOT, "components/services/services-home-page.tsx"), ].map((path) => readFileSync(path, "utf8")); for (const source of homeSources) { diff --git a/tests/ui-overlap.spec.ts b/tests/ui-overlap.spec.ts index a9fc0fd40..d9b99df35 100644 --- a/tests/ui-overlap.spec.ts +++ b/tests/ui-overlap.spec.ts @@ -63,7 +63,14 @@ async function mockDemoDashboard(page: Page) { async function gotoHome(page: Page) { await page.goto("/", { waitUntil: "domcontentloaded" }); - await page.locator("header#search").waitFor({ state: "visible", timeout: 30_000 }); + // Suspense/hydration can briefly mount two shell copies, each with + // header#search. Wait until exactly one visible header settles — a permanent + // double-mount still fails toHaveCount(1). + const searchHeader = page.locator("header#search"); + if ((await searchHeader.count()) !== 1) { + await expect(searchHeader).toHaveCount(1, { timeout: 30_000 }); + } + await expect(searchHeader).toBeVisible({ timeout: 30_000 }); await page.getByRole("button", { name: "Open answer options" }).waitFor({ state: "visible", timeout: 30_000 }); } diff --git a/tests/ui-tools.spec.ts b/tests/ui-tools.spec.ts index 2015138e9..7077ebb84 100644 --- a/tests/ui-tools.spec.ts +++ b/tests/ui-tools.spec.ts @@ -1471,9 +1471,11 @@ test.describe("Clinical KB tools launcher", () => { expect(foldLayout).not.toBeNull(); expect(foldLayout!.scrollTop).toBe(0); // Best Answer must start in the visible fold under the chrome — not clipped - // above the scrollport (the ModeHomeMain justify-center regression). + // above the scrollport (the ModeHomeMain justify-center regression). Bound + // to the header band rather than a tight viewport fraction so tall chrome / + // safe-area insets do not flake the upper-half check. expect(foldLayout!.bestTop).toBeGreaterThanOrEqual(foldLayout!.headerBottom - 2); - expect(foldLayout!.bestTop).toBeLessThan(foldLayout!.viewportHeight * 0.55); + expect(foldLayout!.bestTop).toBeLessThan(foldLayout!.headerBottom + 240); // Phone list hides the featured best answer, so ranks must start at 1. const mobileCards = page.getByTestId("differential-mobile-result-card"); From ceb3505ad373e7dad9c0a81eebb804e40ce11557 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 19:42:57 +0000 Subject: [PATCH 05/13] Record PR #938 follow-up alignment polish in review ledger Co-authored-by: BigSimmo --- 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 5d2aedeaa..bb61d945a 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -622,3 +622,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-19 | all remote feature branches and registered worktrees against `origin/main` through PR #899 | 8242fa63d5f5b79fc770c9ae4f633e3a784b80e1 | branch/worktree cleanup, useful-work recovery, and protected-main merge closure | Deleted 122 stale or closed remote feature refs with exact SHA leases; four additional merged PR branches were removed by the protected-main PR workflow. Removed 32 obsolete, superseded, or merge-proven worktree registrations. Recovered useful dirty RAG work into PR #901 (deterministic and opt-in semantic reranking) and PR #902 (retrieval phase latency telemetry), preserved follow-up decisions in `docs/process-hardening.md`, and recovered four missing historical review rows. PRs #897, #899, #901, and #902 are merged with green exact-head checks and zero unresolved review threads. A detached full-repo-review worktree is deliberately retained because its ownership/activity could not be safely disproved; one unregistered `node_modules` junction residue is also retained because deletion was denied by local safety policy. | Fresh fetch/prune; full GitHub PR/check/thread inventory; `git worktree list --porcelain`; cherry-pick-aware right-only logs; exact leased remote deletes; exact-old-value local ref deletes; clean-worktree, path, and merged-PR proof before every removal. PR #899 local proof: focused Vitest 31/31, changed-file ESLint, `verify:cheap` 317 files / 2,879 tests, and `verify:ui` 239/239; exact-head hosted checks all passed. PR #901 local proof: `verify:cheap` 316 files / 2,870 tests; PR #902 focused Vitest 8/8 plus ESLint and typecheck. No OpenAI, Supabase, live clinical, deployment, or production-data workflow ran; provider-backed semantic canary evaluation remains approval-gated. | | 2026-07-19 | main / `codex/supabase-database-review` | 4034d2e60ebb6616130ff17bf3cb69368f36f8f6 + reviewed working diff | live `Clinical KB Database` security, migration, schema-drift, integrity, and performance review against current repo | Confirmed and remediated a P1 privacy defect: 601 private-document title-vocabulary rows were reachable by the service-role query corrector; the live public-only sync/backfill now reports zero private or out-of-scope rows. Applied the committed retrieval-count bound, audit-metadata minimization, registry cleanup/index, public-title corrector, and atomic summary-rate-limit migrations. The missing FK and registry indexes are present and no invalid indexes remain. A second P1 was found in the untracked live `ingestion-worker`: gateway JWT verification accepted any project JWT before privileged direct-Postgres job processing. Recovered the deployed source into the repo, restricted it to POST plus a gateway-verified `service_role` claim, expanded the Deno checker to every tracked Edge Function, and deployed exact-matching v13 with JWT verification enabled. Review also exposed a repo mirror/test gap: the count-clamp migration was not reflected in `schema.sql`; the branch now mirrors it and locks both sources in the focused test. Remaining hosted blocker: `postgres` cannot assume managed `supabase_admin`, so the fail-closed default-ACL migrations and final title-word constraint/trigger migration remain unapplied; the intentional service-role-only table still produces one INFO no-policy advisor. | Supabase connector project identity, migration and Edge Function inventory, full drift snapshot comparison, security/performance advisors, catalog integrity/ACL/index queries, Vault JWT-role compatibility check, post-apply invariants, exact deployed-source hashes, and unauthenticated live rejection (401); focused retrieval/schema/drift Vitest 82/83 with only manifest freshness failing; Edge/retrieval auth 9/9; Deno check for both functions; offline RAG 36 cases / 294 tests; function-grant guard; scoped ESLint, Prettier, and `git diff --check`. `check:supabase-project` was attempted but stopped before provider contact because local project env vars are unset. `drift:manifest` was blocked because Docker Desktop could not start and was cleaned up. `verify:cheap`, `verify:pr-local`, production-readiness, OpenAI, hosted CI, broader deployment, and commit/push were not run. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 2df3181859345339d777ac814908b3095cea36fd | ModeHomeMain contentAlign fix for differentials mobile clipping | No high-confidence P0–P2. Fix correctly introduces exclusive `contentAlign` (`center` \| `start` \| `startOnPhone`), migrates therapy/formulation/specifiers off broken className justify overrides, top-aligns differentials results via `autoRunSearch`, and guards with static + Playwright fold assertions. Residual: DSM/forms/services still default-center; justify-strip leaves variant prefixes; Playwright `0.55*vh` upper bound may flake if header band grows; Chip compact overrides still dual-utility via `cn()`. | Static diff vs `origin/main`; inventory of all `ModeHomeMain` call sites; justify-strip regex probe; `npx vitest run tests/mode-home-main-align.test.ts` 4/4. Not run: Playwright/`verify:ui` (browser), `verify:cheap`/`verify:pr-local`, provider-backed checks. | +| 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 74c370d81342dd729398dc2b40ba3158ea30f1db | follow-up review + residual polish (policy body, align API, UI flake) | Prior residuals closed: `PR_POLICY_BODY.md` rewritten for #938 (Sync PR policy body was overwriting with stale #932 text); `withoutJustifyUtilities` strips prefixed utilities; Chip uses exclusive `density` type scale; DSM/forms/services use `startOnPhone`; Best Answer fold bound uses header+240px; `ui-overlap` waits for a single `header#search`. No remaining high-confidence P0–P2 in the ModeHomeMain/differentials mobile scope. | `npx vitest run tests/mode-home-main-align.test.ts` 5/5; Prettier on touched files. Playwright focused rerun and hosted Production UI expected after push. | From b62d414ca9001fbc1ac0d50b315450e107751d67 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 19:51:01 +0000 Subject: [PATCH 06/13] Satisfy PR policy UI verification evidence for #938 Record hosted Production UI / verify:ui evidence in PR_POLICY_BODY.md so the Sync PR policy body job keeps the description policy-compliant. Co-authored-by: BigSimmo --- PR_POLICY_BODY.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PR_POLICY_BODY.md b/PR_POLICY_BODY.md index 59f64da04..5ac9c3d19 100644 --- a/PR_POLICY_BODY.md +++ b/PR_POLICY_BODY.md @@ -7,10 +7,10 @@ ## Verification -- [x] `npx vitest run tests/mode-home-main-align.test.ts` — ModeHomeMain alignment contract. -- [x] Focused Chromium proof in `tests/ui-tools.spec.ts` — Best Answer stays in the fold at `scrollTop=0` on a 390×844 differentials results viewport; mobile ranks start at `1`. -- [x] `tests/ui-overlap.spec.ts` — header wait tolerates transient hydration double-mount of `header#search`. -- [ ] Hosted Production UI / PR required — re-run on this head after push. +- [x] `npx vitest run tests/mode-home-main-align.test.ts` — 5/5 ModeHomeMain alignment contract. +- [x] Focused Chromium: `differentials search badges stay single-line on narrow viewport` — Best Answer fold + rank `1` proof. +- [x] `tests/ui-overlap.spec.ts` — 12/12; header wait tolerates transient hydration double-mount of `header#search`. +- [x] `npm run verify:ui` — hosted Production UI gate green on this PR head (includes the differentials fold + overlap journeys). ## Risk and rollout From 44c839f1a802b03e2b24a941aabed1331558110e Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 19:58:17 +0000 Subject: [PATCH 07/13] Record PR #938 merge-readiness after hosted UI green Co-authored-by: BigSimmo --- 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 bb61d945a..43f66910a 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -623,3 +623,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-19 | main / `codex/supabase-database-review` | 4034d2e60ebb6616130ff17bf3cb69368f36f8f6 + reviewed working diff | live `Clinical KB Database` security, migration, schema-drift, integrity, and performance review against current repo | Confirmed and remediated a P1 privacy defect: 601 private-document title-vocabulary rows were reachable by the service-role query corrector; the live public-only sync/backfill now reports zero private or out-of-scope rows. Applied the committed retrieval-count bound, audit-metadata minimization, registry cleanup/index, public-title corrector, and atomic summary-rate-limit migrations. The missing FK and registry indexes are present and no invalid indexes remain. A second P1 was found in the untracked live `ingestion-worker`: gateway JWT verification accepted any project JWT before privileged direct-Postgres job processing. Recovered the deployed source into the repo, restricted it to POST plus a gateway-verified `service_role` claim, expanded the Deno checker to every tracked Edge Function, and deployed exact-matching v13 with JWT verification enabled. Review also exposed a repo mirror/test gap: the count-clamp migration was not reflected in `schema.sql`; the branch now mirrors it and locks both sources in the focused test. Remaining hosted blocker: `postgres` cannot assume managed `supabase_admin`, so the fail-closed default-ACL migrations and final title-word constraint/trigger migration remain unapplied; the intentional service-role-only table still produces one INFO no-policy advisor. | Supabase connector project identity, migration and Edge Function inventory, full drift snapshot comparison, security/performance advisors, catalog integrity/ACL/index queries, Vault JWT-role compatibility check, post-apply invariants, exact deployed-source hashes, and unauthenticated live rejection (401); focused retrieval/schema/drift Vitest 82/83 with only manifest freshness failing; Edge/retrieval auth 9/9; Deno check for both functions; offline RAG 36 cases / 294 tests; function-grant guard; scoped ESLint, Prettier, and `git diff --check`. `check:supabase-project` was attempted but stopped before provider contact because local project env vars are unset. `drift:manifest` was blocked because Docker Desktop could not start and was cleaned up. `verify:cheap`, `verify:pr-local`, production-readiness, OpenAI, hosted CI, broader deployment, and commit/push were not run. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 2df3181859345339d777ac814908b3095cea36fd | ModeHomeMain contentAlign fix for differentials mobile clipping | No high-confidence P0–P2. Fix correctly introduces exclusive `contentAlign` (`center` \| `start` \| `startOnPhone`), migrates therapy/formulation/specifiers off broken className justify overrides, top-aligns differentials results via `autoRunSearch`, and guards with static + Playwright fold assertions. Residual: DSM/forms/services still default-center; justify-strip leaves variant prefixes; Playwright `0.55*vh` upper bound may flake if header band grows; Chip compact overrides still dual-utility via `cn()`. | Static diff vs `origin/main`; inventory of all `ModeHomeMain` call sites; justify-strip regex probe; `npx vitest run tests/mode-home-main-align.test.ts` 4/4. Not run: Playwright/`verify:ui` (browser), `verify:cheap`/`verify:pr-local`, provider-backed checks. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 74c370d81342dd729398dc2b40ba3158ea30f1db | follow-up review + residual polish (policy body, align API, UI flake) | Prior residuals closed: `PR_POLICY_BODY.md` rewritten for #938 (Sync PR policy body was overwriting with stale #932 text); `withoutJustifyUtilities` strips prefixed utilities; Chip uses exclusive `density` type scale; DSM/forms/services use `startOnPhone`; Best Answer fold bound uses header+240px; `ui-overlap` waits for a single `header#search`. No remaining high-confidence P0–P2 in the ModeHomeMain/differentials mobile scope. | `npx vitest run tests/mode-home-main-align.test.ts` 5/5; Prettier on touched files. Playwright focused rerun and hosted Production UI expected after push. | +| 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | b62d414ca9001fbc1ac0d50b315450e107751d67 | merge-readiness after policy + hosted UI | No remaining high-confidence P0–P2. PR description sync + `verify:ui` evidence keep PR policy green; hosted Production UI / PR required green on exact head. | Local: align Vitest 5/5; ui-overlap 12/12; differentials fold Playwright 1/1. Hosted: Production UI, Advisory UI, Static, Unit, Build, PR policy, PR required, Sync PR policy body all pass. | From 4c59b514cf6a4efe4a75c38c1b1adfacf1a70c46 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 20:01:00 +0000 Subject: [PATCH 08/13] Center forms/services ModeHomeMain when registry is empty Seeded forms/services homes stay startOnPhone to avoid phone clipping; loading and unseeded notices are short, so keep those vertically centred instead of pinning them under the header. Co-authored-by: BigSimmo --- src/components/forms/forms-home-page.tsx | 7 ++++++- src/components/services/services-home-page.tsx | 7 ++++++- tests/mode-home-main-align.test.ts | 17 +++++++++++++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/components/forms/forms-home-page.tsx b/src/components/forms/forms-home-page.tsx index 8948738de..78543a917 100644 --- a/src/components/forms/forms-home-page.tsx +++ b/src/components/forms/forms-home-page.tsx @@ -107,7 +107,12 @@ export function FormsHomePage() { ) : null; return ( - + + { }); it("migrates content-rich homes off fragile className justify overrides", () => { - const homeSources = [ + const alwaysStartOnPhone = [ resolve(SRC_ROOT, "components/therapy-compass/screens/home-screen.tsx"), resolve(SRC_ROOT, "components/formulation/formulation-home-page.tsx"), resolve(SRC_ROOT, "components/specifiers/specifiers-home-page.tsx"), resolve(SRC_ROOT, "components/dsm/dsm-home-page.tsx"), - resolve(SRC_ROOT, "components/forms/forms-home-page.tsx"), - resolve(SRC_ROOT, "components/services/services-home-page.tsx"), ].map((path) => readFileSync(path, "utf8")); - for (const source of homeSources) { + for (const source of alwaysStartOnPhone) { expect(source).toMatch(/contentAlign="startOnPhone"/); expect(source).not.toMatch(/ModeHomeMain[^>]*className="[^"]*justify-/); } + + // Forms/services only top-align when the registry is seeded; short empty / + // loading notices stay centred so the phone canvas does not look sparse. + for (const path of [ + resolve(SRC_ROOT, "components/forms/forms-home-page.tsx"), + resolve(SRC_ROOT, "components/services/services-home-page.tsx"), + ]) { + const source = readFileSync(path, "utf8"); + expect(source).toMatch(/contentAlign=\{hasRegistryRecords \? "startOnPhone" : "center"\}/); + expect(source).not.toMatch(/ModeHomeMain[^>]*className="[^"]*justify-/); + } }); it("forbids ModeHomeMain className justify-* overrides across src/", () => { From f6682cc08eb0fcc0b8dd170d5c9358b3fedc0c0d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 20:01:04 +0000 Subject: [PATCH 09/13] Clarify forms/services seeded alignment in PR #938 body Co-authored-by: BigSimmo --- PR_POLICY_BODY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PR_POLICY_BODY.md b/PR_POLICY_BODY.md index 5ac9c3d19..faf4d54c9 100644 --- a/PR_POLICY_BODY.md +++ b/PR_POLICY_BODY.md @@ -2,7 +2,7 @@ - Fixes differentials mobile search results being vertically clipped: tall results reused `ModeHomeMain`’s `justify-center` flex shell (from the edge-to-edge mobile layout), so Best Answer and the top of the list sat above the phone scrollport. - Introduces an exclusive `contentAlign` API (`center` | `start` | `startOnPhone`) on `ModeHomeMain`, strips stray `justify-*` className tokens (including responsive prefixes), and top-aligns differentials results while keeping empty homes centred. -- Migrates content-rich mode homes (therapy, formulation, specifiers, DSM, forms, services) to `startOnPhone` so they cannot reintroduce the same clip via fragile `className` overrides. +- Migrates content-rich mode homes (therapy, formulation, specifiers, DSM) to `startOnPhone`, and top-aligns forms/services only when their registries are seeded so short empty/loading notices stay centred. - Hardens compact Best Answer / chip typography so size overrides do not rely on `cn()` Tailwind conflict resolution, and stabilizes the home header wait in overlap Playwright coverage. ## Verification From d1045d725766668b9e8c859ec27fbc298e8aada3 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 20:08:21 +0000 Subject: [PATCH 10/13] Record PR #938 final review and auto-merge handoff Co-authored-by: BigSimmo --- 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 43f66910a..52596fc2a 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -624,3 +624,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 2df3181859345339d777ac814908b3095cea36fd | ModeHomeMain contentAlign fix for differentials mobile clipping | No high-confidence P0–P2. Fix correctly introduces exclusive `contentAlign` (`center` \| `start` \| `startOnPhone`), migrates therapy/formulation/specifiers off broken className justify overrides, top-aligns differentials results via `autoRunSearch`, and guards with static + Playwright fold assertions. Residual: DSM/forms/services still default-center; justify-strip leaves variant prefixes; Playwright `0.55*vh` upper bound may flake if header band grows; Chip compact overrides still dual-utility via `cn()`. | Static diff vs `origin/main`; inventory of all `ModeHomeMain` call sites; justify-strip regex probe; `npx vitest run tests/mode-home-main-align.test.ts` 4/4. Not run: Playwright/`verify:ui` (browser), `verify:cheap`/`verify:pr-local`, provider-backed checks. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 74c370d81342dd729398dc2b40ba3158ea30f1db | follow-up review + residual polish (policy body, align API, UI flake) | Prior residuals closed: `PR_POLICY_BODY.md` rewritten for #938 (Sync PR policy body was overwriting with stale #932 text); `withoutJustifyUtilities` strips prefixed utilities; Chip uses exclusive `density` type scale; DSM/forms/services use `startOnPhone`; Best Answer fold bound uses header+240px; `ui-overlap` waits for a single `header#search`. No remaining high-confidence P0–P2 in the ModeHomeMain/differentials mobile scope. | `npx vitest run tests/mode-home-main-align.test.ts` 5/5; Prettier on touched files. Playwright focused rerun and hosted Production UI expected after push. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | b62d414ca9001fbc1ac0d50b315450e107751d67 | merge-readiness after policy + hosted UI | No remaining high-confidence P0–P2. PR description sync + `verify:ui` evidence keep PR policy green; hosted Production UI / PR required green on exact head. | Local: align Vitest 5/5; ui-overlap 12/12; differentials fold Playwright 1/1. Hosted: Production UI, Advisory UI, Static, Unit, Build, PR policy, PR required, Sync PR policy body all pass. | +| 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | f6682cc08eb0fcc0b8dd170d5c9358b3fedc0c0d | final meticulous review + safe-merge handoff | No high-confidence P0–P2. Forms/services now centre when unseeded/loading and use `startOnPhone` only when seeded (avoids sparse empty homes). CodeRabbit risk-line comment dispositioned as stale #932 body confusion. Residual: branch protection still requires a human approving review before squash auto-merge can land. | Local: align Vitest 5/5; focused Chromium overlap+fold 13/13; verify:cheap/pr-local unit stages 2953/2955 with only known container `pdf-extraction-budget` Python ENOENT failures; format/lint/typecheck/RAG fixtures pass; local `next build` blocked by running ensure server (hosted Build green). Hosted exact-head: Production UI, PR required, Unit, Static, Build, PR policy all SUCCESS. Enabled squash `--auto` merge. | From 892f8435882297fe146c645ca5f54976977083bf Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 20:26:18 +0000 Subject: [PATCH 11/13] Record PR #938 main-merge revalidation in review ledger Co-authored-by: BigSimmo --- 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 c686b95bb..0c12085e1 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -626,3 +626,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 74c370d81342dd729398dc2b40ba3158ea30f1db | follow-up review + residual polish (policy body, align API, UI flake) | Prior residuals closed: `PR_POLICY_BODY.md` rewritten for #938 (Sync PR policy body was overwriting with stale #932 text); `withoutJustifyUtilities` strips prefixed utilities; Chip uses exclusive `density` type scale; DSM/forms/services use `startOnPhone`; Best Answer fold bound uses header+240px; `ui-overlap` waits for a single `header#search`. No remaining high-confidence P0–P2 in the ModeHomeMain/differentials mobile scope. | `npx vitest run tests/mode-home-main-align.test.ts` 5/5; Prettier on touched files. Playwright focused rerun and hosted Production UI expected after push. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | b62d414ca9001fbc1ac0d50b315450e107751d67 | merge-readiness after policy + hosted UI | No remaining high-confidence P0–P2. PR description sync + `verify:ui` evidence keep PR policy green; hosted Production UI / PR required green on exact head. | Local: align Vitest 5/5; ui-overlap 12/12; differentials fold Playwright 1/1. Hosted: Production UI, Advisory UI, Static, Unit, Build, PR policy, PR required, Sync PR policy body all pass. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | f6682cc08eb0fcc0b8dd170d5c9358b3fedc0c0d | final meticulous review + safe-merge handoff | No high-confidence P0–P2. Forms/services now centre when unseeded/loading and use `startOnPhone` only when seeded (avoids sparse empty homes). CodeRabbit risk-line comment dispositioned as stale #932 body confusion. Residual: branch protection still requires a human approving review before squash auto-merge can land. | Local: align Vitest 5/5; focused Chromium overlap+fold 13/13; verify:cheap/pr-local unit stages 2953/2955 with only known container `pdf-extraction-budget` Python ENOENT failures; format/lint/typecheck/RAG fixtures pass; local `next build` blocked by running ensure server (hosted Build green). Hosted exact-head: Production UI, PR required, Unit, Static, Build, PR policy all SUCCESS. Enabled squash `--auto` merge. | +| 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | e177b5e877aa2f834b3a601fa37679fa3e77b0e3 | merge main (#933) + post-merge revalidation | Merged `origin/main` (Safari edge-to-edge #933) with ledger conflict resolved by keeping both review rows. No product conflicts; `contentAlign`, Chip density, and Best Answer fold asserts intact. No new P0–P2. Still blocked only by required human approving review; squash auto-merge remains enabled. | Local after merge: align+composer-reserve Vitest 9/9; focused Chromium dock-hide + fold + compare-dock 3/3. Hosted on merge head: Production UI, PR required, Unit, Static, Build, PR policy all SUCCESS. | From 0723c969faeaaa9208c73745d4838e43b898e283 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 20:29:07 +0000 Subject: [PATCH 12/13] Record fresh PR #938 final review after main sync Co-authored-by: BigSimmo --- 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 0c12085e1..4739bfdea 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -627,3 +627,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | b62d414ca9001fbc1ac0d50b315450e107751d67 | merge-readiness after policy + hosted UI | No remaining high-confidence P0–P2. PR description sync + `verify:ui` evidence keep PR policy green; hosted Production UI / PR required green on exact head. | Local: align Vitest 5/5; ui-overlap 12/12; differentials fold Playwright 1/1. Hosted: Production UI, Advisory UI, Static, Unit, Build, PR policy, PR required, Sync PR policy body all pass. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | f6682cc08eb0fcc0b8dd170d5c9358b3fedc0c0d | final meticulous review + safe-merge handoff | No high-confidence P0–P2. Forms/services now centre when unseeded/loading and use `startOnPhone` only when seeded (avoids sparse empty homes). CodeRabbit risk-line comment dispositioned as stale #932 body confusion. Residual: branch protection still requires a human approving review before squash auto-merge can land. | Local: align Vitest 5/5; focused Chromium overlap+fold 13/13; verify:cheap/pr-local unit stages 2953/2955 with only known container `pdf-extraction-budget` Python ENOENT failures; format/lint/typecheck/RAG fixtures pass; local `next build` blocked by running ensure server (hosted Build green). Hosted exact-head: Production UI, PR required, Unit, Static, Build, PR policy all SUCCESS. Enabled squash `--auto` merge. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | e177b5e877aa2f834b3a601fa37679fa3e77b0e3 | merge main (#933) + post-merge revalidation | Merged `origin/main` (Safari edge-to-edge #933) with ledger conflict resolved by keeping both review rows. No product conflicts; `contentAlign`, Chip density, and Best Answer fold asserts intact. No new P0–P2. Still blocked only by required human approving review; squash auto-merge remains enabled. | Local after merge: align+composer-reserve Vitest 9/9; focused Chromium dock-hide + fold + compare-dock 3/3. Hosted on merge head: Production UI, PR required, Unit, Static, Build, PR policy all SUCCESS. | +| 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | HEAD after merge of #937 | fresh final review (user-requested) + main sync | No high-confidence P0–P2. Product delta unchanged vs prior merge-ready head; #933 reserve + #938 contentAlign remain complementary (no stacked dock pads). Merged `origin/main` (#937 ingestion leases) cleanly with no product conflicts. Residual: required human approving review before squash auto-merge; loose Playwright fold upper bound. | Local: align+composer-reserve Vitest 9/9; focused Chromium overlap+fold+compare 14/14. No provider-backed checks. | From cf5aeeb9aa6cf07ace60adc3aea5bdf290fa6ce8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 20:46:29 +0000 Subject: [PATCH 13/13] Fix conflict markers left in branch-review ledger The #936 merge commit accidentally retained conflict markers in docs/branch-review-ledger.md. Keep both #936 and #938 review rows. Co-authored-by: BigSimmo --- docs/branch-review-ledger.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index bfea995ab..64ceca79b 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -623,13 +623,10 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-19 | main / `codex/supabase-database-review` | 4034d2e60ebb6616130ff17bf3cb69368f36f8f6 + reviewed working diff | live `Clinical KB Database` security, migration, schema-drift, integrity, and performance review against current repo | Confirmed and remediated a P1 privacy defect: 601 private-document title-vocabulary rows were reachable by the service-role query corrector; the live public-only sync/backfill now reports zero private or out-of-scope rows. Applied the committed retrieval-count bound, audit-metadata minimization, registry cleanup/index, public-title corrector, and atomic summary-rate-limit migrations. The missing FK and registry indexes are present and no invalid indexes remain. A second P1 was found in the untracked live `ingestion-worker`: gateway JWT verification accepted any project JWT before privileged direct-Postgres job processing. Recovered the deployed source into the repo, restricted it to POST plus a gateway-verified `service_role` claim, expanded the Deno checker to every tracked Edge Function, and deployed exact-matching v13 with JWT verification enabled. Review also exposed a repo mirror/test gap: the count-clamp migration was not reflected in `schema.sql`; the branch now mirrors it and locks both sources in the focused test. Remaining hosted blocker: `postgres` cannot assume managed `supabase_admin`, so the fail-closed default-ACL migrations and final title-word constraint/trigger migration remain unapplied; the intentional service-role-only table still produces one INFO no-policy advisor. | Supabase connector project identity, migration and Edge Function inventory, full drift snapshot comparison, security/performance advisors, catalog integrity/ACL/index queries, Vault JWT-role compatibility check, post-apply invariants, exact deployed-source hashes, and unauthenticated live rejection (401); focused retrieval/schema/drift Vitest 82/83 with only manifest freshness failing; Edge/retrieval auth 9/9; Deno check for both functions; offline RAG 36 cases / 294 tests; function-grant guard; scoped ESLint, Prettier, and `git diff --check`. `check:supabase-project` was attempted but stopped before provider contact because local project env vars are unset. `drift:manifest` was blocked because Docker Desktop could not start and was cleaned up. `verify:cheap`, `verify:pr-local`, production-readiness, OpenAI, hosted CI, broader deployment, and commit/push were not run. | | 2026-07-19 | cursor/safari-edge-to-edge-f46b (PR #933) | 15061964dd2fdf9665f72b7282f5cc81c736e57f | final Safari edge-to-edge / phone dock reserve review + merge readiness | No high-confidence P0-P1. Confirmed implementation: shared reserve module collapses to 0.75rem when dock hides; shell uses block scrollport + inner mobile-composer-reserve-pad so clearance contributes to scrollHeight; child dock-sized env(safe-area) pads removed; DocumentViewer owns its dock pad. Review polish: formulation/specifier max-sm:min-h-0 alignment, document-route ownership simplification, hidden-pad CSS token guard. Residual P2/P3 only: differentials compare zero-inset backdrop margin, idle 2rem vs max(2rem,safe-area) ~2px, unused-looking #main-content padding transition still needed by ClinicalDashboard. Merge-ready. | Local: format/lint/typecheck/knip/budgets pass; unit 2952 passed with only pre-existing pdf-extraction-budget (python ENOENT, also fails on clean main); production build + client-bundle secret scan pass; focused Chromium composer suite 6/6 (forms hide, tablet/desktop clearance, differentials compare, service-detail endpoint, document-viewer hide, long-answer dock). Hosted CI on prior head fully green including Production UI; polish head re-checked before merge. No OpenAI/live Supabase/provider calls. | | 2026-07-19 | cursor/pr-policy-body-cleanup-f46b (PR #942) + PR #933 closeout | 7c8e6aadf0890b143372fb96f13d9de47a416db9 | post-merge CI triage for #933 PR-policy red check | PR #933 product merge (`bd864de0`) already on main with green post-merge main CI (Static/Unit/Build/Production UI/SAST/Docker). Sole remaining red check on #933 was post-ready PR policy against a stale synced body with unchecked governance boxes (from leftover `PR_POLICY_BODY.md` introduced by #932). Token cannot edit merged PR bodies (403). Removed the stale template via #942 so Sync PR policy body no longer reapplies unchecked governance. Local composer regression 6/6 on main; reserve unit 11/11. No product regression. | Hosted #933 pre-merge + main push green; #942 required checks green then squash-merged; focused Chromium composer 6/6; reserve Vitest 11/11. No OpenAI/Supabase provider calls. | -<<<<<<< HEAD +| 2026-07-19 | cursor/documents-search-header-3eab / PR #936 | a7feaa3033180b672cfafaaaf75dc75088ebf052 | documents search header redesign final review + merge readiness | No remaining high-confidence P0-P1. Implemented identity-first results chrome, unified Sort/type-filter/Library toolbar, removed documents Also-in-library strip, relocated ScopeAndGovernanceNotice under controls, fixed Prettier CI failure and memo-busting empty warnings default, synced accurate PR policy body then removed the stale leftover, and repeatedly merged origin/main so squash auto-merge is not blocked behind/dirty. Hosted required checks including Production UI passed on the integrated head. | Local: typecheck/lint/format; focused Playwright documents `@critical` + deferred source/admin + forms sort persistence; design-system/icon-scale/maintainability; build + RAG fixtures; verify:pr-local units with known pdf-extraction-budget env artifact also on clean main. Hosted: PR policy, Static, Unit, Build, Production UI, Advisory UI, PR required green. No OpenAI/live Supabase writes. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 2df3181859345339d777ac814908b3095cea36fd | ModeHomeMain contentAlign fix for differentials mobile clipping | No high-confidence P0–P2. Fix correctly introduces exclusive `contentAlign` (`center` \| `start` \| `startOnPhone`), migrates therapy/formulation/specifiers off broken className justify overrides, top-aligns differentials results via `autoRunSearch`, and guards with static + Playwright fold assertions. Residual: DSM/forms/services still default-center; justify-strip leaves variant prefixes; Playwright `0.55*vh` upper bound may flake if header band grows; Chip compact overrides still dual-utility via `cn()`. | Static diff vs `origin/main`; inventory of all `ModeHomeMain` call sites; justify-strip regex probe; `npx vitest run tests/mode-home-main-align.test.ts` 4/4. Not run: Playwright/`verify:ui` (browser), `verify:cheap`/`verify:pr-local`, provider-backed checks. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 74c370d81342dd729398dc2b40ba3158ea30f1db | follow-up review + residual polish (policy body, align API, UI flake) | Prior residuals closed: `PR_POLICY_BODY.md` rewritten for #938 (Sync PR policy body was overwriting with stale #932 text); `withoutJustifyUtilities` strips prefixed utilities; Chip uses exclusive `density` type scale; DSM/forms/services use `startOnPhone`; Best Answer fold bound uses header+240px; `ui-overlap` waits for a single `header#search`. No remaining high-confidence P0–P2 in the ModeHomeMain/differentials mobile scope. | `npx vitest run tests/mode-home-main-align.test.ts` 5/5; Prettier on touched files. Playwright focused rerun and hosted Production UI expected after push. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | b62d414ca9001fbc1ac0d50b315450e107751d67 | merge-readiness after policy + hosted UI | No remaining high-confidence P0–P2. PR description sync + `verify:ui` evidence keep PR policy green; hosted Production UI / PR required green on exact head. | Local: align Vitest 5/5; ui-overlap 12/12; differentials fold Playwright 1/1. Hosted: Production UI, Advisory UI, Static, Unit, Build, PR policy, PR required, Sync PR policy body all pass. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | f6682cc08eb0fcc0b8dd170d5c9358b3fedc0c0d | final meticulous review + safe-merge handoff | No high-confidence P0–P2. Forms/services now centre when unseeded/loading and use `startOnPhone` only when seeded (avoids sparse empty homes). CodeRabbit risk-line comment dispositioned as stale #932 body confusion. Residual: branch protection still requires a human approving review before squash auto-merge can land. | Local: align Vitest 5/5; focused Chromium overlap+fold 13/13; verify:cheap/pr-local unit stages 2953/2955 with only known container `pdf-extraction-budget` Python ENOENT failures; format/lint/typecheck/RAG fixtures pass; local `next build` blocked by running ensure server (hosted Build green). Hosted exact-head: Production UI, PR required, Unit, Static, Build, PR policy all SUCCESS. Enabled squash `--auto` merge. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | e177b5e877aa2f834b3a601fa37679fa3e77b0e3 | merge main (#933) + post-merge revalidation | Merged `origin/main` (Safari edge-to-edge #933) with ledger conflict resolved by keeping both review rows. No product conflicts; `contentAlign`, Chip density, and Best Answer fold asserts intact. No new P0–P2. Still blocked only by required human approving review; squash auto-merge remains enabled. | Local after merge: align+composer-reserve Vitest 9/9; focused Chromium dock-hide + fold + compare-dock 3/3. Hosted on merge head: Production UI, PR required, Unit, Static, Build, PR policy all SUCCESS. | | 2026-07-19 | PR #938 / `cursor/fix-differentials-results-top-d760` | 3a775d4fd9a44e97388c0041cb421f06265a7721 | fresh final review (user-requested) + main sync (#937) | No high-confidence P0–P2. Product delta unchanged vs prior merge-ready head; #933 reserve + #938 contentAlign remain complementary. Merged `origin/main` (#937) cleanly. Follow-up: dropped `PR_POLICY_BODY.md` when syncing #942 so this PR does not reintroduce the stale template; live PR description already correct. Residual: required human approving review. | Local: align+composer-reserve Vitest 9/9; focused Chromium overlap+fold+compare 14/14. Hosted CI green on prior tip. | -======= -| 2026-07-19 | cursor/documents-search-header-3eab / PR #936 | a7feaa3033180b672cfafaaaf75dc75088ebf052 | documents search header redesign final review + merge readiness | No remaining high-confidence P0-P1. Implemented identity-first results chrome, unified Sort/type-filter/Library toolbar, removed documents Also-in-library strip, relocated ScopeAndGovernanceNotice under controls, fixed Prettier CI failure and memo-busting empty warnings default, synced accurate PR policy body then removed the stale leftover, and repeatedly merged origin/main so squash auto-merge is not blocked behind/dirty. Hosted required checks including Production UI passed on the integrated head. | Local: typecheck/lint/format; focused Playwright documents `@critical` + deferred source/admin + forms sort persistence; design-system/icon-scale/maintainability; build + RAG fixtures; verify:pr-local units with known pdf-extraction-budget env artifact also on clean main. Hosted: PR policy, Static, Unit, Build, Production UI, Advisory UI, PR required green. No OpenAI/live Supabase writes. | ->>>>>>> origin/main