Skip to content

Codify live retrieval RPCs, reclaim dead vector indexes, unify schema health - #117

Merged
BigSimmo merged 3 commits into
mainfrom
claude/sweet-mcclintock-9f3854
Jul 2, 2026
Merged

Codify live retrieval RPCs, reclaim dead vector indexes, unify schema health#117
BigSimmo merged 3 commits into
mainfrom
claude/sweet-mcclintock-9f3854

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

  • Fix retrieval reproducibility (critical): the five hybrid retrieval RPCs carried live-only performance fixes applied via raw SQL that were never captured in migrations, so a db reset/branch DB rebuilt the slow pre-fix retrieval layer. Migration 20260701140631_codify_live_retrieval_rpcs captures the live definitions (validated byte-equivalent to production via whitespace-stripped pg_get_functiondef md5 before applying — a confirmed behavioral no-op on live). supabase/schema.sql reconciled to match.
  • Reclaim ~4.4 GB dead index storage:20260702014803_drop_legacy_vector_indexes (applied live 2026-07-02 with explicit approval) drops the embedding_fields ivfflat (3.66 GB, 8 lifetime scans), chunks ivfflat (610 MB, duplicate of the serving HNSW), the never-used index_units HNSW (640 MB, 0 scans), and four 0-scan btrees. DB size 13 GB → 8.6 GB; health checks green after apply.
  • Unify search_schema_health():20260702021604 merges the two diverged lineages into one superset (comprehensive signature + 22 required-index checks + legacy-ivfflat report + hybrid-RPC zero-vector execution smoke). Applied live, ok:true.
  • Add missing 20260701000000_document_label_taxonomy_v2 file (already in live history).
  • Record the no-raw-SQL migration rule and remaining debts in docs/process-hardening.md.

Clinical governance preflight

Touches search/ranking + document access surface (SQL only; no app-code behavior change — all live applies verified as no-ops or index-only). Post-change golden evals against live: doc_recall@5 1.0 (up from 0.9 baseline), hit_rate 1.0, content_recall@5 0.9667 (one pre-existing-class lexical ranking case, tracked separately), latency p90 12.4s vs 20s budget, 0 latency failures. search_schema_health() execution smoke ok:true. Schema tests 27/27; typecheck clean.

🤖 Generated with Claude Code

