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 @@ -561,6 +561,7 @@ Records before 2026-07-28 were written by hand and had drifted: 146 lines carrie
| 2026-07-31 | codex/merge-privacy-safe-error-tracking-implementation | fab9a9ec5181eb6ef3f8f43f303c39fa87cc1f6c | bugbot-review | no-p0-p1; empty/partial-meta-neutralized; sentry-init-failopen; gitleaks+pr-policy-body; merge-tree-clean; PR-left-closed | vitest:46-pass-focused; typecheck:pass; gitleaks-range:clean; merge-tree:clean; verify:pr-local:codex-cloud-fixed |
| 2026-07-31 | codex/address-performance-issues-in-package | aa8c2dfb1406a7a3f74745d20f2b370c75b55719 | PR #1489 review+bugbot+fix+heavy | synced main (#1478 behind-but-clean); fixed docs inventory + #117 stale hashed paths; verify:cheap 4683 passed; verify:pr-local build+bundle-budget+RAG fixtures green; typecheck clean | verify:cheap: 448 files / 4683 passed; verify:pr-local: Client bundle secret surface check passed + Offline RAG fixture validation passed (36 golden cases); check:bundle-budget: within tolerance + done; format:check: All matched files use Prettier code style!; merge-tree origin/main clean |
| 2026-07-31 | claude/issues-writer-cli (PR #1524) | 83dec1f5a36d577c87ee9a5382ef8431d197d93d | PR #1524 review+bugbot+fix | before: dirty/CONFLICTING vs main (outstanding-issues.md + scripts-index.md), missing pull_request CI, 0 review threads, NOT REVIEWED. after: merged origin/main (prefer main queues; renumbered this PR collision-free-ids note #159→#168, next-id=169); fixed wrong skill/writer cite #154→#156/#168; no other P0–P2 writer defects; 0 threads. Residual: concurrent id RMW (#156/#168) still open. | check:outstanding-issues pass (166 rows, next-id=169); outstanding-issues.mjs --self-test pass; vitest tests/outstanding-issues-writer.test.ts 8/8; merge-tree clean vs origin/main; format clean; no provider-backed checks |
| 2026-07-31 | PR #1536 | f92ad5ea35a9c68c2382fd94c56cfbb3deffb185 | documents filter panel + library naming | Handoff. Made the smart-tag facet panel reachable (its only mount was gated on a selection nothing could make), merged source-type filtering into it, and renamed the library control off 'Open source filters'. Kept the ribbon library button after a browser run showed the action-menu route clears the query via onSearchModeChange. Ledger #176 filed for the separately-inert command-scope system. | verify:cheap exit 0 (450 files / 4710 tests); ui-smoke.spec.ts chromium 93 passed 1 failed, the failure pre-existing under Chromium 1194 vs pinned 1228; mutation-tested (old gate fails all 6 new DOM tests) |
| 2026-07-31 | claude/fable-implementation-fc937c | 8401138cf7fc2c02d2fad54a7960bbb66d1fd7ae | design-system doc set (SPEC/TOKENS/COMPONENTS/DECISIONS/GATES) + sentry-merge repair (instrumentation syntax, ui-primitives icon revert, sentry options, formatting) | handoff: PR opened for review; auto-merge not armed (clinical-risk paths) | tsc 0 errors; vitest ui-primitives.dom+icon-button.dom 7/7; token contracts 47/47 (design branch); prettier whole-tree; docs:check-links 1486; eslint 0 errors |
| 2026-07-31 | claude/fable-implementation-fc937c | 14e3c3773d8be0a771673248e898c9bcde08b8dc | pr-1531 review-and-fix | fixed-sentry-privacy-blockers; merge-tree-clean; threads-cleared | vitest:error-tracking+env-sentry 6/6; tsc --noEmit 0 |
| 2026-07-31 | claude/fable-implementation-fc937c | e87d4e583cec7277f6c1ff2fc5c3a08b2d1b37aa | pr-1531 unblock | fixed static-pr eslint anon-export + build bundle-budget (-client Sentry); merge-tree-clean; 0 blocking threads | eslint next.config --max-warnings 0; check:bundle-budget within tolerance (1394.0/1278.6 KiB gzip); vitest error-tracking+env-sentry 6/6 |
Expand Down
4 changes: 3 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=181 -->
<!-- issues:next-id=183 -->

## Open items

Expand Down Expand Up @@ -160,6 +160,8 @@ removed after current-main verification; it is not missing recommended work.
| #178 | P2 | rec | pr-policy does not flag operational risk bundled with clinical or UI risk | **Outcome:** a PR that mixes operational-risk paths with clinical or UI risk is called out before it merges, because squash-merging that mix destroys per-item revert. **Detail:** `classifyPullRequestFiles` already computes `operationalRisk`, `clinicalRisk`, `ragRanking` and `ui` independently, but nothing reacts to the combination. AGENTS.md's "PR bundling" section forbids bundling anything once `operationalRisk` is true; the classifier is where that could be enforced. PR #1489 is the worked example: 33 files spanning `.github/workflows/ci.yml`, both Dockerfiles, a rewrite of the bundle-budget gate, a phone-chrome scroll change and a therapy data restructure, merged as one squash (945148251). Reverting any single item now means hand-reverting hunks out of the squash commit, because the branch commits are unreachable. The remediation PR for that review repeats the pattern on a smaller scale (clinical data plus a one-line ci.yml timeout), which is why this is a recommendation rather than a hard gate — the right severity is probably a warning that names the mixed classes, not a merge block. **Next:** emit an advisory line from `evaluatePullRequestPolicy` when `operationalRisk` coincides with `clinicalRisk` or `ui`, listing which paths drove each; decide separately whether it ever blocks. Cover it in the `--self-test` block. **Stop:** do not make it a hard failure in the same change that introduces it — land the signal first and see how often it fires. Renumbered from this PR's original `#172`. | PR #1489 review remediation; PR #1532; session 2026-07-31 | 2026-07-31 |
| #179 | P3 | issue | The full therapy catalogue silently switched from minified to pretty-printed | **Outcome:** the full catalogue's on-disk format is a decision someone made, not a side effect. **Detail:** `public/therapy-compass-data/therapies.json` was a single minified line (2,529,429 bytes) until PR #1532 routed it through `syncTarget` to scrub the tag-echo `modality`. `syncTarget` serialises with `JSON.stringify(records, null, 2)`, so the file is now 18,400 pretty-printed lines at 2,652,783 bytes. **Measured cost:** +123,354 bytes raw (+4.9%), but only +3,409 bytes gzipped (333,428 -> 336,837, +1.0%) — gzip absorbs almost all the added whitespace, and the file is not JavaScript so `check:bundle-budget` never sees it. The visible cost is git churn: each future data revision now produces ~18,400 changed lines in this file plus another ~18,400 in its content-addressed twin, which is why PR #1532 read as 42,071 insertions when only 381 of them were hand-written. **The benefit is real and probably wins:** a 205-record clinical dataset with a one-line diff is unreviewable, and a reviewer needs to see which clinical field changed. The two index projections were already pretty-printed, so this is now consistent. **Next:** confirm the format deliberately, then either leave it (recommended — 1% wire cost buys reviewable clinical diffs) or pass a minified serialiser for the full payload only, which would land below main's original size now that `modality` is gone. Either way record the reason next to `syncTarget`. **Stop:** do not minify the index or home projections to "match" — they are small and their diffs are the review surface for catalogue changes. | PR #1532; session 2026-07-31 | 2026-07-31 |
| #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 |


## Resolved / archive
Expand Down
Loading
Loading