Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/branch-review-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -645,3 +645,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD
| 2026-07-20 | origin/main PWA-surface review, window `ef042ca..e128384` (44+ commits; explicit user request) + phone install-sheet redesign (this branch, content commit d8d8c4a) | e1283846647b20cd49ca6ae6920a7c76f2b945d7 | PWA-version review of new progress + install-notification design elevation | Sweep verdict (agent-verified): only #905/#897 (this program's own work) touched PWA surfaces in the window — sw.js CACHE_VERSION `2026-07-18-v1` and its offline.html binding, manifest (7 icons incl. monochrome; screenshots deliberately absent), icons route, kill-switch, and next.config headers all unchanged, so the privacy contract holds by construction. Geometric risk from five composer/dock-space reworks (#933 mobile-composer-reserve, #932, #930, #922, #899) probed live at 390×844: the non-install notice stack keeps correct clearance at rest (offline card bottom 744/844 with the 5.5rem gutter) and the stack's offset is now a custom property (`--pwa-notice-bottom-gap`) for one-line re-anchoring if composer geometry moves again. Redesign: install prompt + iOS hint present as a native bottom sheet on phones (full-bleed, flush bottom, grip bar matching #935's sheet language, real app icon identity via /icons/icon-192, Free/no-store meta row, two accent step chips for Share→Add to Home Screen as aria-hidden reinforcement of the unchanged accessible sentence); ≥640px keeps the #905 card/toast placements; region names, button names, and test-locked sentences unchanged. | Focused vitest 56/56 across the four PWA suites; `verify:cheap` 2971/2975 (sole fail = known container-only pdf-extraction-budget artifact); `test:e2e:pwa` privacy/offline green (installability fail = known container `in-incognito` artifact); `verify:ui` 243 passed/2 failed (the two long-baselined container artifacts); production build + client-bundle secret scan + bundle budget within tolerance (1303.4 vs 1278.6 KiB baseline; sheet adds ~0 JS); visual evidence at 390 light/dark/iOS-hint + 768 + 1440 with bounding-box math (full-bleed flush-bottom on phone; card/toast intact above). No provider-backed checks run. |
| 2026-07-20 | Credentialed release-gate checkpoint closeout (workflow_dispatch on main `7ec25d9`; user-authorized ≤$10, single dispatch each) | 7ec25d9675dea13635fa4a895af88c93da694a42 | Credentialed half of the release gate: CI dispatch + live eval canary | CI dispatch: 9/10 jobs green (unit coverage, build, Chromium production journeys, migration replay on local Supabase emulator, production-readiness CI-safe, policy self-tests, static/safety/scope). `release-browser-matrix` (WebKit/Firefox) CANCELLED twice by main-churn: ci.yml `concurrency: CI-${ref}, cancel-in-progress: true` kills in-flight dispatch runs on every main push and this repo merges every few minutes — livelock confirmed at the 2-attempt cap; WebKit/iOS verification remains outstanding with three human options (quiet-window dispatch, the weekly scheduled run, or a one-line dedicated concurrency group for the matrix job — operational-risk change, not applied). Eval canary: golden retrieval eval FAILED 4/36 (document_recall@5 0.944, ndcg@10 0.923, force_embedding_failure_count 0, no 429s — vector layer healthy, NOT the documented vector-ptsd transient class); the July 17 dispatch PASSED this step pre-#901, so the regression window implicates #901's deterministic semantic reranking (lithium-therapy-monitoring shows three unrelated documents with byte-identical rerank scores burying the lithium guideline; two other failures add fixture-vs-corpus identity components; answer-quality subset — the July 17 failure — never ran). NO canary re-run per plan (deterministic, not transient); retrieval is clinical-path and deferred to a human decision. Provider spend ≈ $1–2 (one canary run's embeddings); matrix/CI runs $0. | actions_run_trigger dispatches + rerun_failed_jobs (attempt 2); job-level conclusions and log excerpts from runs 29675875530 (both attempts), 29675878737 (July 19 canary), and 29567502452 (July 17 baseline). No local provider calls; secrets never left GitHub Actions. |
| 2026-07-20 | claude/clinical-kb-pwa-review-asi3wb (restarted; PR: ci.yml concurrency) | 79aaacf04e64f753c480dd957a81ac9be6acbb43 | CI workflow concurrency: stop main churn cancelling dispatch/schedule runs | One-line group expression: workflow_dispatch/schedule events now get a per-run concurrency group (github.run_id) while push/PR keep the shared ref group with cancel-in-progress — fixes the release-browser-matrix livelock (cancelled twice on 2026-07-19/20 by main merges mid-run; the weekly Sunday 18:00 UTC scheduled run was subject to the same cancellation). release-browser-matrix is not a required branch-protection check; pin/scope checkers do not constrain the concurrency block. Accepted side effect: deliberate runs can overlap push runs. Rollback: plain revert. | check:github-actions PASS; check:ci-scope PASS; format:check PASS (repo files; local-only .claude/settings.local.json warning is gitignored) |
| 2026-07-20 | claude/clinical-kb-pwa-review-asi3wb (restarted; PR: #901 rerank regression closeout) | fd5dcd1582e1c7aa8bf92ff097575e0c68aa930d | #901 rerank regression: baseline re-eval + offline guard net + saturated-tie fix | Baseline eval-canary dispatch on remediated main b3ae061 (run 29731533081) PASSED — golden retrieval 36/36 + answer-quality green, confirming #913-#926 closed the live 4/36 regression (July 19 failing run tested the raw #901 state; fixes landed 1-8h after it, never re-evaled until now). Residual defect found by new offline repro and fixed: with byte-identical imputed fast-path primaries, selection's clamped keys tie exactly and the chunk-id fallback decides, which secondStageScore's position adjustment launders into releaseRankScore (buried the CIWA answer doc in repro); fix = contentRankScore carried on RetrievalCandidate as tie-break between clamped rerankScore and chunk id, never added to scores. Amended #901's own never-live-validated saturated-tie pin to content-rank-then-id. Guards: tests/rag-fast-path-ordering.test.ts (4 end-to-end eval-shape repros) + ranking-tuning gates (4 golden-mapped hard negatives at production weights + full-snapshot high-risk). Fixture aliases NOT changed (Step C not triggered — identity cases pass live). | Targeted 4-suite vitest 37/37; npm run test 2981 passed (sole fail = container-only pdf-extraction-budget artifact); verify:cheap green through all 18 pre-test checks incl. lint+typecheck; check:production-readiness PASS on substantive checks (2 FAILs = documented missing-secret class in this container); build + client-bundle scan + check:rag:fixtures PASS |
19 changes: 19 additions & 0 deletions src/lib/retrieval-selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,19 @@ export function buildRetrievalCandidates(
// rank already used rankScore; reusing the unbounded value here would compound boosts across
// passes and reintroduce the measured recall regression guarded below.
rerankScore: result.score_explanation?.finalScore ?? result.hybrid_score,
// Carried ONLY as the last tie-break before chunk id: on the embedding-free fast path,
// imputed primaries make clamped score/lexical/rerank ties routine, and a chunk-id tie-break
// is arbitrary — the second stage's position-based adjustment then launders that arbitrary
// winner into the released order. Never added to score. Note this rankScore is the full
// clinical rank, which includes the bounded source-governance metadata terms — deliberate
// for a tie-break: among otherwise-indistinguishable candidates it prefers the current,
// well-extracted document (the conservative direction), unlike governance WEIGHTING of the
// primary score, which the NOTE below still forbids.
contentRankScore:
result.score_explanation?.rankScore ??
result.score_explanation?.preClampFinalScore ??
result.score_explanation?.finalScore ??
result.hybrid_score,
matchedSignals: [],
sourceHref: documentCitationHref(citationFromResult(result)),
};
Expand Down Expand Up @@ -602,6 +615,12 @@ export function selectRetrievalEvidence(args: {
if ((right.lexicalScore ?? 0) !== (left.lexicalScore ?? 0))
return (right.lexicalScore ?? 0) - (left.lexicalScore ?? 0);
if ((right.rerankScore ?? 0) !== (left.rerankScore ?? 0)) return (right.rerankScore ?? 0) - (left.rerankScore ?? 0);
// Exact tie on every clamped key (routine on the embedding-free fast path, where imputed
// primaries are byte-identical and confidences saturate at 1.0): prefer the content-aware
// clinical rank over an arbitrary chunk-id ordering. This never raises any score — it only
// orders otherwise-indistinguishable candidates, so the measured clamped-score contract holds.
if ((right.contentRankScore ?? 0) !== (left.contentRankScore ?? 0))
return (right.contentRankScore ?? 0) - (left.contentRankScore ?? 0);
return left.chunkId.localeCompare(right.chunkId);
});
const selectedCandidates: RetrievalCandidate[] = [];
Expand Down
1 change: 1 addition & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ export type RetrievalCandidate = {
lexicalScore?: number;
semanticScore?: number;
rerankScore?: number;
contentRankScore?: number;
matchedSignals: string[];
sourceHref?: string;
};
Expand Down
Loading