From 26bddafb2da14e2ca54113932c33cf938c54a6b9 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 11 Jul 2026 04:47:07 +0800 Subject: [PATCH 1/2] fix(mobile): keep mode-home composer hero-centred on phones and never let it vanish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to #456, which fixed the phone-width composer vanish by raising the mode-home hero query to 640px — moving the phone composer into the bottom dock and regressing the hero-centred landing design that four advisory UI tests encode (confirmed A/B against pre-merge main). - Restore modeHomeComposerMediaQuery to (min-width: 0px) so mode-home shells portal the composer into the hero at every width. - Key the inline fallback on portal outcome instead of the media match: while a slot id is present the inline composer stays suppressed only until the portal mounts or the slot-retry budget exhausts, so the search can never vanish at any width even when the slot never appears. - Add a @critical composer-presence test (phone + desktop, dashboard and standalone shells) so this bug class blocks merges via the required Critical UI smoke gate instead of only failing the advisory suite. - Record the PR #456 review in docs/branch-review-ledger.md. Co-Authored-By: Claude Fable 5 --- docs/branch-review-ledger.md | 1 + .../master-search-header.tsx | 34 ++++++++++++------- tests/ui-tools.spec.ts | 31 +++++++++++++++++ 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 80b660b16..3edfe3b1e 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -29,3 +29,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-10 | codex/architecture-review-fixes | 648abfa3f7c91395b5eeca543f70e0b6ea59e9e0 | architecture-review | Seven findings fixed in the working tree: three runtime cycles, unbounded owner caches, a client/server env boundary breach, reversed runtime-to-scripts ownership, and architecture-doc drift. | `npm run test -- tests/architecture-boundaries.test.ts tests/bounded-ttl-cache.test.ts tests/rag-score.test.ts tests/rag-cache-utils.test.ts tests/rag-cache-invalidation.test.ts tests/evidence-panels.test.ts tests/clinical-dashboard-merge-artifacts.test.ts`; `npm run verify:cheap`; `npm run check:production-readiness:ci` | | 2026-07-10 | codex/architecture-review-fixes | 648abfa3f7c91395b5eeca543f70e0b6ea59e9e0 | frontend-architecture-review | Shared cycle/env findings confirmed and fixed; three additional findings fixed for defeated lazy boundaries, duplicate shell/dashboard subscriptions, and unstable search-context values. | `npm run test -- tests/architecture-boundaries.test.ts tests/evidence-panels.test.ts tests/clinical-dashboard-merge-artifacts.test.ts`; `npm run verify:cheap`; UI gate deferred pending explicit local-API approval | | 2026-07-11 | codex/architecture-review-integration | b45df727b29aad8ba4ec5d4e96d1f0599d7dad8a | branch-integration-review | Replayed the reviewed architecture fixes onto current `origin/main`; preserved current CI/autofix history and found no new high-confidence defect in the integrated diff. | `npm run check:runtime`; `npm run check:github-actions`; `npm run sitemap:check`; `npm run lint`; `npm run typecheck`; focused Vitest (24 passed); full Vitest with `--testTimeout=30000` (1,433 passed, 1 skipped); `git diff --check` | +| 2026-07-11 | claude/mobile-search-bar-fix (PR #456) | b73196c2e2e4a536804cdcdb50879c29e2c582c5 | PR required-testing review | All 4 Advisory UI regression failures confirmed PR-caused via A/B against pre-merge main (01f2cee0d): the 640px mode-home query moved the phone composer out of the hero, contradicting the design tests; residual ≥640px vanish remained when the slot never mounts. PR merged (b32c17b34) before the rework landed; follow-up fix shipped on `claude/mode-home-composer-hero-fix` (0px hero query restored, portal-outcome inline fallback, new `@critical` composer-presence test). Also found: main CI red on every push — missing `RAG_QUERY_HASH_SECRET` secret fails the deployment boot smoke and skips `release-browser-matrix`; owner adding the secret. | Local chromium A/B (PR head 4/5 fail vs baseline product-pass); rework targeted run 6/6 pass incl. new `@critical`; `npm run typecheck`; `npm run lint`; focused Prettier check | diff --git a/src/components/clinical-dashboard/master-search-header.tsx b/src/components/clinical-dashboard/master-search-header.tsx index 2367e91d7..1cdd9c526 100644 --- a/src/components/clinical-dashboard/master-search-header.tsx +++ b/src/components/clinical-dashboard/master-search-header.tsx @@ -71,10 +71,11 @@ import { tagSearchText } from "@/lib/document-tags"; const phoneSearchLayoutMediaQuery = "(max-width: 639px)"; const scopeSheetMediaQuery = "(max-width: 1023px)"; const desktopHomeComposerMediaQuery = "(min-width: 1024px)"; -// Standalone mode-home shells move the composer into the hero from the tablet -// breakpoint up (see heroComposerFromTablet), so it sits in the middle of the -// hero exactly like desktop instead of floating over the heading. -const modeHomeComposerMediaQuery = "(min-width: 640px)"; +// Mode-home shells centre the composer in the hero at every width (see +// heroComposerFromTablet): phones share the hero-centred landing design that +// tests/ui-tools.spec.ts "mode home routes center the shared search on mobile" +// encodes, so the query intentionally always matches. +const modeHomeComposerMediaQuery = "(min-width: 0px)"; const defaultVisibleAppModeOptions = visibleAppModeDefinitions(); function splitFilterText(value: string) { @@ -287,11 +288,12 @@ export function MasterSearchHeader({ const [usesScopeSheet, setUsesScopeSheet] = useState(false); const [usesPhoneSearchLayout, setUsesPhoneSearchLayout] = useState(false); const [desktopHomeComposerActive, setDesktopHomeComposerActive] = useState(false); - // True while the hero-composer media query matches (tablet+ for mode-home - // pages). The portal can lag this by a frame or a retry cycle, so we track the - // match separately to suppress the inline fallback without waiting for the - // portal to mount — otherwise the inline composer flashes during that window. - const [desktopHomeComposerMediaMatches, setDesktopHomeComposerMediaMatches] = useState(false); + // True once the hero portal is conclusively unavailable — the media query + // does not match, or the slot never appeared after the retry budget. While a + // slot id is present and this is false the inline composer stays suppressed + // (no flash while the portal mounts); once it flips true the inline composer + // renders, so the search can never vanish from the page at any width. + const [desktopHomeComposerFallback, setDesktopHomeComposerFallback] = useState(false); // Phone-only hide-on-scroll: never hide while a header-owned surface is open // or while focus sits inside the header chrome (keyboard users must not tab // into invisible controls). @@ -697,7 +699,7 @@ export function MasterSearchHeader({ if (!desktopHomeComposerSlotId) { const frame = window.requestAnimationFrame(() => { setDesktopHomeComposerActive(false); - setDesktopHomeComposerMediaMatches(false); + setDesktopHomeComposerFallback(false); setDesktopHomeComposerHost(null); }); return () => window.cancelAnimationFrame(frame); @@ -724,19 +726,25 @@ export function MasterSearchHeader({ window.clearTimeout(retryTimeout); retryTimeout = null; } - setDesktopHomeComposerMediaMatches(mediaQuery.matches); const slot = mediaQuery.matches ? document.getElementById(desktopHomeComposerSlotId) : null; if (slot) { portalRetryCount = 0; if (host.parentNode !== slot) slot.appendChild(host); setDesktopHomeComposerHost(host); setDesktopHomeComposerActive(true); + setDesktopHomeComposerFallback(false); } else { host.parentNode?.removeChild(host); setDesktopHomeComposerActive(false); if (mediaQuery.matches && portalRetryCount < 24) { portalRetryCount += 1; retryTimeout = window.setTimeout(syncTarget, Math.min(40 * portalRetryCount, 400)); + } else { + // The composer belongs inline at this width, or the slot never + // appeared within the retry budget: release the inline fallback so + // the search cannot vanish. The MutationObserver keeps watching, so + // a slot that shows up later still reclaims the portal. + setDesktopHomeComposerFallback(true); } } }; @@ -756,7 +764,7 @@ export function MasterSearchHeader({ mediaQuery.removeEventListener("change", scheduleSync); host.parentNode?.removeChild(host); setDesktopHomeComposerActive(false); - setDesktopHomeComposerMediaMatches(false); + setDesktopHomeComposerFallback(false); setDesktopHomeComposerHost(null); }; }, [desktopHomeComposerSlotId, heroComposerFromTablet]); @@ -1547,7 +1555,7 @@ export function MasterSearchHeader({ {searchComposerVisible ? ( <> {(desktopHomeComposerActive && desktopHomeComposerHost) || - (desktopHomeComposerSlotId && desktopHomeComposerMediaMatches) + (desktopHomeComposerSlotId && !desktopHomeComposerFallback) ? null : renderSearchComposer("default")} {desktopHomeComposerActive && desktopHomeComposerHost diff --git a/tests/ui-tools.spec.ts b/tests/ui-tools.spec.ts index 8b290e6b3..b40aa7903 100644 --- a/tests/ui-tools.spec.ts +++ b/tests/ui-tools.spec.ts @@ -454,6 +454,37 @@ test.describe("Clinical KB tools launcher", () => { } }); + // Required-gate guard for the bug class PR #456 fixed and then reintroduced in + // a narrower form: a mode-home page rendering with NO search composer at some + // width. Presence plus hero containment are asserted at the extreme widths on + // one dashboard-shell home and one standalone-shell home; the full 5-route + // design spec stays in the advisory "mode home routes center the shared + // search on mobile" test above. + test("mode home search composer is always present at phone and desktop widths @critical", async ({ page }) => { + test.setTimeout(120_000); + await mockAnswerDashboardApi(page); + + for (const viewport of [ + { name: "phone", width: 390, height: 820 }, + { name: "desktop", width: 1280, height: 900 }, + ] as const) { + await page.setViewportSize({ width: viewport.width, height: viewport.height }); + + for (const home of [ + { path: "/?mode=answer", testId: "answer-empty-state" }, + { path: "/services", testId: "services-home" }, + ] as const) { + await gotoLauncher(page, home.path); + await expect(page.getByTestId(home.testId)).toBeVisible(); + // The composer must never vanish: exactly one visible search input. + await expect(visibleGlobalSearchInput(page)).toHaveCount(1, { timeout: 15_000 }); + // Hero-centred design: the input lives inside the mode-home hero at + // every width, phones included. + await expect(page.getByTestId(home.testId).getByTestId("global-search-input")).toBeVisible(); + } + } + }); + test("all mode home heroes share identical sizing on mobile", async ({ page }) => { test.setTimeout(150_000); await mockAnswerDashboardApi(page); From df64b8f7724588fc0c4357bbc8892425598c9f74 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 11 Jul 2026 04:52:50 +0800 Subject: [PATCH 2/2] style: realign branch-review-ledger table after merge Co-Authored-By: Claude Fable 5 --- docs/branch-review-ledger.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 90812c7fe..3c80c1d5f 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -18,17 +18,17 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD ## Review Records -| Date | Branch or ref | Reviewed HEAD | Scope | Outcome | Checks | -| ---------- | ------------------------------------- | ---------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 2026-07-09 | example/branch | abc1234 | branch-cleanup | Example: already merged into `main`; no unique patch content. | `git log --right-only --cherry-pick main...example/branch`; `git diff --name-status main...example/branch` | -| 2026-07-10 | codex/pr-testing-streamlining | 155c801cd58f797037d8aaa8b885405a1c599249 | working-tree diff: PR testing streamlining | Changes requested: 2 P1 clinical-gate defects and 7 P2/P3 scope, local parity, and UI-process defects. | `npm run check:ci-scope`; `npm run check:github-actions`; `npm run check:codex-autofix-workflow`; `npm run eval:rag:offline`; `npm run test:e2e:critical`; targeted scope classifications; `git diff --check` | -| 2026-07-10 | codex/pr-testing-streamlining | 155c801cd58f797037d8aaa8b885405a1c599249 | working-tree remediation review | All recorded P1-P3 findings fixed; no remaining high-confidence issue in the changed scope. | `npm run verify:cheap`; `npm run verify:pr-local`; `npm run eval:rag:offline`; `npm run test:e2e:critical`; `npm run test:e2e:advisory`; CI YAML parse; scope/action/Codex guards; `git diff --check` | -| 2026-07-10 | codex/review-autofix-flow | 155c801cd58f797037d8aaa8b885405a1c599249 | codex-autofix-flow | Fixed exact connector authorization, trusted-marker deduplication, and strict self-trigger matching; added regression coverage. | `npm run check:codex-autofix-workflow`; focused Vitest (4 passed); `npm run verify:cheap` pre-test stages passed before tool timeout; `npm test` (1,415 passed, 1 skipped); focused Prettier check; `npm run check:github-actions` | -| 2026-07-10 | codex/review-autofix-flow | 155c801cd58f797037d8aaa8b885405a1c599249 | codex-autofix-flow-followup | Fixed untrusted workflow-level concurrency interference and migrated the bridge from the Node 20 action runtime to `actions/github-script@v9`; added direct embedded-script execution coverage. | Focused Vitest (13 passed); targeted ESLint; `tsc --noEmit`; `npm run check:codex-autofix-workflow`; `npm run check:github-actions`; focused Prettier check; `git diff --check` | -| 2026-07-10 | codex/review-autofix-flow | 155c801cd58f797037d8aaa8b885405a1c599249 | codex-autofix-residual-fixes | Replaced one-shot PR deduplication with a three-cycle head-SHA cap, made comment permission failures fail visibly, and pinned `github-script` v9.0.0 to its verified immutable commit. | TDD red run (7 expected failures); focused Vitest green run (15 passed); `npm run verify:cheap` (152 files passed, 1 skipped; 1,426 tests passed, 1 skipped); focused Prettier check; `git diff --check`; official `git ls-remote` tag verification | -| 2026-07-10 | codex/architecture-review-fixes | 648abfa3f7c91395b5eeca543f70e0b6ea59e9e0 | architecture-review | Seven findings fixed in the working tree: three runtime cycles, unbounded owner caches, a client/server env boundary breach, reversed runtime-to-scripts ownership, and architecture-doc drift. | `npm run test -- tests/architecture-boundaries.test.ts tests/bounded-ttl-cache.test.ts tests/rag-score.test.ts tests/rag-cache-utils.test.ts tests/rag-cache-invalidation.test.ts tests/evidence-panels.test.ts tests/clinical-dashboard-merge-artifacts.test.ts`; `npm run verify:cheap`; `npm run check:production-readiness:ci` | -| 2026-07-10 | codex/architecture-review-fixes | 648abfa3f7c91395b5eeca543f70e0b6ea59e9e0 | frontend-architecture-review | Shared cycle/env findings confirmed and fixed; three additional findings fixed for defeated lazy boundaries, duplicate shell/dashboard subscriptions, and unstable search-context values. | `npm run test -- tests/architecture-boundaries.test.ts tests/evidence-panels.test.ts tests/clinical-dashboard-merge-artifacts.test.ts`; `npm run verify:cheap`; UI gate deferred pending explicit local-API approval | -| 2026-07-11 | codex/architecture-review-integration | b45df727b29aad8ba4ec5d4e96d1f0599d7dad8a | branch-integration-review | Replayed the reviewed architecture fixes onto current `origin/main`; preserved current CI/autofix history and found no new high-confidence defect in the integrated diff. | `npm run check:runtime`; `npm run check:github-actions`; `npm run sitemap:check`; `npm run lint`; `npm run typecheck`; focused Vitest (24 passed); full Vitest with `--testTimeout=30000` (1,433 passed, 1 skipped); `git diff --check` | -| 2026-07-11 | codex/architecture-review-integration | 665103250ccc33b5870862b8d8467607a1ae5d23 | coderabbit-followup | Fixed POSIX project-root identity collisions and closed dynamic-import and self-cycle gaps in the architecture regression guard. | Local-server Vitest passed; architecture-boundaries Vitest passed (6 tests); `npm run typecheck`; focused Prettier; `git diff --check` | -| 2026-07-11 | codex/architecture-review-followup | f5deaaee98864f1d32c1060ae14966a4f5975872 | coderabbit-test-followup | Removed probabilistic no-collision assertions from the local identity test and replaced them with deterministic normalization, repeatability, ID-shape, and port-range checks. | Local-server Vitest (2 passed); focused Prettier; `git diff --check`; hosted CI/SAST/Secret Scan passed on the reviewed head | +| Date | Branch or ref | Reviewed HEAD | Scope | Outcome | Checks | +| ---------- | -------------------------------------- | ---------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 2026-07-09 | example/branch | abc1234 | branch-cleanup | Example: already merged into `main`; no unique patch content. | `git log --right-only --cherry-pick main...example/branch`; `git diff --name-status main...example/branch` | +| 2026-07-10 | codex/pr-testing-streamlining | 155c801cd58f797037d8aaa8b885405a1c599249 | working-tree diff: PR testing streamlining | Changes requested: 2 P1 clinical-gate defects and 7 P2/P3 scope, local parity, and UI-process defects. | `npm run check:ci-scope`; `npm run check:github-actions`; `npm run check:codex-autofix-workflow`; `npm run eval:rag:offline`; `npm run test:e2e:critical`; targeted scope classifications; `git diff --check` | +| 2026-07-10 | codex/pr-testing-streamlining | 155c801cd58f797037d8aaa8b885405a1c599249 | working-tree remediation review | All recorded P1-P3 findings fixed; no remaining high-confidence issue in the changed scope. | `npm run verify:cheap`; `npm run verify:pr-local`; `npm run eval:rag:offline`; `npm run test:e2e:critical`; `npm run test:e2e:advisory`; CI YAML parse; scope/action/Codex guards; `git diff --check` | +| 2026-07-10 | codex/review-autofix-flow | 155c801cd58f797037d8aaa8b885405a1c599249 | codex-autofix-flow | Fixed exact connector authorization, trusted-marker deduplication, and strict self-trigger matching; added regression coverage. | `npm run check:codex-autofix-workflow`; focused Vitest (4 passed); `npm run verify:cheap` pre-test stages passed before tool timeout; `npm test` (1,415 passed, 1 skipped); focused Prettier check; `npm run check:github-actions` | +| 2026-07-10 | codex/review-autofix-flow | 155c801cd58f797037d8aaa8b885405a1c599249 | codex-autofix-flow-followup | Fixed untrusted workflow-level concurrency interference and migrated the bridge from the Node 20 action runtime to `actions/github-script@v9`; added direct embedded-script execution coverage. | Focused Vitest (13 passed); targeted ESLint; `tsc --noEmit`; `npm run check:codex-autofix-workflow`; `npm run check:github-actions`; focused Prettier check; `git diff --check` | +| 2026-07-10 | codex/review-autofix-flow | 155c801cd58f797037d8aaa8b885405a1c599249 | codex-autofix-residual-fixes | Replaced one-shot PR deduplication with a three-cycle head-SHA cap, made comment permission failures fail visibly, and pinned `github-script` v9.0.0 to its verified immutable commit. | TDD red run (7 expected failures); focused Vitest green run (15 passed); `npm run verify:cheap` (152 files passed, 1 skipped; 1,426 tests passed, 1 skipped); focused Prettier check; `git diff --check`; official `git ls-remote` tag verification | +| 2026-07-10 | codex/architecture-review-fixes | 648abfa3f7c91395b5eeca543f70e0b6ea59e9e0 | architecture-review | Seven findings fixed in the working tree: three runtime cycles, unbounded owner caches, a client/server env boundary breach, reversed runtime-to-scripts ownership, and architecture-doc drift. | `npm run test -- tests/architecture-boundaries.test.ts tests/bounded-ttl-cache.test.ts tests/rag-score.test.ts tests/rag-cache-utils.test.ts tests/rag-cache-invalidation.test.ts tests/evidence-panels.test.ts tests/clinical-dashboard-merge-artifacts.test.ts`; `npm run verify:cheap`; `npm run check:production-readiness:ci` | +| 2026-07-10 | codex/architecture-review-fixes | 648abfa3f7c91395b5eeca543f70e0b6ea59e9e0 | frontend-architecture-review | Shared cycle/env findings confirmed and fixed; three additional findings fixed for defeated lazy boundaries, duplicate shell/dashboard subscriptions, and unstable search-context values. | `npm run test -- tests/architecture-boundaries.test.ts tests/evidence-panels.test.ts tests/clinical-dashboard-merge-artifacts.test.ts`; `npm run verify:cheap`; UI gate deferred pending explicit local-API approval | +| 2026-07-11 | codex/architecture-review-integration | b45df727b29aad8ba4ec5d4e96d1f0599d7dad8a | branch-integration-review | Replayed the reviewed architecture fixes onto current `origin/main`; preserved current CI/autofix history and found no new high-confidence defect in the integrated diff. | `npm run check:runtime`; `npm run check:github-actions`; `npm run sitemap:check`; `npm run lint`; `npm run typecheck`; focused Vitest (24 passed); full Vitest with `--testTimeout=30000` (1,433 passed, 1 skipped); `git diff --check` | +| 2026-07-11 | codex/architecture-review-integration | 665103250ccc33b5870862b8d8467607a1ae5d23 | coderabbit-followup | Fixed POSIX project-root identity collisions and closed dynamic-import and self-cycle gaps in the architecture regression guard. | Local-server Vitest passed; architecture-boundaries Vitest passed (6 tests); `npm run typecheck`; focused Prettier; `git diff --check` | +| 2026-07-11 | codex/architecture-review-followup | f5deaaee98864f1d32c1060ae14966a4f5975872 | coderabbit-test-followup | Removed probabilistic no-collision assertions from the local identity test and replaced them with deterministic normalization, repeatability, ID-shape, and port-range checks. | Local-server Vitest (2 passed); focused Prettier; `git diff --check`; hosted CI/SAST/Secret Scan passed on the reviewed head | | 2026-07-11 | claude/mobile-search-bar-fix (PR #456) | b73196c2e2e4a536804cdcdb50879c29e2c582c5 | PR required-testing review | All 4 Advisory UI regression failures confirmed PR-caused via A/B against pre-merge main (01f2cee0d): the 640px mode-home query moved the phone composer out of the hero, contradicting the design tests; residual ≥640px vanish remained when the slot never mounts. PR merged (b32c17b34) before the rework landed; follow-up fix shipped on `claude/mode-home-composer-hero-fix` (0px hero query restored, portal-outcome inline fallback, new `@critical` composer-presence test). Also found: main CI red on every push — missing `RAG_QUERY_HASH_SECRET` secret fails the deployment boot smoke and skips `release-browser-matrix`; owner adding the secret. | Local chromium A/B (PR head 4/5 fail vs baseline product-pass); rework targeted run 6/6 pass incl. new `@critical`; `npm run typecheck`; `npm run lint`; focused Prettier check |