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
5 changes: 4 additions & 1 deletion docs/outstanding-issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ removed after current-main verification; it is not missing recommended work.
| 34 | `#163` | A3 | High — frontend/UI | After or with `#162` | 0.5–1.5 days | Redesign `/services?q=` as Progressive Referral Workflow (direction B): H1 = query (not match count), progressive shortlist/compare (no always-on decision panel or giant step rail). Comps in `public/mockups/mode-page-redesign-2026-07/services-search/`. Verify referral shortlist still works; stop before changing Services home ModeHome. |
| 35 | `#164` | A3 | High — frontend/UI | Product confirmed Favourites is hybrid dashboard+search (no ModeHome) | 1–2 days | Redesign Favourites as one dashboard + search page: recommended Search-Led Workspace (direction B) — persistent search, sets as chips, Continue + recent + table on empty query, in-place filter on typed query. Comps in `public/mockups/mode-page-redesign-2026-07/favourites-hybrid/`. Do not reintroduce ModeHome for Favourites. Verify desktop+phone; stop before splitting into separate ModeHome routes. |

<!-- issues:next-id=183 -->
<!-- issues:next-id=186 -->

## Open items

Expand Down Expand Up @@ -161,6 +161,7 @@ removed after current-main verification; it is not missing recommended work.
| #180 | P3 | issue | build-therapies-index now overwrites its own source input | **Outcome:** the therapy catalogue generator has a source it does not also destroy. **Detail:** `scripts/build-therapies-index.mjs` reads `public/therapy-compass-data/therapies.json` as `source`, and since PR #1532 also writes the curated full payload back to that same path (`syncTarget(legacyFullTarget, curatedFull)`). Input and output are now the same file, so the generator is no longer idempotent with respect to its own input in the strict sense: it is stable in practice only because `curatedModality` is a fixed point (a null modality stays null, a genuinely curated non-tag value survives a second pass). The original tag-echo values are now recoverable only from git history. **Why it matters beyond tidiness:** `#175` asks someone to curate real modality values in this file. They will be editing the generator's output, and any field the generator ever decides to rewrite will silently discard their edit on the next run — with no gate to catch it, because `--check` compares the file against what the generator would produce, so a clobbered hand edit reads as "current". **Next:** separate the two roles — keep an unprocessed source (`therapies.source.json`, or move curation upstream of `public/`) and let `therapies.json` be purely generated, or at minimum add a header comment to the file stating it is generated and hand edits to processed fields will not survive. **Stop:** do not fix this by reverting the full-catalogue scrub; detail and recommend load `catalogue: "full"`, so the scrub is what keeps the ECT/rTMS mislabel off the only screens that render the chip. | PR #1532; session 2026-07-31 | 2026-07-31 |
| #181 | P3 | issue | Correction to `#171`: source-type does NOT duplicate the `Document type` facet group | **CORRECTS a claim already merged to `main` in `#171`.** `#171` states that the documents source-type control "duplicates the facet group already named `Document type`". That is wrong, and it was asserted from a shared word rather than from the code. **What is actually true:** `resultTypeTabs`/`filterMatchesByResultType` (`document-search-results.tsx:253-273`) filter on artefact properties of the file — `match.tableCount > 0`, `match.imageCount > 0`, `match.file_name.endsWith(".pdf")`. The `Document type` **facet** group comes from `label_type: "document_type"` labels, meaning the *kind* of document: policy, guideline, form. A guideline containing a table is both; neither implies the other. They are complementary axes, not duplicates. **The real duplication** is the scope chip `{ id: "tables", label: "Tables" }` in `search-command-surface.ts` against the source-type `Tables` tab — same meaning, two controls. **Consequence for `#171`:** the merge it recommends is still worth doing (four entry points for narrowing one list is too many), but the shape changes — source-type becomes its own group in the panel (Format) rather than being absorbed into `Document type`, and the scope chips are the part that genuinely folds away. `#171`'s other claim, that `Sources` is navigation rather than a filter, is unaffected and stands. **Stop:** do not implement the absorption `#171` describes. **Before merging any of it,** verify the scope-chip semantics per mode — only services and prescribing were traced, and this row exists because an untraced inference reached `main` as fact. | `document-search-results.tsx:253-273`; `document-tags.ts` groupLabels; session 2026-07-31 | 2026-07-31 |
| #182 | P2 | issue | The command-scope system is inert — chips are configured and matchers exist, but nothing can ever set a scope | **Outcome:** either scopes can be applied by a user, or the dead config, matchers, props and UI that serve them are removed — not the current middle state where five surfaces look wired and none are. **Detail:** `src/components/clinical-dashboard/universal-search-command-surface.tsx:392-393` does `void commandScopes; void onCommandScopesChange;` — the surface receives both the value and the setter and discards them. Every other write in the repo passes an empty array (`ClinicalDashboard.tsx:2367,2671`; `global-search-shell.tsx:630,660`), so `commandScopes` is permanently `[]` in production. Consequences, all currently invisible: `recordMatchesCommandScopes`, `favouriteMatchesCommandScopes` and `medicationMatchesCommandScopes` (`src/lib/search-command-surface.ts:253,269,293`) each early-return `true` on an empty array, so the four pages that call them — services, prescribing, favourites, forms — filter nothing; the `scopes:` arrays configured for six modes in `search-command-surface.ts` (documents, services, prescribing, forms, favourites, differentials) are unreachable config; and the scope-chip shelf added to `search-results-header-band.tsx:171,676` in PR #1523 can never render, since `command?.commandScopes` is always empty. `tests/search-results-header-band.dom.test.tsx` passes because it constructs the command context by hand, and `tests/search-command-surface.test.ts` unit-tests the matchers directly — neither test reaches the production path, which is why this survived. Not a wiring-conventions violation: no control is clickable, so nothing advertises an action it fails to perform. It is cruft that reads as a feature, and it cost this session a full trace to establish that the documents mode was not uniquely broken. Predates the current branch — confirmed present on `origin/main`. **Next:** decide before building any further filtering UI on top of it. Cheapest honest option is deletion: drop the two voided props, the `scopes` config arrays, the three matcher functions and their call sites, and the band's scope shelf, then let the smart-tag facet panel be the single filtering surface for documents. The alternative — wiring chips into the command dropdown — is a real feature and needs its own design, not a quiet revival. **Stop:** do not add a second filtering surface that reads `commandScopes` while it is inert, and do not treat the DOM/unit tests above as evidence that scopes work end to end. | session 2026-07-31 Batch B trace; universal-search-command-surface.tsx:392-393; search-command-surface.ts:253-296; PR #1523 | 2026-07-31 |
| #183 | P2 | task | Create Sentry metric alert for production DB span p95 > 500ms | Still blocked 2026-08-01 closeout: SUPABASE_ACCESS_TOKEN and SENTRY_AUTH_TOKEN missing from session env; Sentry MCP OAuth can list/get alerts but has no create tool; browser hits login wall; no metric rules exist yet on clinibase-xz. Create Metric Alert: p95(span.duration), filter span.op:db, environment production, threshold >500ms, notify Active Members. Provide SENTRY_AUTH_TOKEN in session to finish via sentry alert metrics create. | session 2026-07-31 db-query-perf follow-up | 2026-07-31 |