BigSimmoand others added 3 commits July 2, 2026 09:59
The hybrid retrieval RPCs (match_document_chunks_hybrid,
_embedding_fields_hybrid, _index_units_hybrid, _memory_cards_hybrid +
its _v2 core) carried live-only performance fixes applied via raw SQL
that were never captured in migrations, so a db reset / branch DB
silently rebuilt the slow pre-fix retrieval layer.
- Add 20260701140631_codify_live_retrieval_rpcs: capture the live
definitions verbatim (validated byte-equivalent to production via
whitespace-stripped pg_get_functiondef md5 before applying; the live
apply was a confirmed behavioral no-op).
- Add 20260702014803_drop_legacy_vector_indexes (applied to live
2026-07-02 with explicit approval): drop ~4.4 GB of dead/duplicate
indexes - embedding_fields ivfflat 3.66 GB @ 8 scans, chunks ivfflat
610 MB, index_units HNSW 640 MB @ 0 scans, four 0-scan btrees.
DB size 13 GB -> 8.6 GB; search_schema_health() ok after apply.
- Add missing 20260701000000_document_label_taxonomy_v2 (already in
live migration history; file was absent from this branch).
- Sync supabase/schema.sql to the live RPC bodies and the live-kept
embedding_fields index set; intentionally no HNSW index on
document_index_units.embedding (text-gated RPC never used it).
- Update tests/supabase-schema.test.ts to pin the live shapes while
keeping historical assertions on the original migrations (27/27).
- Record the no-raw-SQL migration rule, verification evidence, and
follow-up debts in docs/process-hardening.md.
Post-change evals: doc_recall@5 1.0 (up from 0.9), hit_rate 1.0,
content_recall@5 0.9667 (one pre-existing-class lexical ranking case),
latency p90 12.4s vs 20s budget, zero latency failures.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The health function had diverged on two lineages: live carried the
hybrid-RPC execution smoke but lost the comprehensive required-index /
signature checks; the committed copy had the comprehensive checks but no
smoke. Migration 20260702021604 (applied live, verified ok:true) merges
both: 11 signature checks incl. match_document_memory_cards_hybrid_v2,
the full 22-entry required-index list updated for the index drops
(memory_cards HNSW added, index_units HNSW removed; all entries verified
present live first), the legacy-ivfflat report, and the zero-vector
execution smoke that catches silent runtime breaks like the historical
42702 regression. schema.sql matches exactly - the migration is
extracted from it, not re-typed. Schema tests 27/27.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@BigSimmo
BigSimmo merged commit aa0c3d4 into mainJul 2, 2026
2 checks passed
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Whole-table conflict in docs/outstanding-issues.md — main advanced 44
commits and gained rows while this PR sat open. Resolved by rebuilding
from main's current file and re-applying this branch's three changes,
not by taking either side: settling a whole-table conflict by picking a
side is the row-loss failure ledger #112 exists to make loud.
Renumbered the new row #117 -> #125. When this branch opened it, the
marker was 117; main's marker is now 125 and #117..#119 were reserved by
other sessions in the meantime, so keeping #117 would have collided with
a row someone else is about to add under that number. Ids are never
reused — renumber the incoming row above the marker and bump it.
Audited row-by-row against origin/main rather than eyeballed:
main rows: 119 resolved rows: 120
LOST from main: (none)
ADDED vs main: #125
MOVED table: #113 open->archive, #114 open->archive
duplicates: (none)
check:outstanding-issues: 120 rows (58 open, 62 archived), unique ids,
next-id=126 above the highest. verify:cheap exit 0, Tests 4493 passed |
4 skipped. format:check clean. `c2edda18` still absent from the file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FvU8z73P6TXUXoYBqN5K1P
BigSimmo added a commit that referenced this pull request Jul 30, 2026
docs(issues): archive #113 and #114, open #117 for the stale spec reference
BigSimmo added a commit that referenced this pull request Jul 30, 2026
Keep main's closed#115 and open #116. Remap this branch's ledger
additions to #117#119 and advance next-id past the reserved range.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
BigSimmo added a commit that referenced this pull request Jul 30, 2026
… PR babysitting (#1421)
* issues: capture two CI/merge operational findings from PR babysitting
#117: this repo's CI (on: pull_request with default types) doesn't
retrigger on the draft-to-ready transition, only on
opened/synchronize/reopened — a marked-ready PR can sit with a
minimal check set until an actual new commit lands. #118: GitHub's
update-branch API doesn't honor the merge=union .gitattributes driver
on docs/branch-review-ledger.md, so it can 422 with a false conflict
that a local git merge resolves cleanly. Both observed today on PR
#1406.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Re9ERtQwJ82ErbAnahAhsa
* Address Codex review: clarify ledger rows #125/#126 wording
#125: spell out that ready_for_review must be added alongside the
existing pull_request.types defaults, not replace them.
#126: qualify the update-branch fallback push with the same
explicit user confirmation the provider boundary already requires.
* docs(issues): capture #1396's unaddressed physical-device chrome gate
PR #1396 repeatedly declared physical-device Safari/PWA acceptance
(docs/phone-chrome-physical-acceptance.md) as required before merge
because headless Chromium cannot certify Safari chrome minimisation
or cold-launch PWA paint, then merged with the checklist still blank.
Also notes a related missing pre-paint/cold-load hydration test the
same PR's review flagged but never filed.
* style: fix table padding drift from the main merge
npx prettier --write after merging main (9e2fe44) — a table cell
width shifted during the merge and format:check would have caught it.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
Main's side carried #128-#130, archived #116 and reordered #117-#119, so it
is taken whole; only the #127 row is grafted from this branch, since main
still holds the withdrawn "sharedChromePinned is stuck" text. Marker stays
at main's 131. The file now reports `union merge active`, so this class of
collision should stop.
Also cross-links #130 into #127. PR #1396 ("overlay the phone header so
hiding it never moves content") merged at 06:49:55, about twenty minutes
before the first failure, and rewrote the exact overlay path this defect
sits in — phoneOverlayMotion, the overlay stack transition, and
readChromeCollapseMetrics charging zero released top geometry. Its merge
commit 90b3e34 is the single main run that passed, which fits the
passed-once-then-failed-twice-escalating shape better than the focus-latch
reading. #130 also records that #1396's own declared physical-device
prerequisite was never run, and that headless Chromium cannot certify what
it covers.
Verified after the merge: check:outstanding-issues 128 rows / unique ids /
next-id=131 / union merge active; check:branch-review-ledger 97 live + 1206
archived; prettier clean on all three changed files. Not re-run after the
merge: verify:cheap and the phone-scroll spec, which both passed on this
branch's own commit before it (434 test files / 4562 tests, and 56 passed).
The merge adds only main's already-verified tree plus one docs cell, so the
earlier evidence still covers this diff — but it is the earlier commit's
evidence, not this one's.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XrPbbfU9yWuEjEVypCr4ZQ
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
…line
#17 asked for the mobile breach to be ranked by measured contribution.
Done, and the measurement turned up something that changes what the work
costs.
Ran the local offline production Lighthouse harness over the same five
routes the live dispatch used. The mobile CLS numbers do not merely
correlate with production — they match run 30548662649 to three decimals
on all four locally measurable routes (0.023 / 0.142 / 0.220 / 0.363),
and the desktop range matches at both endpoints (0.016-0.097). /forms
did not measure locally (Lighthouse NO_NAVSTART, its own "run again"
transient); live it was 0.212.
So CLS on these routes is deterministic layout structure, not network or
production data. The CLS half of #17 is debuggable and gate-able locally
at zero provider cost, and #17's recorded premise that production vitals
need Supabase secrets is stale — run-lighthouse-budget.mjs builds and
serves an offline production app precisely to sidestep that. Its earlier
"dev-mode CLS is excellent at 0.00-0.04" note was measuring dev, which
does not reproduce production.
LCP does NOT reproduce and must not be read from local runs: 2014-2051 ms
local against 3639-4716 ms live, because the loopback server has no
network latency. The LCP ranking does survive — /therapy-compass is the
outlier both locally and live — which corroborates #117.
Filed as #147 with the ranking (/dsm 0.363 worst, then /documents/search
0.220, /forms 0.212, /therapy-compass 0.142, / 0.023 passing) and the
next step: Lighthouse's layout-shift-elements audit returned zero items
on every route, so element attribution needs a PerformanceObserver on
layout-shift against the same offline build.
Two reproduction traps recorded with it: the harness reads CHROME_PATH
but nothing in this container sets it, so chrome-launcher fails on every
route; and a truncated `progress` package in the npx cache broke
Lighthouse startup entirely. No budget baseline was committed — the
grader correctly refused this run as incomplete evidence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
BigSimmo added a commit that referenced this pull request Jul 30, 2026
…ation, restore #105 after an upstream deletion (#1459)
* docs(issues): record #105's preconnect verification in a browser
The preconnect half of #105 is verified; the LoadingPanel half is not, and the
row now says which is which rather than carrying one PENDING for both.
Worth recording how it was verified, because the obvious check silently proves
nothing: locally NEXT_PUBLIC_SUPABASE_URL is unset, so supabaseOrigin() returns
null and the layout renders no link at all. Loading the app and finding no
preconnect would have looked like a failure and been an absent fixture. The
check needs a placeholder origin (no real network call — the point is React's
hoisting, not Supabase connectivity).
With that set, both the SSR HTML and the live browser DOM show preconnect and
dns-prefetch in <head> with zero stray preconnect in <body>, so React 19 does
hoist them out of the body where they are authored.
survives the hoist, which matters: without it supabase-js's CORS fetches open a
second connection and the hint buys nothing.
The remaining half needs a different technique. A LoadingPanel fallback only
renders while a lazy chunk is in flight, so it needs a throttled-network browser
check rather than verify:ui, which would race past it.
Gates: outstanding-issues guard 142 rows / unique ids; prettier clean; the edit
is a 1-line diff because it stays inside the Detail column's existing width
(1133 chars against a 3268 budget) — see #133 for why that matters in this file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs(issues): record #17's live Web-Vitals verdict — mobile breaches
Dispatched live-web-vitals.yml against psychiatry.tools (run 30548662649,
5 routes x 3 samples). #17 has been the gate on seven latency findings for
weeks with no evidence behind it. It now has evidence, and it is a breach.
Mobile medians against LCP<2500ms / CLS<0.1:
root 4308ms 0.023
therapy-compass 4716ms 0.142
documents-search 3676ms 0.220
dsm 3639ms 0.363
forms 3786ms 0.212
Desktop passes everywhere (LCP 625-694ms, CLS 0.016-0.097), which is worth
noting because desktop-only checking would have concluded the opposite.
The verdict is gradeable rather than noisy: every LCP sample range sits wholly
above 2500ms, so the straddle rule #114 added does not fire. That distinction is
the whole point of #1407's sampling work — a single run per cell could not have
told a real breach from variance.
Applying the rule as written before the numbers were read: any breach makes only
the breaching routes' findings actionable, and NOTHING becomes WONTFIX. That is
the opposite of what a favourable sample would have produced, which is exactly
why the rule was written first.
CLS 0.363 on /dsm is the worst single number and is visible layout shift, not a
byte-count problem — so it is not addressed by the payload findings #17 gates.
Recorded honestly as one step short of complete: this reads the summariser's
emitted table, not the raw Lighthouse JSON (artifact 8762211043, 30-day
retention). The row itself asks for that cross-check before recording a verdict,
most of all a PASS; this is a breach, so the risk of the table flattering the
result is lower, but the check is still outstanding. INP is absent because
Lighthouse cannot measure it in lab conditions.
Diff stays 1 line: #17's Detail cell is 2184 chars against the column's 3268
budget, so nothing repads (see #133).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs(issues): withdraw the #105 LoadingPanel verification — it matched the wrong component
The claim that `LoadingPanel` was verified present in the SSR response HTML
does not hold, so #105 is reopened rather than archived.
The evidence was `role="status" aria-label="Loading"` appearing in the
initial HTML of `/`, `/dsm` and `/forms`. Those hits are real, but that
exact string has exactly one renderer in `src/` — `ModeHomePageSkeleton`
(`src/components/mode-home-page-skeleton.tsx:8`). `LoadingPanel` never
emits a bare "Loading" label; it renders `aria-label={label}`, always a
specific string such as "Loading differentials". Re-checked per route
against a running server, `/`, `/dsm`, `/forms`, `/differentials` and
`/favourites` return zero `aria-label="Loading <something>"` matches.
Codex's mechanism finding on this PR stands and is not what failed: the
installed Next 16 loader does set `hasSuspenseBoundary` when a `loading`
element is supplied, and `BailoutToCSR` throws on the server, so a mounted
`ssr:false` surface emits its fallback into the response HTML. What was
missing is that this only fires for a surface mounted during the initial
render, and none of the eleven in `clinical-dashboard-lazy.tsx` are —
every one sits behind interaction state (`ClinicalDashboard.tsx:3666-4070`).
So neither a cold-load grep nor the throttled check the row originally
prescribed can observe them; that needs a driven browser session.
The reopened row and its queue entry both record the withdrawn claim and
carry an explicit stop rule against re-closing on a cold-load grep. The
preconnect half remains verified and is marked so, to avoid redoing it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs(issues): rank #17's mobile findings — CLS reproduces exactly offline
#17 asked for the mobile breach to be ranked by measured contribution.
Done, and the measurement turned up something that changes what the work
costs.
Ran the local offline production Lighthouse harness over the same five
routes the live dispatch used. The mobile CLS numbers do not merely
correlate with production — they match run 30548662649 to three decimals
on all four locally measurable routes (0.023 / 0.142 / 0.220 / 0.363),
and the desktop range matches at both endpoints (0.016-0.097). /forms
did not measure locally (Lighthouse NO_NAVSTART, its own "run again"
transient); live it was 0.212.
So CLS on these routes is deterministic layout structure, not network or
production data. The CLS half of #17 is debuggable and gate-able locally
at zero provider cost, and #17's recorded premise that production vitals
need Supabase secrets is stale — run-lighthouse-budget.mjs builds and
serves an offline production app precisely to sidestep that. Its earlier
"dev-mode CLS is excellent at 0.00-0.04" note was measuring dev, which
does not reproduce production.
LCP does NOT reproduce and must not be read from local runs: 2014-2051 ms
local against 3639-4716 ms live, because the loopback server has no
network latency. The LCP ranking does survive — /therapy-compass is the
outlier both locally and live — which corroborates #117.
Filed as #147 with the ranking (/dsm 0.363 worst, then /documents/search
0.220, /forms 0.212, /therapy-compass 0.142, / 0.023 passing) and the
next step: Lighthouse's layout-shift-elements audit returned zero items
on every route, so element attribution needs a PerformanceObserver on
layout-shift against the same offline build.
Two reproduction traps recorded with it: the harness reads CHROME_PATH
but nothing in this container sets it, so chrome-launcher fails on every
route; and a truncated `progress` package in the npx cache broke
Lighthouse startup entirely. No budget baseline was committed — the
grader correctly refused this run as incomplete evidence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF
* docs(review): record PR 1459 final reconciliation
---------
Co-authored-by: Claude <noreply@anthropic.com>
BigSimmo pushed a commit that referenced this pull request Aug 12, 2026
…re-scope the wave plan
Archived with source evidence:
- #166 the verify-before-use caveat ships (verification-notice.tsx:52, rendered
unconditionally by AnswerCard at answer-card.tsx:108). I reported this row as
open twice before reading the code; the archive says so.
- #208 buildAnswerClipboardText composes renderCopyText rather than replacing
formatAnswerRenderCopyText (answer-copy-payload.ts:121-138).
- #216 AnswerCard is adopted on the answer surface and the manifest agrees.
Re-scoped #250: its wave plan names A1 rows that are now closed and hygiene
rows that are in flight, so as written it misdirects. Recorded what actually
remains (#147, #117, #118, #98, #189).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017paT42ZVMf8jaLtkjFxdy5
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@BigSimmo