From 3f8b3f9c8185bd2fb26f953b7e60672576cb327a Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 11:44:22 +0000 Subject: [PATCH 1/2] fix(answer): stop neighbouring source marks stealing each other's taps Each in-prose source mark has a 48px invisible tap square centred on it. In a cluster the squares overlapped and the later mark painted last, so a tap on the centre of mark 1 opened source 2 (measured on a phone-width page before the change). Sides between two marks now stop halfway across the gap; outer sides and the full height keep the tap size. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01VkKjYakMrMXofU8foQCgbq --- src/app/globals.css | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index 73895aef56..a0306ef76f 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -2785,17 +2785,29 @@ html[data-motion="reduced"] .shared-compare-tray-layer[data-scroll-hidden="true" /* The tap area. The box above is ~18px, far under the 48px tap rule, and it cannot grow without growing the line box. This invisible square, centred on the mark, takes the tap instead: absolutely positioned, so it changes neither the visible - size nor the text flow (audit D05, 2026-10-13). Adjacent marks in a cluster - overlap here; the later mark paints last and takes a tap in the overlap, which - still opens a source of that same sentence. */ + size nor the text flow (audit D05, 2026-10-13). + + Inside a cluster the squares used to overlap and the later mark painted last, so + a tap on the right half of "1" opened source 2. Now each side between two marks + stops halfway across the gap, so every tap lands on the mark drawn under the + finger. Only the outer sides of a cluster reach out to the full tap width; the + full height stays on every mark. */ .answer-source-mark::before { content: ""; position: absolute; - left: 50%; top: 50%; - width: max(100%, var(--spacing-tap)); + left: calc(-1 * max(0px, (var(--spacing-tap) - 100%) / 2)); + right: calc(-1 * max(0px, (var(--spacing-tap) - 100%) / 2)); height: var(--spacing-tap); - transform: translate(-50%, -50%); + transform: translateY(-50%); +} + +.answer-source-mark + .answer-source-mark::before { + left: calc(-0.5 * var(--answer-mark-gap)); +} + +.answer-source-mark:has(+ .answer-source-mark)::before { + right: calc(-0.5 * var(--answer-mark-gap)); } /* The partial-support glyph. One glyph reads at this size; a dotted underline From 2ffd7dd9792e6767467776e64458ce6bd12066a5 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 12:12:38 +0000 Subject: [PATCH 2/2] fix(rag): stop the 30 s admin-client deadline cutting off keyword search PR #3454 (11 Oct) gave the shared service-role client a 30 s default. The keyword RPC can take 30-48 s on the live corpus, so it aborted and returned nothing for 9 of the 36 golden cases in every eval canary since 11 Oct (none on 4 Oct). Search then leaned on vector and table facts, and 'alcohol CIWA threshold' lost the Alcohol Withdrawal guideline from its top 10. The search path now uses the unbounded client again and keeps the caller's own abort signal, exactly as before #3454. Approved by the owner on 15 Oct 2026, with a live canary pair to follow. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01VkKjYakMrMXofU8foQCgbq --- src/lib/rag/rag.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/rag/rag.ts b/src/lib/rag/rag.ts index 724ea4f9c3..1a3f85458b 100644 --- a/src/lib/rag/rag.ts +++ b/src/lib/rag/rag.ts @@ -1148,7 +1148,11 @@ async function searchChunksWithTiming( recordSearchScoreTelemetry(telemetry, []); return finishSearch(searchTiming, { results: [] as SearchResult[], telemetry }); } - const supabase = createAdminClient(); + // No client-side deadline here. PR #3454 (11 Oct 2026) gave the shared admin client a + // 30 s default, and the keyword RPC can take 30-48 s on the live corpus, so it was + // aborted and returned nothing for 9 of the 36 golden cases (eval canaries from 11 Oct). + // Search keeps the caller's own abort signal, as it did before that change. + const supabase = createAdminClient({ timeoutMs: null }); // Source-only retrieval never calls embeddings. const sourceOnlyRetrieval = isSourceOnlyMode(); if (args.forceEmbedding && sourceOnlyRetrieval) {