## Resolved / archive
Expand Down Expand Up @@ -294,4 +295,6 @@ Move resolved rows here with the resolution date and a one-line outcome. Keep th
| #130 | issue | Phone-chrome physical-device acceptance never run (#1396) — not pursued | CLOSED 2026-07-30 by owner decision — **not because the gate was run.** Stating that plainly so the record is not read as evidence later: `docs/phone-chrome-physical-acceptance.md` on `main` is still the blank checklist template, no PR comment attaches device evidence, and PR #1396's shared phone-chrome overlay change therefore shipped without the physical-device acceptance its own body and review thread said applied before merge (restated at least three times, including after the final fix). The owner has decided not to pursue it. Residual risk is unchanged and unmeasured: headless Chromium was explicitly stated as unable to certify Safari chrome-minimisation or cold-launch PWA paint (invariant 23), so nothing in CI covers what that checklist covers. The separately-identified missing guard — a pre-paint/cold-load hydration test comparing content position before and after hydration — was also never filed and is also not pursued. Reopen a new row if phone-chrome behaviour is reported wrong on a real device. | 2026-07-30 |
| #103 | issue | Wide table-facts trigram index missing from `schema.sql` | Refuted and archived 2026-07-31. The terminal migration chain already drops `document_table_facts_text_trgm_idx` in `20260717010000_harden_rag_scalability_patch.sql`; `schema.sql` deliberately retains only the expression-matching narrow index, and `tests/supabase-schema.test.ts` pins both facts. No hosted inspection or index re-addition is required. Verified against origin/main before landing: the drop is present in that migration and the index name appears nowhere in schema.sql. Disposition authored in another session's worktree and landed here. | 2026-07-31 |
| #028 | rec | Runtime error tracking (Sentry or similar) | Enabled production Sentry server error + DB tracing on Railway Database/production (SENTRY_DSN, SENTRY_ENVIRONMENT=production, SENTRY_TRACES_SAMPLE_RATE=0.1); staging app enabled with environment=staging; browser DSN/source-map tokens intentionally unset; verified production span.op:db in Sentry. | 2026-07-31 |
| #185 | task | Confirm hosted migration history row for 20260731150000 db-query-perf | Confirmed on live Clinical KB Database (sjrfecxgysukkwxsowpy): supabase_migrations.schema_migrations has version 20260731150000 name db_query_perf_rate_limit_and_image_indexes; document_images_searchable_doc_page_relevance_idx present. No re-apply needed. | 2026-07-31 |
| #184 | task | Regenerate supabase/drift-manifest.json after db-query-perf migration | Regenerated supabase/drift-manifest.json via Docker npm run drift:manifest on host; includes document_images_searchable_doc_page_relevance_idx and updated consume_api_*_rate_limit inventory; schema_sha256 matches schema.sql. | 2026-07-31 |

