From ba812925e2ebd1ded746d1233965bac645ac7822 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sun, 19 Jul 2026 18:09:41 +0800 Subject: [PATCH 1/4] fix(rag): retain live hybrid fallback --- src/lib/rag.ts | 11 +++++------ tests/rag-second-stage-ranking.test.ts | 8 ++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/lib/rag.ts b/src/lib/rag.ts index f3183a125..9b0cb513a 100644 --- a/src/lib/rag.ts +++ b/src/lib/rag.ts @@ -564,12 +564,13 @@ function resultsHaveReleaseRankScore(results: SearchResult[]) { * * App-layer rank scores remain available to answer evidence ranking and telemetry, but the * live corpus gate has not validated using them as the final retrieval order. Resolve duplicate - * chunks to their strongest released-hybrid copy. Distinct results keep the clinical selection's - * existing order unless `preferSecondStageScore` is enabled and the current set carries bounded - * second-stage release scores. + * chunks to their strongest released-hybrid copy. When second-stage ordering was requested but the + * final set has no valid release scores, distinct results keep the clinical selection's existing + * order. Otherwise they use the live-proven raw-hybrid or bounded second-stage order. */ export function stabilizeReleasedSearchOrder(results: SearchResult[], preferSecondStageScore = false) { const useSecondStageReleaseOrder = preferSecondStageScore && resultsHaveReleaseRankScore(results); + const preserveCurrentOrder = preferSecondStageScore && !useSecondStageReleaseOrder; const compareReleasedHybridStrength = (left: SearchResult, right: SearchResult) => { const leftHybrid = left.hybrid_score ?? left.similarity ?? 0; const rightHybrid = right.hybrid_score ?? right.similarity ?? 0; @@ -602,9 +603,7 @@ export function stabilizeReleasedSearchOrder(results: SearchResult[], preferSeco if (!current || compareReleasedHybridStrength(result, current) < 0) strongestById.set(result.id, result); } const distinctResults = [...strongestById.values()]; - const releasedResults = useSecondStageReleaseOrder - ? distinctResults.sort(compareReleasedSearchOrder) - : distinctResults; + const releasedResults = preserveCurrentOrder ? distinctResults : distinctResults.sort(compareReleasedSearchOrder); const deduped = releasedResults.map((result, index) => result.score_explanation ? { ...result, score_explanation: { ...result.score_explanation, finalRank: index + 1 } } diff --git a/tests/rag-second-stage-ranking.test.ts b/tests/rag-second-stage-ranking.test.ts index a19c8be40..97f400043 100644 --- a/tests/rag-second-stage-ranking.test.ts +++ b/tests/rag-second-stage-ranking.test.ts @@ -229,7 +229,7 @@ describe("second-stage rank score", () => { expect(stabilized.map((item) => item.score_explanation?.finalRank)).toEqual([1, 2]); }); - it("ignores sticky second-stage preference when the final result set has no releaseRankScore", () => { + it("preserves sticky second-stage order while retaining raw-hybrid fallback when release scores are absent", () => { const clinicallyOrdered = [ result({ id: "lithium-monitoring", @@ -255,6 +255,10 @@ describe("second-stage rank score", () => { expect(stabilized.map((item) => item.id)).toEqual(["lithium-monitoring", "cardiac-dose"]); expect(stabilized[0].content).toBe("Stronger released-hybrid copy of the lithium evidence."); expect(stabilized.map((item) => item.score_explanation?.finalRank)).toEqual([1, 2]); + + const hybridFallback = stabilizeReleasedSearchOrder([...clinicallyOrdered], false); + expect(hybridFallback.map((item) => item.id)).toEqual(["cardiac-dose", "lithium-monitoring"]); + expect(hybridFallback[1].content).toBe("Stronger released-hybrid copy of the lithium evidence."); }); it("only applies bounded release ordering when the current result set carries releaseRankScore", () => { @@ -274,7 +278,7 @@ describe("second-stage rank score", () => { "hybrid-leading", ]); expect(stabilizeReleasedSearchOrder([withReleaseScore, withoutReleaseScore], false).map((item) => item.id)).toEqual( - ["release-ranked", "hybrid-leading"], + ["hybrid-leading", "release-ranked"], ); }); From f7c48618c13010c3d8ff521a0578a907651ff303 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sun, 19 Jul 2026 18:17:29 +0800 Subject: [PATCH 2/4] fix(rag): gate release score comparator --- src/lib/rag.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/lib/rag.ts b/src/lib/rag.ts index 9b0cb513a..87a0f7ff5 100644 --- a/src/lib/rag.ts +++ b/src/lib/rag.ts @@ -583,12 +583,14 @@ export function stabilizeReleasedSearchOrder(results: SearchResult[], preferSeco return left.id.localeCompare(right.id); }; const compareReleasedSearchOrder = (left: SearchResult, right: SearchResult) => { - const leftReleaseScore = isBoundedReleaseRankScore(left.score_explanation?.releaseRankScore) - ? left.score_explanation.releaseRankScore - : (left.hybrid_score ?? left.similarity ?? 0); - const rightReleaseScore = isBoundedReleaseRankScore(right.score_explanation?.releaseRankScore) - ? right.score_explanation.releaseRankScore - : (right.hybrid_score ?? right.similarity ?? 0); + const leftReleaseScore = + useSecondStageReleaseOrder && isBoundedReleaseRankScore(left.score_explanation?.releaseRankScore) + ? left.score_explanation.releaseRankScore + : (left.hybrid_score ?? left.similarity ?? 0); + const rightReleaseScore = + useSecondStageReleaseOrder && isBoundedReleaseRankScore(right.score_explanation?.releaseRankScore) + ? right.score_explanation.releaseRankScore + : (right.hybrid_score ?? right.similarity ?? 0); if (rightReleaseScore !== leftReleaseScore) return rightReleaseScore - leftReleaseScore; const leftSimilarity = left.similarity ?? 0; const rightSimilarity = right.similarity ?? 0; From 14149d23f2a36ff88341888f31205b0cdbdfee60 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Jul 2026 10:19:40 +0000 Subject: [PATCH 3/4] fix(rag): restore raw-hybrid fallback and preserve semantic rerank order When second-stage release ordering is not active, sort stabilized results by raw hybrid strength instead of releaseRankScore. Preserve incoming order when semantic rerank has reordered a result set without bounded release scores. Co-authored-by: BigSimmo --- src/lib/rag.ts | 19 +++++++++++++++---- tests/rag-second-stage-ranking.test.ts | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/lib/rag.ts b/src/lib/rag.ts index 87a0f7ff5..1ddd1aa26 100644 --- a/src/lib/rag.ts +++ b/src/lib/rag.ts @@ -568,9 +568,14 @@ function resultsHaveReleaseRankScore(results: SearchResult[]) { * final set has no valid release scores, distinct results keep the clinical selection's existing * order. Otherwise they use the live-proven raw-hybrid or bounded second-stage order. */ -export function stabilizeReleasedSearchOrder(results: SearchResult[], preferSecondStageScore = false) { +export function stabilizeReleasedSearchOrder( + results: SearchResult[], + preferSecondStageScore = false, + preserveIncomingOrder = false, +) { const useSecondStageReleaseOrder = preferSecondStageScore && resultsHaveReleaseRankScore(results); - const preserveCurrentOrder = preferSecondStageScore && !useSecondStageReleaseOrder; + const preserveCurrentOrder = + preserveIncomingOrder || (preferSecondStageScore && !useSecondStageReleaseOrder); const compareReleasedHybridStrength = (left: SearchResult, right: SearchResult) => { const leftHybrid = left.hybrid_score ?? left.similarity ?? 0; const rightHybrid = right.hybrid_score ?? right.similarity ?? 0; @@ -605,7 +610,11 @@ export function stabilizeReleasedSearchOrder(results: SearchResult[], preferSeco if (!current || compareReleasedHybridStrength(result, current) < 0) strongestById.set(result.id, result); } const distinctResults = [...strongestById.values()]; - const releasedResults = preserveCurrentOrder ? distinctResults : distinctResults.sort(compareReleasedSearchOrder); + const releasedResults = preserveCurrentOrder + ? distinctResults + : useSecondStageReleaseOrder + ? distinctResults.sort(compareReleasedSearchOrder) + : distinctResults.sort(compareReleasedHybridStrength); const deduped = releasedResults.map((result, index) => result.score_explanation ? { ...result, score_explanation: { ...result.score_explanation, finalRank: index + 1 } } @@ -634,7 +643,9 @@ function recordSearchScoreTelemetry(telemetry: SearchTelemetry, results: SearchR const useSecondStageReleaseOrder = resultsHaveReleaseRankScore(results); telemetry.second_stage_rerank_used = useSecondStageReleaseOrder; - stabilizeReleasedSearchOrder(results, useSecondStageReleaseOrder); + const preserveSemanticRerankOrder = + telemetry.semantic_rerank_outcome === "reordered" && !useSecondStageReleaseOrder; + stabilizeReleasedSearchOrder(results, useSecondStageReleaseOrder, preserveSemanticRerankOrder); const coverageScores = results .map((result) => Math.max(0, result.hybrid_score ?? result.similarity ?? 0)) .sort((left, right) => right - left); diff --git a/tests/rag-second-stage-ranking.test.ts b/tests/rag-second-stage-ranking.test.ts index 97f400043..f003bc518 100644 --- a/tests/rag-second-stage-ranking.test.ts +++ b/tests/rag-second-stage-ranking.test.ts @@ -282,6 +282,26 @@ describe("second-stage rank score", () => { ); }); + it("preserves semantic rerank order when release scores are absent", () => { + const semanticallyOrdered = [ + result({ + id: "semantic-first", + hybrid_score: 0.7, + score_explanation: explanation(0.7), + }), + result({ + id: "semantic-second", + hybrid_score: 0.9, + score_explanation: explanation(0.9), + }), + ]; + + expect(stabilizeReleasedSearchOrder([...semanticallyOrdered], false, true).map((item) => item.id)).toEqual([ + "semantic-first", + "semantic-second", + ]); + }); + it("preserves clinical order when releaseRankScore values are not finite", () => { const clinicallyOrdered = [ result({ From 9152ca62d7200fdb6e048d2b76546faee4f76326 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sun, 19 Jul 2026 18:21:20 +0800 Subject: [PATCH 4/4] style(rag): format fallback ordering --- src/lib/rag.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib/rag.ts b/src/lib/rag.ts index 1ddd1aa26..75708202c 100644 --- a/src/lib/rag.ts +++ b/src/lib/rag.ts @@ -574,8 +574,7 @@ export function stabilizeReleasedSearchOrder( preserveIncomingOrder = false, ) { const useSecondStageReleaseOrder = preferSecondStageScore && resultsHaveReleaseRankScore(results); - const preserveCurrentOrder = - preserveIncomingOrder || (preferSecondStageScore && !useSecondStageReleaseOrder); + const preserveCurrentOrder = preserveIncomingOrder || (preferSecondStageScore && !useSecondStageReleaseOrder); const compareReleasedHybridStrength = (left: SearchResult, right: SearchResult) => { const leftHybrid = left.hybrid_score ?? left.similarity ?? 0; const rightHybrid = right.hybrid_score ?? right.similarity ?? 0; @@ -643,8 +642,7 @@ function recordSearchScoreTelemetry(telemetry: SearchTelemetry, results: SearchR const useSecondStageReleaseOrder = resultsHaveReleaseRankScore(results); telemetry.second_stage_rerank_used = useSecondStageReleaseOrder; - const preserveSemanticRerankOrder = - telemetry.semantic_rerank_outcome === "reordered" && !useSecondStageReleaseOrder; + const preserveSemanticRerankOrder = telemetry.semantic_rerank_outcome === "reordered" && !useSecondStageReleaseOrder; stabilizeReleasedSearchOrder(results, useSecondStageReleaseOrder, preserveSemanticRerankOrder); const coverageScores = results .map((result) => Math.max(0, result.hybrid_score ?? result.similarity ?? 0))