Reconcile search_schema_health index drift on live Supabase - #266
Closed
BigSimmo wants to merge 2 commits into
Closed
Reconcile search_schema_health index drift on live Supabase#266BigSimmo wants to merge 2 commits into
BigSimmo wants to merge 2 commits into
Conversation
- Degrade invalid bearer tokens to anonymous scope instead of 401 - Allow public document read routes (list, detail, signed-url, search, images) - Align registry routes with medications/differentials auth-signal short-circuit - Let DocumentViewer load public sources without requiring sign-in - Add regression tests and update access-control expectations
Create missing retrieval-support indexes (trgm, composite btree, partial miss log) that were absent or only present under legacy names on live. Update search_schema_health() to accept verified functional equivalents during rollout. Set search_path for pg_trgm gin_trgm_ops in extensions. Verified on linked project: search_schema_health() ok=true, missing=[].
|
Updates to Preview Branch (cursor/reconcile-search-health-indexes-5f13) ↗︎
Tasks are run on every commit but only new migration files are pushed.
View logs for this Workflow Run ↗︎. |
3 tasks
Owner
Author
|
Superseded by #269 (consolidated platform fixes branch). |
BigSimmo
added a commit
that referenced
this pull request
Aug 8, 2026
…sured (#1719) * docs(issues): correct the re-measured A3 scope and B1 adoption count Replays a correction stranded in a local-only worktree when PR #1712 squash-merged and its branch was deleted before the commit could be pushed. Both figures were re-measured today against origin/main 2675e6e rather than copied forward, and one claim in the stranded version turned out to be wrong. #262: legacyShadowAliases counts SEVEN tokens, not one and not eight — the regex has matched tight|card|soft|hover|elevated|lux|lift since PR #1616 and has never included focus. Measured total 228 = tight 100, soft 72, elevated 17, hover 17, card 12, lux 8, lift 2. So --shadow-tight is 100 production sites across 55 files rather than the 155 or 229 previously recorded, clearing all 100 will not zero the ratchet, and #261's --shadow-focus does not appear in this metric at all. #266: adoption is 23 unadopted, not 24, since Button moved via #263 — its sole production importer is src/components/AccessibleTable.tsx. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(design-system): mark the TextField/SearchField/Select row done, it was stale Replays a correction stranded in a local-only worktree when PR #1712 squash-merged and its branch was deleted before the commit could be pushed. Re-measured today against origin/main 2675e6e: all three fold onto FormField, which renders hint AND error unconditionally (form-field.tsx:131-132) and merges aria-describedby caller -> hint -> error (form-field.tsx:107-109); TextField and SearchField each take an external id and a Ref<HTMLInputElement>, Select an external id and a Ref<HTMLSelectElement>. Landed in PR 13, not the PR 7 the row pointed at. Section 4's 'Do: fold TextField/SearchField/Select/Checkbox/RadioGroup onto this shell (PR 7)' was stale in a second way and is corrected too: Checkbox and RadioGroup deliberately do NOT fold onto FormField — a group keeps fieldset/legend and composes FieldHint/FieldError directly (choice.tsx:207-210). Left as written, that line asks a future session to 'finish' a fold that is finished and to break one that was a deliberate decision. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: correct future-dated re-measurement records to 2026-08-08 Codex review on PR #1719 flagged SCOPE/COUNT RE-MEASURED and COMPONENTS.md rows dated 2026-08-09 while the recording commits were authored on 2026-08-08. Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com> * docs(design-system): separate FormField integration from product adoption, re-measure the ui-primitives row Two review findings on PR #1719, both valid. Section 4 said 'Select/choice controls remain separate adoption work', which contradicted the section above it and was wrong on both axes for Select: select.tsx consumes FormField (folded in PR 13), and adoption-manifest.json gives Select 2 production importers, so it is adopted. The genuinely unadopted member of the trio is SearchField, at zero, which the sentence did not mention. Rewritten to state the two axes explicitly — integration is complete for TextField, SearchField and Select, and deliberately declined for Checkbox/RadioGroup; adoption is measured TextField 3, Select 2, SearchField/Checkbox/RadioGroup 0 — so a control cannot be read as pending on one axis because it is pending on the other. The ui-primitives row carried three stale figures. Re-measured on this head: the module is 698 lines, not 686; 157 production files import it, not 200 — that figure is 202 including mockups, the same mockup-inclusive mislabelling this PR already corrects for the shadow aliases; and 30 of the 53 registered components are adopted, not 27. Future-dated 2026-08-09 records were already corrected to 2026-08-08 by f3a91c6 before this commit; verified none remain under docs/. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <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
Aug 12, 2026
…system rows Archived as verified-delivered or duplicate: #303, #284 (dup of #296), #149, #159, #286, #287, #288, #256, #261, #291. Re-scoped with re-measured evidence: #210 (gate was never missing; the defect is the .next/dev types include), #262 (aliases 228 -> 193), #266 (counts moved, 23 unadopted holds), #275 (premise 'only one implementation' is false — the values leaked to five files). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017paT42ZVMf8jaLtkjFxdy5
BigSimmo
pushed a commit
that referenced
this pull request
Aug 12, 2026
… rows Repairs. Two main-merges silently reverted edits from this branch, and the re-apply script missed them because it was hand-enumerated from round 1's second commit only: - #293 the entire min-h-tap refutation was gone (grep sm:min-h-0 returned 0); the row was back to asserting a defect that does not exist. Restored from a6bfc6f. This was the live hazard — as reverted it directed a reader to strip desktop step-downs and pin every control to 48px. - #266 restored the 2026-08-12 counts (54/31/23) over main's older 53/30/23. - #262 deliberately NOT restored: main's version is newer than mine and records --shadow-tight retired outright on 2026-08-10. - #289 archived; verified fixed in round 1 and never actually closed. Stamps. Sixteen rows were checked during the sweep, found correct, and left unchanged — which left no trace, so they were indistinguishable from rows nobody had opened. Each now carries VERIFIED CORRECT 2026-08-12 plus the measurement that settled it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017paT42ZVMf8jaLtkjFxdy5
BigSimmo
added a commit
that referenced
this pull request
Aug 18, 2026
* feat(ui): one category-identity registry for card glyphs and accents Icons and category colour were spread across ten independent maps and two of them disagreed, so the same tool rendered differently depending on which screen reached it. - `launcherIconById` (applications-launcher-page.tsx) carried 13 tool ids; `iconByToolId` (tools-search-results-page.tsx) carried 8 with a different fallback, so `guidelines`, `care-plans`, `safety-plan`, `calculators` and `monitoring` showed a real glyph on the launcher and a generic `Grid2X2` in search results. - Colour diverged the same way: the launcher tinted by tool area, the results page painted every tile `--type-source`, so one list read as a single purple family while the other grouped the same tools into five. - `ShieldCheck` was assigned to `guidelines`, to `risk-safety`, and to the "Source-backed" status chip — three unrelated meanings, one glyph, reachable on a single card. - `appIconTone` overrode the area map per id, routing `differentials` and `forms` to a tone key named `differentials`, so the advertised "category colour" was not a category colour. `src/lib/category-identity.ts` is now the single source of truth. It is framework-free (string glyph keys, no lucide) following the `semantic-tone.ts` precedent, so data and server modules can name a glyph without the render layer; `category-identity-icons.ts` is the only place that binds keys to components, resolving through `createElement` as `factsheets-icons.ts` does to satisfy `react-hooks/static-components`. `ToolCatalogRecord.id` is narrowed from `string` to a `ToolCatalogId` union, so `Record<ToolCatalogId, …>` cannot be under-filled: adding a tool without choosing a glyph is now a type error rather than a silent runtime fallback. `appModeIcons` keeps its name and shape but is derived rather than hand-maintained, so its "keep in sync" comment is now a property of the type. Accent delivery is `data-category-accent` → `--cat-accent`/`--cat-soft`/ `--cat-border` in globals.css rather than interpolated class names, which Tailwind's scanner cannot see, and rather than inline styles, which bypass the theme contract. Every accent aliases an existing non-semantic triad (`--type-*`, `--tone-*`), so light, dark and forced-colors need no new declarations. `risk-safety` loses its permanent danger-red tile: red asserted caution about a route rather than about a patient, spending the loudest colour in the system on a navigation target. Safety is carried by the now-unique shield glyph and by the danger-toned selected state, which is a real state. Gates: typecheck, lint, `npm run test` (643 files, 6882 passed / 4 skipped), check:design-system-contract, check:icon-scale, check:type-scale — all green. No provider-backed check was run and none is required; no RAG surface touched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XGhewT2mmRoRTynjWfF1Vn * fix(factsheets): stop painting content categories in semantic colours `categoryTheme()` drew two of its four category accents from the SEMANTIC palette: Therapies on `--success-text`/`--success-bg` and Tests & procedures on `--warning-text`/`--warning-bg`. Those tokens carry meaning. `src/lib/semantic-tone.ts` defines six tones where the colour IS the claim — warning means "pause, check, adjust, review", success means a check passed — and `docs/clinical-badge-system-guide.md` states the rule as "meaning drives the colour, never the other way round". Applying warning-amber to an entire category of patient handouts asserted caution about content that nothing had reviewed, and it did so on the largest surface the factsheet has: the hero band. It also spent a colour the badge system needs, so a genuine caution badge had to compete with its own page chrome. All four categories now sit on non-semantic identity triads, sourced from `FACTSHEET_CATEGORY_IDENTITY`: Medications --clinical-accent -> --type-form Conditions --tone-indigo -> --type-source Therapies --success-text -> --type-service Tests & procedures --warning-text -> --type-table Medications moves too, for a different reason: it was the same blue as every selection state, focus ring and evidence marker on the page, so the biggest category was the one with no identity of its own. `FactsheetTheme`'s shape is unchanged, so the ~20 call sites passing these as inline style values are untouched. `FactsheetCategory` is now a re-export of the registry's union, so the accent map and the content model cannot disagree about what the categories are. Three guards added to tests/design-token-contract.test.ts, each mutation-verified: - no `[data-category-accent]` rule may reference a semantic token (verified: pointing "table" at --warning-text fails the test) - `categoryTheme` must stay derived via `categoryAccentVars` and return no semantic token (verified: reinstating the old --warning-* return fails it) - `CategoryAccent` may not declare a semantic member, which is what makes the mistake unrepresentable at every call site rather than caught per site Gates: typecheck, lint, `npm run test` (643 files, 6885 passed / 4 skipped), check:design-system-contract — all green. No provider-backed check run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XGhewT2mmRoRTynjWfF1Vn * refactor(ui): add the shared card recipe and absorb the two private forks Four cards that sit side by side in the same shell had drifted on every axis: ToolCard rounded-lg --shadow-card p-4 border + tint + hover lift ServiceCard rounded-xl --shadow-inset p-3 sm:p-4 border + ring/35 CalculatorCard rounded-lg --shadow-inset p-4 border + --shadow-soft Factsheet card rounded-xl --shadow-card - inline-style border-t-[3px] Two radii, three resting elevations, and four different "this one is selected" encodings, three of those expressed as fractional opacity on a token colour — which is unreviewable, because the contrast an alpha lands on depends on whatever surface happens to sit behind it in each theme. `src/components/card-recipes.ts` holds the shared definitions: `cardSurface`, `cardInteractive`, `cardSelected`, `cardAccentEdge`, `cardPadding`, and one exported `focusRing` (that string is currently redeclared as a local const in a dozen files and inline in dozens more). Recipes rather than a registered component: COMPONENTS.md §0.4 measures 157 production importers of ui-primitives.tsx against 31 product imports across the whole 54-component registry, and ledger #266 says adoption is demand-driven, "never a race to 54/54". A function also sidesteps element polymorphism — these cards are variously <article>, <button> and <Link>. A new module rather than growing ui-primitives.tsx, which §0.4 already lists as over-budget and slated to split. Two deliberate departures from what the four cards did: - `--shadow-inset` is dropped as a card elevation. It is the design-system bevel, and SPEC §4.7 says an inset well uses a border or inset shading, not both; pairing it with a border is why the services and calculator cards read flatter than the tool cards beside them. Resting is border + --e1. - The recipes name `--e1`/`--e2`/`--e3` directly rather than the `--shadow-card` / `--shadow-soft` / `--shadow-hover` role aliases. TOKENS.md schedules those for retirement "inside the recipes first", and the contract ratchet counts every use — a new consolidating module reaching for one would move the count the wrong way. Caught by the gate on the first attempt (114 -> 115); now 113, unchanged from baseline. `specifierCard` and `formulationCard` were byte-identical copies of the same string; both now name the shared recipe. This moves those two modes' cards from `--surface` to `--surface-raised`, which is the SPEC §177 correction (true-white cards against the near-white page) and is a visible, intended change. Consumers for `cardInteractive`/`cardSelected`/`cardAccentEdge` land in the following commit. Gates: typecheck, lint, `npm run test` (643 files, 6885 passed / 4 skipped), check:design-system-contract, check:knip — all green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XGhewT2mmRoRTynjWfF1Vn * feat(tools): elevate the tool cards and merge the phone/desktop pair The launcher rendered two components for the same content — `ToolCard` and `MobileToolRow` — and they had already drifted: different resting elevation (--shadow-card vs --shadow-inset), different selected tint (/50 vs /55), and a hover lift on one but not the other. They are now one component with a `density` prop. Both test ids are kept: `application-card-*` and `application-row-*` are each asserted by ui-tools and ui-smoke, and ui-smoke is blocking at zero retries. Verified in Chromium at 390px that the row renders visible and the card hidden, with all 13 of each still in the DOM. Craft changes, launcher and tools search results: - The fake button is gone. `Details` was a <span> painted as a solid accent button INSIDE the card's own <button>: it read as a nested control, was announced as nothing, was the loudest element on the card, and — being identical on every card — distinguished nothing. The card is the control; a chevron on the decoration tier says so, taking the category accent on hover so the affordance points at the card's own family. - On the search results page the same button is real (that card is an <article> and not itself clickable), so it stays — but as `floatingControl` rather than a filled accent. Thirteen filled primaries down one list were thirteen primary actions, none of them the page's actual primary action. - Titles move from `text-base font-extrabold` to `text-lg font-semibold`. At extrabold they matched the section heading above them, so a grid of cards read as a wall of headings. Size carries the hierarchy; weight stops trying to. SPEC §4.6 puts card titles at --text-lg. - "Best for:" was a bold inline run inside the body copy, giving a label the same emphasis as the clinical text it labels. It is a kicker, so it uses the shared `eyebrowText` recipe. - The magnifier beside "Best for" on the results page is dropped: "Best for" is not a search, and it spent an accent-coloured glyph on a label. - The selected rail on a results row takes the tool's own category accent rather than the product blue, so it agrees with the tile beside it. - `min-h-[9.25rem]` and `min-h-[5.25rem]` are replaced by content height with a `min-h-tap` floor. Production tap targets stay at min-h-12. - The local `focusRing` const in both files now imports the shared one. `risk-safety` keeps a danger-toned SELECTED state via the new `cardSelectedDanger` — selection is a real state, unlike the permanent red tile retired earlier in this branch. `legacyShadowAliases` fell 113 -> 111 as the cards moved off --shadow-card and --shadow-inset onto the --e ladder. Gates: typecheck, lint, `npm run test` (643 files, 6885 passed / 4 skipped), check:design-system-contract, check:icon-scale, check:type-scale — all green. Chromium: check:playwright-browser-revision was failing on the known #255 drift (1194 installed against the pinned 1234); the pinned revision was installed, the check now reports OK, and ui-tools + ui-hydration + the ui-smoke tools assertions were run locally against it. Five ui-tools failures were investigated and are pre-existing: all four reproduce on origin/main with this work stashed (two /services/13yarn composer cases, two service-detail cases, and the tools mobile detail-sheet case), and the tools one passes when driven manually, so it is environmental rather than a regression. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XGhewT2mmRoRTynjWfF1Vn * feat(ui): adopt the card recipe and category accents on factsheets, calculators and services Factsheets - The three inline `style` objects per card are gone. An inline value cannot be remapped by the dark or forced-colors blocks, so the old cards carried their light-mode tint into both. Verified in Chromium: the four accents now remap correctly in dark, and under forced-colors they flatten to Canvas/CanvasText as they should — identity colour is decoration, and the glyph and category chip carry the meaning in high contrast. - The category browse pills take the same accents, so a pill and the cards it filters to now agree. - Card titles move to `text-lg font-semibold`, and hover tints the title with the card's own category accent rather than the product blue. Calculators - The directory tile was grey until a card opened, so a closed directory showed five domains rendered identically and the domain was findable only by reading the chip. It now carries the domain accent at rest — which is what the chip beside it has always said in words. - `CALCULATOR_DOMAIN_ACCENT` deliberately gives `risk` (suicide risk) an identity accent, not `--danger`. The label already says "Suicide risk", and an instrument is not itself a warning; a red tile on a directory row would claim urgency about a tool rather than about a patient. - Open/closed states move onto `cardSelected` and the --e ladder. Services - Adopts `cardSurface` + `cardSelected`, retiring the fourth "this one is selected" encoding (`ring-1 …/35` — an alpha on a token colour, so what it contrasted against depended on whatever surface sat behind it per theme). - The leading tile deliberately stays a RANK rather than becoming a category glyph: this is a ranked referral list, the number is what the "Best fit" pill refers to, and it doubles as the shortlist checkmark. Services has no single category axis either — records carry facets — so there would be nothing honest to put there. Ratchets moved the right way: legacyShadowAliases 111 -> 107, edge conflicts 19 -> 18. Deferred, unchanged: therapy-compass/therapy-card.tsx (own SVG icon set, own control recipes, own IconTile, and the open rawPadding/rawGap debt from #261), the differentials-home card family, and the forms detail cards — those are detail-panel compositions rather than category-bearing list items. Gates: typecheck, lint, `npm run test` (643 files, 6885 passed / 4 skipped), check:design-system-contract — all green. Chromium inspection at 390/1440 in light, dark and forced-colors against the pinned revision 1234. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XGhewT2mmRoRTynjWfF1Vn --------- Co-authored-by: Claude <noreply@anthropic.com>
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes live
search_schema_health()failure (ok: false, 10 missing indexes) discovered during database review.20260705180000_reconcile_search_health_indexes.sqlthat creates canonical retrieval-support indexes missing on live (trgm, composite btree, partial miss-log indexes).search_schema_health()to accept verified functional equivalents (e.g.documents_title_search_tsv_idxfordocuments_title_trgm_idx) so health checks do not false-fail mid-rollout.search_path = public, extensions, pg_catalogin the migration sogin_trgm_opsresolves whenpg_trgmlives in theextensionsschema.supabase/schema.sqland adds regression coverage intests/supabase-schema.test.ts.Live verification (already applied)
Checks run
npx vitest run tests/supabase-schema.test.ts— 37/37 passedsearch_schema_health()— ok: true after migration applyOperator notes
sjrfecxgysukkwxsowpyduring this change; other environments should runnpx supabase db push --linked(or normal deploy migration workflow).set search_path(gin_trgm_opsnot found); fixed before successful apply.