14 changes: 10 additions & 4 deletions supabase/drift-manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"generated_at": "2026-07-31T14:44:06.210Z",
"generated_at": "2026-07-31T17:55:21.421Z",
"generator": "scripts/generate-drift-manifest.ts",
"postgres_image": "supabase/postgres:17.6.1.127@sha256:be60aee15997daca475b710b734bc6bfe52cd544dcd7e9fd2ff58210b6747d83",
"schema_sha256": "d45841d7de9b2e4834134204e1919fcbbf239540f9f0003d555739e15f806dd8",
"replay_seconds": 17,
"replay_seconds": 107,
"snapshot": {
"views": [
{
Expand Down Expand Up @@ -4980,6 +4980,12 @@
"table": "document_images",
"def_hash": "10b08574f74bb01b0727ce93ef68e25d"
},
{
"def": "CREATE INDEX document_images_searchable_doc_page_relevance_idx ON public.document_images USING btree (document_id, page_number, clinical_relevance_score DESC NULLS LAST) WHERE ((searchable IS TRUE) AND (image_type IS DISTINCT FROM 'logo_decorative'::text))",
"name": "document_images_searchable_doc_page_relevance_idx",
"table": "document_images",
"def_hash": "c4375ac3874774369a483bd951677606"
},
{
"def": "CREATE INDEX document_images_searchable_idx ON public.document_images USING btree (document_id, searchable, image_type, page_number)",
"name": "document_images_searchable_idx",
Expand Down Expand Up @@ -6747,15 +6753,15 @@
"postgres=X/postgres",
"service_role=X/postgres"
],
"def_hash": "c30484095942ebbcbfd087215dd7ec0a",
"def_hash": "fdfad79a080ac7993b486e83399aa349",
"signature": "public.consume_api_rate_limit(uuid,text,integer,integer)"
},
{
"acl": [
"postgres=X/postgres",
"service_role=X/postgres"
],
"def_hash": "e263f3819b05177abcf2eedd3f468991",
"def_hash": "18f2c79eaaadbf2025377e9db3e12902",
"signature": "public.consume_api_subject_rate_limit(text,text,integer,integer)"
},
{
Expand Down
Loading