Skip to content

fix: remediate the PR #1489 review findings - #1532

Merged
BigSimmo merged 9 commits into
mainfrom
claude/pr-1489-review-786e01
Jul 31, 2026
Merged

fix: remediate the PR #1489 review findings#1532
BigSimmo merged 9 commits into
mainfrom
claude/pr-1489-review-786e01

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

Remediates the findings from the review of PR #1489 (merged as 945148251). No finding in that PR was P0 or P1, so this is follow-up rather than a revert. Each item is its own commit.

  • Therapy modality was inferred, not curated. The source catalogue derives it from each record's own tag list: all 205 records carried one, every value was also present in that record's tags, and the catalogue collapsed to CBT/ACT/DBT. That mislabelled the treatments it cannot describe — ECT and rTMS as ACT, Psychoanalysis and Psychodynamic Psychotherapy as CBT, MBT and TFP as DBT — while rendering as a curated chip on the detail and recommend screens and scoring related-therapy selection. The generator now emits the field only when the source curates a value that is not already a tag, which today means null for 205/205. This defect was pre-existing on main, not introduced by perf: reduce Therapy startup and sidebar layout work #1489; perf: reduce Therapy startup and sidebar layout work #1489 surfaced it by adding a new projection.
  • Superseded content-addressed catalogue assets were never pruned. Every regeneration mints new hashed filenames, so each data revision stranded the previous full catalogue (~2.5 MB) plus both projections permanently, in git history and in every image. PR perf: reduce Therapy startup and sidebar layout work #1489 stranded two inside a single pull request and needed a hand-deletion commit to clear them. The generator now prunes, keeping a one-deploy grace generation.
  • classifyPullRequestFiles treated clinical reference datasets as non-clinical. PR perf: reduce Therapy startup and sidebar layout work #1489 shipped 205 therapy records carrying per-record recommendation prose with clinicalRisk: false, so no governance preflight was ever required for it. src/data/**, data/** and public/therapy-compass-data/** are clinical output even with no code diff. This PR is itself gated by that new rule.
  • The viewportHeightChanged guard outranked the top reveal band. It sat above the offset <= topRevealOffset branch, so a resize landing while the chrome was hidden and the scroller was clamped to the top stranded the chrome off-screen at offset 0 until the next scroll. Reordered, with a test at offset 0 that the existing 480/500 case never covered.
  • That guard also keyed on the wrong height. It read window.innerHeight while the listener fired on visualViewport resize, so it could not engage for the Safari toolbar collapse its own comment named first. It now measures visualViewport.height, rounded so sub-pixel jitter during a toolbar animation does not register as a resize on every frame.
  • The false-key escaper missed project-scoped keys. An alphanumeric-only tail never matched sk-proj-…, whose hyphen sits four characters in, leaving unescaped the key shape most likely to be pasted into source.
  • The bundle-budget step timeout had no margin. The 3-minute ceiling exists so a stuck exit fails as failure rather than being cancelled at the job timeout; the check finishes in seconds, so 3 minutes risked turning a healthy build red on a contended runner. Raised to 8.
  • Recorded the deliberate sidebar snap.perf: reduce Therapy startup and sidebar layout work #1489 removed the grid-template-columns transition for measured reasons; both call sites now say so, so it is not "fixed" back as a missing transition.

Two defects were found in this remediation and corrected before it left the branch. Pruning the previous hash immediately would 404 a client whose bundle still names it — the deployment-straddling failure the unversioned aliases exist to prevent, one level down — so a one-deploy grace generation was added (THERAPY_CATALOGUE_ASSETS_PREVIOUS) plus an alias fallback in useTherapyData for bundles older than that window. Rotating that window on every invocation then meant a second local re-run silently retired a generation that is still deployed, so rotation is now per-kind and content-driven; verified idempotent across three consecutive runs. The currently deployed therapies-index.4b4ee988e0ff84e2.json is retained, so no live client breaks.

Removing modality is provably search-neutral rather than merely low-risk: src/lib/therapies.ts scores with a boolean haystack.includes(token), not term frequency, and every modality value was already contributed by tags.join(" ") in the same haystack, so the token set and every score are unchanged.

This PR mixes clinical-risk paths with one operational-risk path (.github/workflows/ci.yml). That is the same bundling pattern the #1489 review criticised, and after squash the CI timeout will not be independently revertible. It is kept together because every item is a fix to one review; the classifier gap that would flag this combination is recorded as an open item rather than fixed here.

Verification

  • npm run verify:cheap — all 29 static gates pass; lint clean; typecheck exit 0; unit suite Test Files 449 passed (449), Tests 4700 passed | 3 skipped (4703)
  • npm run verify:phone-chrome — contracts Test Files 9 passed (9), Tests 116 passed; focused browser leg 13 passed (1.2m); escalated full-UI leg 342 passed, 2 failed
  • npm run verify:ui — run as the escalated final leg of verify:phone-chrome: 342 passed, 2 failed, both failures analysed below and passing in isolation
  • npm run check:therapy-data-indexTherapy indexes are current (205 records).
  • npm run check:pr-policy[pr-policy] self-test passed
  • npm run format — exit 0, committed

Verification not run: npm run verify:pr-localverify:cheap plus the full verify:phone-chrome chain (which itself runs verify:ui) were run instead and are a strict superset of the unit, lint, typecheck and browser coverage verify:pr-local would add for this diff; the build-conditional legs are exercised by CI.

The two failures inside the escalated full-UI leg are ui-tools.spec.ts:959 asserting the composer's CSS position is fixed, on /services/13yarn and /differentials?q=acute+confusion&focus=1&run=1, both receiving relative. They are not from this change, on evidence rather than assertion: use-hide-on-scroll.ts contains no position: assignment at all, so scroll-hide cannot produce that value; the assertion is hero-vs-dock composer ownership, decided by isStandaloneModeHomePath, which this diff does not touch. Re-run in isolation both pass, in 1.3s and 1.4s (5 passed (11.3s)). This is the one-frame hydration race named in docs/search-chrome-behaviour.md invariant 12.

No provider-backed gate was run. Retrieval, ranking, selection, chunking and answer generation are untouched, so no retrieval eval applies — RAG impact: no retrieval behaviour change — this PR touches the Therapy Compass static catalogue, the phone scroll-hide guard, the PR policy classifier and one CI step timeout; no file under src/lib/rag/**, clinical-search, retrieval-selection, ranking-config, answer-ranking, the eval harness or the golden fixture is modified, and the therapy catalogue is a standalone tool dataset that never enters retrieval candidate assembly.

Risk and rollout

  • Risk: low-to-moderate, concentrated in clinical display rather than behaviour. The modality chip disappears from the Therapy detail and recommend screens for every record, which is a visible change to clinical output and is the point of the change — an inferred label rendered as curated fact. Related-therapy scoring loses a same-modality point that was near-uniform noise (77% of records were CBT). Search recall and ordering are unchanged, provably. The catalogue pruning and phone-chrome reorder are behaviour-preserving in the cases their tests pin.
  • Rollback: revert this branch's commits. cfb18d2f4 (catalogue and policy), 2d001305b (phone chrome) and c600ac631 (CI timeout) are independent before merge; after squash they are one commit, so a post-merge revert of a single item means reverting hunks by hand. Reverting the catalogue commit restores the inferred modality values on the next regeneration, since the source data is unchanged.
  • Provider or production effects: None. No Supabase, OpenAI, Railway or hosted-CI mutation. The only deployment-visible change is which static catalogue filenames exist under public/therapy-compass-data/, and the retained previous generation plus the alias fallback mean no deployed client loses a URL it depends on.

Clinical Governance Preflight

  • Source-backed claims still require linked source verification before clinical use
  • No patient-identifiable document workflow was introduced or expanded without explicit governance approval
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy)
  • Service-role keys and private document access remain server-only
  • Demo/synthetic content remains clearly separated from real clinical sources
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative
  • Deployment classification/TGA SaMD impact was checked when clinical decision-support behavior changed

On the sixth item specifically: this change makes the catalogue strictly more conservative. reviewStatus is untouched and every record remains needs_review; the field being suppressed is one that asserted a treatment modality the source never curated. Removing an unsupported label is the conservative direction, and no record gains a claim.

On the seventh: the Therapy Compass catalogue is clinical reference content in a prototype that is explicitly not validated clinical decision support. Suppressing an inferred label reduces the decision-support surface rather than extending it, so the SaMD classification is unchanged.

Notes

  • Ledger row appended for the perf: reduce Therapy startup and sidebar layout work #1489 review at head 67d5cb91083f9b0e9d3017816cbf68abab102688 via npm run ledger:append.
  • Four follow-ups recorded in docs/outstanding-issues.md (#169#172): curate or remove modality; the sourceChanged guard's identical ordering defect; the aliases duplicating 2.53 MB; and pr-policy not flagging operational risk bundled with clinical or UI risk. The "therapy search still loads the full corpus" follow-up was not duplicated — it is already tracked as #117.

BigSimmoand others added 4 commits July 31, 2026 19:11
…ues, gate clinical data
Three findings from the PR #1489 review, all in the generator/policy layer.
1. `modality` was inferred, not curated. The source catalogue derives it from
each record's own tag list: all 205 records carry one, every value is also
present in that record's `tags`, and the catalogue collapses to CBT/ACT/DBT.
That mislabels the treatments it cannot describe — ECT and rTMS as "ACT",
Psychoanalysis and Psychodynamic Psychotherapy as "CBT", MBT and TFP as "DBT" —
while rendering as a curated chip on the detail and recommend screens and
scoring related-therapy selection. Emit it only when the source curates a value
that is not already a tag; consumers already treat null as unknown.
Removing it is provably search-neutral: `src/lib/therapies.ts` scores with a
boolean `haystack.includes(token)`, not term frequency, and every modality
value is already contributed by `tags.join(" ")` in the same haystack.
2. Superseded content-addressed assets were never pruned. Each regeneration
mints new hashed filenames, so every data revision stranded the previous full
catalogue (~2.5 MB) plus both projections permanently, in git history and in
every image; PR #1489 stranded two inside one pull request and needed a
hand-deletion commit. Pruning keeps a one-deploy grace generation, because
dropping the previous hash immediately would 404 a client whose bundle still
names it — the deployment-straddling failure the unversioned aliases exist to
prevent. `useTherapyData` now also falls back to the alias, covering bundles
older than the grace window. Rotation is per-kind and content-driven so a
repeat local run cannot retire a generation that is still deployed.
3. `classifyPullRequestFiles` treated clinical reference datasets as
non-clinical. PR #1489 shipped 205 therapy records carrying per-record
recommendation prose with `clinicalRisk: false`, so no governance preflight was
ever required. `src/data/**`, `data/**` and `public/therapy-compass-data/**`
are clinical output even with no code diff.
Also widen the false-key escaper: an alphanumeric-only tail never matched
`sk-proj-…`, whose hyphen sits four characters in, leaving unescaped the key
shape most likely to be pasted into source.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The `viewportHeightChanged` guard added in PR #1489 sat above the
`offset <= topRevealOffset` branch, so a resize landing while the chrome was
hidden and the scroller was clamped to the top returned `hidden: true` and
stranded the chrome off-screen at offset 0 until the next scroll. The top
reveal band is an absolute layout contract; a viewport change does not stop the
reader being at the top of the range. Reordered, with a test at offset 0 that
the existing 480/500 case never covered.
The guard also keyed on `window.innerHeight` while the listener fired on
`visualViewport` resize, so it could not engage for the Safari toolbar collapse
its own comment named first. Measure `visualViewport.height` instead, rounded
so sub-pixel jitter during a toolbar animation does not register as a resize on
every frame, and fall back to `innerHeight` for jsdom and older engines.
Also record the deliberate removal of the sidebar grid-track transition at both
call sites. Animating `grid-template-columns` relayouts the whole shell every
frame and needed a mount-gating hook in both shells to avoid animating from the
default track width; the snap is the point, not a missing transition.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The 3-minute step timeout added in PR #1489 exists so a stuck exit fails as
`failure` rather than being cancelled at the job timeout, which "Re-run failed
jobs" will not re-run. The check gzips every chunk once and finishes in
seconds, so the ceiling only needs to sit well below the job timeout — 3
minutes left no margin for a slow or contended runner and would turn a healthy
build red.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ledger row for the review at head 67d5cb9 (approved with follow-ups, merged
9451482), and four open items: therapy modality now null on all 205 records
pending curation or removal, the sourceChanged guard's ordering defect, the
catalogue aliases duplicating 2.53 MB, and pr-policy not flagging operational
risk bundled with clinical or UI risk. The "search still loads the full corpus"
follow-up is already tracked by #117 and was not duplicated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@supabase

supabaseBot commented Jul 31, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitaiBot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in:29 minutes

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8e7899b2-75e3-4056-93ff-818a0a572370

📥 Commits

Reviewing files that changed from the base of the PR and between 6f94ae8 and 668a489.

📒 Files selected for processing (21)
  • .github/workflows/ci.yml
  • docs/branch-review-ledger.md
  • docs/outstanding-issues.md
  • public/therapy-compass-data/therapies-index.8455f92cf736cbfa.json
  • public/therapy-compass-data/therapies-index.json
  • public/therapy-compass-data/therapies.d0358686e452b00b.json
  • public/therapy-compass-data/therapies.json
  • scripts/build-therapies-index.mjs
  • scripts/lib/escape-false-openai-key-signatures.mjs
  • scripts/pr-policy.mjs
  • src/components/ClinicalDashboard.tsx
  • src/components/clinical-dashboard/global-search-shell.tsx
  • src/components/clinical-dashboard/use-hide-on-scroll.ts
  • src/components/therapy-compass/data/generated-assets.ts
  • src/components/therapy-compass/data/use-therapy-data.ts
  • src/data/therapies-index.json
  • tests/escape-false-openai-key-signatures.test.ts
  • tests/therapy-compass-data-recovery.dom.test.tsx
  • tests/therapy-compass-mode-wiring.test.ts
  • tests/therapy-compass-pathways.test.ts
  • tests/use-hide-on-scroll.test.ts
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@ecc-tools

ecc-toolsBot commented Jul 31, 2026

Copy link
Copy Markdown

🔒 Upgrade Required

Private repository analysis requires Pro or Enterprise.

Upgrade: https://ecc.tools/pricing?plan=pro


ECC Tools keeps the core app open, and puts private repos, team features, and enterprise controls behind paid tiers.

@BigSimmo
BigSimmo enabled auto-merge (squash) July 31, 2026 11:18
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Fix therapy catalogue modality, prune hashed assets, and tighten clinical gating

🐞 Bug fix🧪 Tests⚙️ Configuration changes📝 Documentation🕐 40+ Minutes

Grey Divider

AI Description

• Stop emitting inferred therapy modality and regenerate therapy index projections.
• Prune superseded hashed catalogue assets and add alias fallback for stale bundles.
• Classify therapy datasets as clinical-risk changes; fix phone chrome resize guard.
Diagram

graph TD
E["escape-false-openai-key-signatures.mjs"] --> A["build-therapies-index.mjs"] --> B["generated-assets.ts"]
A --> C[("public/therapy-compass-data/")]
B --> D["use-therapy-data.ts"] --> C --> T["CI/Vitest gates"]
F["pr-policy.mjs"] --> T
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Serve unversioned aliases via rewrites (no duplicated files)
  • ➕ Eliminates duplicate bytes in working tree and Docker images
  • ➕ Keeps alias URLs stable while still benefiting from hashed immutability
  • ➖ Requires careful cache-header handling so rewrites don’t inherit immutable caching
  • ➖ Would change existing tests that assert alias and hashed files have identical bytes on disk
2. Remove `modality` from the exported schema until curated
  • ➕ Avoids carrying a field that is currently always null
  • ➕ Prevents accidental future UI reliance on an uncurated label
  • ➖ Requires coordinated changes across types, UI chips, and related-therapy scoring
  • ➖ Loses a placeholder for future curated modality data
3. Store the asset manifest as JSON instead of TS exports
  • ➕ Simplifies parsing in generator/check scripts (no regex over TS)
  • ➕ Keeps data/metadata clearly separated from code
  • ➖ Loses compile-time typing/const inference in TS consumers (unless wrapped)
  • ➖ Requires updating import paths/loader wiring

Recommendation: The PR’s approach is sound for remediation: it stops presenting inferred clinical labels as curated, bounds hashed asset growth with a one-deploy grace window, and makes clients resilient to stale hashed URLs via alias fallback. The main alternative worth considering later is serving aliases via rewrites to avoid duplicated payload bytes, but that is appropriately out-of-scope for a follow-up fix focused on correctness and governance.

Files changed (19) +5236 / -433

Enhancement (1) +10 / -0
generated-assets.tsAdd previous-generation therapy asset manifest alongside current+10/-0

Add previous-generation therapy asset manifest alongside current

• Extends the generated manifest to export both current and previous hashed asset filenames. Supports one-deploy grace retention and enables runtime fallbacks/tests to reason about allowed generations.

src/components/therapy-compass/data/generated-assets.ts

Bug fix (8) +5068 / -426
therapies-index.8455f92cf736cbfa.jsonAdd new hashed Therapy Compass index projection asset+4480/-0

Add new hashed Therapy Compass index projection asset

• Introduces a new content-addressed therapies-index JSON projection reflecting the updated generator output (including null modalities). This file is referenced by the generated asset manifest.

public/therapy-compass-data/therapies-index.8455f92cf736cbfa.json

therapies-index.jsonRegenerate unversioned therapies-index with null modality values+205/-205

Regenerate unversioned therapies-index with null modality values

• Updates the unversioned index projection so each record’s modality is null instead of inferred from tags. Keeps the alias projection aligned with the new hashed generation.

public/therapy-compass-data/therapies-index.json

build-therapies-index.mjsPrune stale hashed assets and suppress inferred modality in projections+109/-6

Prune stale hashed assets and suppress inferred modality in projections

• Adds logic to emit modality only when curated (not an echo of tags), rotates a one-deploy grace generation in the manifest, and prunes older hashed assets from public output. Extends check-only mode to fail on orphaned assets and missing retained previous-generation files.

scripts/build-therapies-index.mjs

escape-false-openai-key-signatures.mjsEscape project-scoped OpenAI key shapes (sk-proj-…)+7/-1

Escape project-scoped OpenAI key shapes (sk-proj-…)

• Widens the matcher tail to include '-' and '_' so 'sk-proj-…' tokens are escaped. Updates comments to clarify why word-boundary anchoring prevents hyphenated prose from being rewritten.

scripts/lib/escape-false-openai-key-signatures.mjs

pr-policy.mjsTreat shipped clinical reference datasets as clinical-risk changes+15/-0

Treat shipped clinical reference datasets as clinical-risk changes

• Adds 'src/data/', 'data/', and 'public/therapy-compass-data/' to clinical risk path patterns so data-only clinical output changes trigger governance gates. Extends self-tests to pin the new classifier behavior.

scripts/pr-policy.mjs

use-hide-on-scroll.tsFix resize guard ordering and measure visual viewport height+22/-8

Fix resize guard ordering and measure visual viewport height

• Reorders computeScrollHideUpdate so the top reveal band overrides the viewport-resize guard, preventing hidden chrome from being stranded at offset 0. Updates viewport height change detection to use rounded 'visualViewport.height' with an 'innerHeight' fallback to avoid Safari toolbar/keyboard mis-detection and sub-pixel jitter.

src/components/clinical-dashboard/use-hide-on-scroll.ts

use-therapy-data.tsFallback from hashed catalogue URL to unversioned alias+25/-1

Fallback from hashed catalogue URL to unversioned alias

• Wraps catalogue fetches in a helper that tries the content-addressed asset first and falls back to the stable alias on failure. Prevents error screens for sessions with stale hashed URLs during/after deployments.

src/components/therapy-compass/data/use-therapy-data.ts

therapies-index.jsonRegenerate source-facing therapies index with null modality+205/-205

Regenerate source-facing therapies index with null modality

• Updates the internal therapies index dataset to set modality to null across records rather than shipping an inferred value. Keeps the app’s source dataset consistent with the public projection behavior.

src/data/therapies-index.json

Tests (5) +138 / -5
escape-false-openai-key-signatures.test.tsAdd coverage for sk-proj keys and protect hyphenated prose+25/-0

Add coverage for sk-proj keys and protect hyphenated prose

• Adds a regression test proving 'sk-proj-…' tokens are escaped and round-trip via JSON.parse. Adds a safety test ensuring widened matching does not modify hyphenated clinical prose or slugs due to word-boundary anchoring.

tests/escape-false-openai-key-signatures.test.ts

therapy-compass-data-recovery.dom.test.tsxTest alias fallback behavior during Therapy Compass data recovery+11/-2

Test alias fallback behavior during Therapy Compass data recovery

• Updates the DOM recovery test to expect the loader to try the hashed URL and then the unversioned alias before failing. Pins call ordering and the additional fetch attempt when recovering from a transient failure.

tests/therapy-compass-data-recovery.dom.test.tsx

therapy-compass-mode-wiring.test.tsEnforce two-generation hashed asset retention and alias fallback wiring+51/-3

Enforce two-generation hashed asset retention and alias fallback wiring

• Adds tests ensuring only current + one previous generation of hashed assets are committed and that the previous generation exists on disk. Updates wiring assertions to reflect the new fetchCatalogue helper and checks for alias fallback presence.

tests/therapy-compass-mode-wiring.test.ts

therapy-compass-pathways.test.tsPin therapy modality as curated-only and null for mislabelled treatments+27/-0

Pin therapy modality as curated-only and null for mislabelled treatments

• Adds catalogue integrity tests asserting modality is never just a tag echo and that specific somatic/psychodynamic treatments (e.g., ECT, rTMS, Psychoanalysis) remain null. Prevents reintroducing the tag-derived modality inference in future regenerations.

tests/therapy-compass-pathways.test.ts

use-hide-on-scroll.test.tsAdd regression case for top reveal during viewport height change+24/-0

Add regression case for top reveal during viewport height change

• Adds a test verifying computeScrollHideUpdate reveals chrome at offset 0 even when viewportHeightChanged is true. Covers the previously untested ordering bug that could strand hidden chrome after resize/keyboard/orientation events.

tests/use-hide-on-scroll.test.ts

Documentation (4) +14 / -1
branch-review-ledger.mdRecord PR #1489 remediation status in review ledger+1/-0

Record PR #1489 remediation status in review ledger

• Adds an entry documenting the #1489 review findings and the fixes landed on this branch, including verification signals. Keeps the ledger aligned with current remediation work.

docs/branch-review-ledger.md

outstanding-issues.mdAdd follow-up issues and advance outstanding-issues counter+5/-1

Add follow-up issues and advance outstanding-issues counter

• Bumps the next-id marker and appends new rows capturing follow-ups discovered during PR #1489 remediation. Documents modality curation/removal and other identified recommendations.

docs/outstanding-issues.md

ClinicalDashboard.tsxDocument intentional snap behavior for sidebar collapse+6/-0

Document intentional snap behavior for sidebar collapse

• Adds an in-code note explaining why the grid-track transition for sidebar collapse is intentionally not used. Prevents future “missing transition” fixes that would reintroduce expensive relayout animations.

src/components/ClinicalDashboard.tsx

global-search-shell.tsxMirror sidebar-collapse snap rationale in standalone search shell+2/-0

Mirror sidebar-collapse snap rationale in standalone search shell

• Adds a comment matching ClinicalDashboard’s guidance that sidebar collapse should snap by design. Helps keep the two shells consistent and avoids reintroducing grid-track transitions.

src/components/clinical-dashboard/global-search-shell.tsx

Other (1) +6 / -1
ci.ymlIncrease bundle-budget step timeout for slow runners+6/-1

Increase bundle-budget step timeout for slow runners

• Raises the bundle budget check timeout from 3 to 8 minutes with explanatory comments. This reduces false CI failures due to runner contention while preserving an upper bound below job timeout.

.github/workflows/ci.yml

@BigSimmo

Copy link
Copy Markdown
OwnerAuthor

@cursoragent Work the current open PR end-to-end. Confirm the PR number and GitHub head first from context. If more than one open PR could apply, stop and say which one you would use and why.

Fetch and start from the remote tip that matches that GitHub head. If the named branch ref is missing or stale, use the PR head ref. Preserve unrelated local WIP, including any local-only ledger commits; do not discard dirty work, and do not treat a local-ahead commit as the reviewed tip. Do not merge the PR, force-push, rebase, or arm auto-merge unless I explicitly ask. No provider-backed gates without separate approval. If you cannot push or resolve threads, diagnose and comment only; if inline replies fail, resolve when possible and put dispositions in the summary comment. If auto-merge is already armed, push only for a real blocker, and avoid pushes that would cancel in-flight required CI unless the push itself clears that blocker.

If the PR is already merged or closed: confirm the head and merge commit, note required-CI outcome, post one summary, and stop.

Goal: deep review plus Bugbot, fix actionable issues with the smallest correct changes, clear merge / required-CI / thread blockers, run strong local offline verification, push fixes, append the review ledger, and post one PR summary. Prefer thoroughness over speed. Regenerate large assets only when a fix requires it; then run the asset check and keep compatibility aliases byte-identical where the repo uses them.

Snapshot the GitHub head SHA: tip, base, behind/ahead, mergeable state, merge-tree versus origin/main (real conflict versus behind-but-clean), required checks on that tip including Production UI when selected, advisory separately, unresolved actionable threads. Missing checks while dirty are not green. If the tip moves mid-work, re-snapshot and continue from the new head.

Ledger-lookup against that GitHub head under the heavy review-and-fix scope for this PR. Already reviewed at this head with clean merge-tree, green required checks, and no new actionable threads → summarize, comment, stop unless I asked for a fresh superseding pass. Follow the repo review protocol.

Unblock once: real conflict → merge origin/main (prefer main’s shared queues; keep this PR’s notes); behind-but-clean → one sync, late if required CI is in flight; clean → leave. Labels like skip-branch-sync do not block a manual sync needed to clear a real blocker. No sync thrash. After any sync or push, re-snapshot tip, merge-tree, and required checks before declaring done. Dedupe the ledger if a merge touched it.

Review high-confidence delta risks only. Separate PR-introduced defects from pre-existing re-emitted debt. For generated assets, review contracts, aliases, cache, and manifests—not every generated line. If protected RAG or ranking surfaces are touched, say so before editing; fix PR-body policy text only when wrong or missing. Ignore bot noise. No nit spam or broad rewrites. Escalate verification by touched risk: clinical / RAG / privacy / migrations / auth → domain check plus production-readiness when warranted; UI / phone-chrome / routing / styling → ensure plus phone-chrome or UI gates when warranted; generated assets or docs inventory/links → asset or docs checks when warranted.

Fix P0/P1 always; clear scoped P2 when locally provable; else disposition and resolve. Required-check failures on this tip only; ignore advisory. Prefer reverting a bad autofix commit. After fixes: format and commit before push; smallest targeted proof; repo cheap gate; repo PR-local gate. No release, lighthouse, live eval, or live provider gates without approval.

Push only this PR’s fix commits. Append ledger for the final GitHub head under the heavy scope. Never push a ledger-only tip—include ledger in a real fix push, or leave a no-change ledger append local and unpushed.

One PR comment: tip, sync/merge-tree, fixed versus dispositioned, threads, required CI, decisive local gate lines, residual risks; merge left to me. Inline only for remaining human-needed P0/P1.

Stop when merge-tree is clean on the current GitHub tip, actionable threads are clear, required checks are green or clearly in progress, heavy gates for scope passed, summary posted, merge left to me.

@cursor

cursorBot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

PR #1532 worked end-to-end at tip 3dc8bfe2fa1b0bd0a16f2e9a86fa4bbdbcae3b79.

Done

  • Confirmed sole open PR context → fix: remediate the PR #1489 review findings #1532; fetched matching GitHub head; no review threads
  • Cleared real merge conflict (docs/outstanding-issues.md): merged origin/main, kept main’s queue, renumbered follow-ups #169#172#175#178
  • P1 fixed:modality scrub now applies to the full catalogue (detail/recommend path), not only index projections; tests pin both; new hash therapies.ac849069245cbf11.json, previous retained
  • P2 dispositioned: grace window = one content-changing regeneration (comments aligned)
  • Pushed merge + fix; auto-merge left armed; merge left to you
  • Summary posted on the PR

State now

  • MERGEABLE, merge-tree clean, CI in progress (Static PR checks, Build, Production UI critical, …)
  • Local: verify:cheap 449 files / 4705 pass; verify:pr-local format + bundle + RAG 36; therapy index + pr-policy green
  • Phone-chrome contracts 116 pass; 1 short-runway geometry fail is env-only (same on pre-merge tip)
  • Ledger row left local/unpushed (would be ledger-only tip)
Open in WebOpen in Cursor

@BigSimmo

Copy link
Copy Markdown
OwnerAuthor

@CodeRabbit open PR review

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0)📘 Rule violations (0)📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Prefer main's shared outstanding-issues queue. Main claimed #169#174 while
this branch was open, so the four PR #1489 remediation follow-ups move to
#175#178 with next-id=179.
Detail and recommend load catalogue: "full", not the index projections.
curatedModality was only applied to the thin indexes, so the chips and
related-therapy same-modality boost still used ECT→ACT and similar
mislabels. Write the curated full payload, pin the echo invariant on
THERAPY_CATALOGUE_ASSETS.full, and align the grace-window comments with
content-driven rotation.
@BigSimmo

Copy link
Copy Markdown
OwnerAuthor

@cursoragent Work the current open PR end-to-end. Confirm the PR number and GitHub head first from context. If more than one open PR could apply, stop and say which one you would use and why.

Fetch and start from the remote tip that matches that GitHub head. If the named branch ref is missing or stale, use the PR head ref. Preserve unrelated local WIP, including any local-only ledger commits; do not discard dirty work, and do not treat a local-ahead commit as the reviewed tip. Do not merge the PR, force-push, rebase, or arm auto-merge unless I explicitly ask. No provider-backed gates without separate approval. If you cannot push or resolve threads, diagnose and comment only; if inline replies fail, resolve when possible and put dispositions in the summary comment. If auto-merge is already armed, push only for a real blocker, and avoid pushes that would cancel in-flight required CI unless the push itself clears that blocker.

If the PR is already merged or closed: confirm the head and merge commit, note required-CI outcome, post one summary, and stop.

Goal: deep review plus Bugbot, fix actionable issues with the smallest correct changes, clear merge / required-CI / thread blockers, run strong local offline verification, push fixes, append the review ledger, and post one PR summary. Prefer thoroughness over speed. Regenerate large assets only when a fix requires it; then run the asset check and keep compatibility aliases byte-identical where the repo uses them.

Snapshot the GitHub head SHA: tip, base, behind/ahead, mergeable state, merge-tree versus origin/main (real conflict versus behind-but-clean), required checks on that tip including Production UI when selected, advisory separately, unresolved actionable threads. Missing checks while dirty are not green. If the tip moves mid-work, re-snapshot and continue from the new head.

Ledger-lookup against that GitHub head under the heavy review-and-fix scope for this PR. Already reviewed at this head with clean merge-tree, green required checks, and no new actionable threads → summarize, comment, stop unless I asked for a fresh superseding pass. Follow the repo review protocol.

Unblock once: real conflict → merge origin/main (prefer main’s shared queues; keep this PR’s notes); behind-but-clean → one sync, late if required CI is in flight; clean → leave. Labels like skip-branch-sync do not block a manual sync needed to clear a real blocker. No sync thrash. After any sync or push, re-snapshot tip, merge-tree, and required checks before declaring done. Dedupe the ledger if a merge touched it.

Review high-confidence delta risks only. Separate PR-introduced defects from pre-existing re-emitted debt. For generated assets, review contracts, aliases, cache, and manifests—not every generated line. If protected RAG or ranking surfaces are touched, say so before editing; fix PR-body policy text only when wrong or missing. Ignore bot noise. No nit spam or broad rewrites. Escalate verification by touched risk: clinical / RAG / privacy / migrations / auth → domain check plus production-readiness when warranted; UI / phone-chrome / routing / styling → ensure plus phone-chrome or UI gates when warranted; generated assets or docs inventory/links → asset or docs checks when warranted.

Fix P0/P1 always; clear scoped P2 when locally provable; else disposition and resolve. Required-check failures on this tip only; ignore advisory. Prefer reverting a bad autofix commit. After fixes: format and commit before push; smallest targeted proof; repo cheap gate; repo PR-local gate. No release, lighthouse, live eval, or live provider gates without approval.

Push only this PR’s fix commits. Append ledger for the final GitHub head under the heavy scope. Never push a ledger-only tip—include ledger in a real fix push, or leave a no-change ledger append local and unpushed.

One PR comment: tip, sync/merge-tree, fixed versus dispositioned, threads, required CI, decisive local gate lines, residual risks; merge left to me. Inline only for remaining human-needed P0/P1.

Stop when merge-tree is clean on the current GitHub tip, actionable threads are clear, required checks are green or clearly in progress, heavy gates for scope passed, summary posted, merge left to me.

@cursor

cursorBot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Taking a look!

Open in WebOpen in Cursor

@coderabbitai

coderabbitaiBot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
repo="BigSimmo/Database"
pr="1532"echo"== Pull request snapshot =="
gh pr view "$pr" --repo "$repo" --json number,state,url,title,headRefName,headRefOid,baseRefName,baseRefOid,isDraft,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,labels
echoecho"== Changed files and commits =="
gh pr view "$pr" --repo "$repo" --json files,commits --jq '{files: [.files[] | {path, additions, deletions}], commits: [.commits[] | {oid, messageHeadline}]}'echoecho"== Reviews and review comments =="
gh api "repos/$repo/pulls/$pr/reviews?per_page=100" --paginate \
--jq '.[] | {id, user: .user.login, state, submitted_at, body}'||true
gh api "repos/$repo/pulls/$pr/comments?per_page=100" --paginate \
--jq '.[] | {id, user: .user.login, path, line, side, in_reply_to_id, created_at, body}'||trueechoecho"== Local checkout state =="
git status --short --branch
echo"HEAD=$(git rev-parse HEAD)"
git remote -v
git branch -vv
echoecho"== Remote PR refs and main =="
git ls-remote origin "refs/pull/$pr/head""refs/heads/main""refs/heads/*"| head -n 80

Length of output: 7218


🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
base="ed849c7f04401536e1324688cf5d28b7af64e0b0"
head="b4e97e4774468707e67f30e3d13e48be8de91ca3"echo"== Merge base and ahead/behind =="
merge_base="$(git merge-base "$base""$head")"printf'merge_base=%s\n'"$merge_base"
git rev-list --left-right --count "$base...$head"echoecho"== Merge-tree conflict paths =="
git merge-tree --write-tree "$base""$head">/tmp/pr1532-merge-tree.out 2>/tmp/pr1532-merge-tree.err ||true
cat /tmp/pr1532-merge-tree.err
grep -nE 'CONFLICT|<<<<<<<|=======|>>>>>>>' /tmp/pr1532-merge-tree.out ||true
sed -n '1,240p' /tmp/pr1532-merge-tree.out
echoecho"== Changed handwritten hunks =="
git diff --unified=60 "$base...$head" -- \
scripts/build-therapies-index.mjs \
scripts/lib/escape-false-openai-key-signatures.mjs \
scripts/pr-policy.mjs \
src/components/ClinicalDashboard.tsx \
src/components/clinical-dashboard/global-search-shell.tsx \
src/components/clinical-dashboard/use-hide-on-scroll.ts \
src/components/therapy-compass/data/generated-assets.ts \
src/components/therapy-compass/data/use-therapy-data.ts \
tests/escape-false-openai-key-signatures.test.ts \
tests/therapy-compass-data-recovery.dom.test.tsx \
tests/therapy-compass-mode-wiring.test.ts \
tests/therapy-compass-pathways.test.ts \
tests/use-hide-on-scroll.test.ts \
.github/workflows/ci.yml \
docs/outstanding-issues.md
echoecho"== AST outlines for changed implementation files =="
ast-grep outline scripts/build-therapies-index.mjs --items all --view expanded
ast-grep outline scripts/pr-policy.mjs --items all --view expanded
ast-grep outline src/components/clinical-dashboard/use-hide-on-scroll.ts --items all --view expanded
ast-grep outline src/components/therapy-compass/data/use-therapy-data.ts --items all --view expanded

Length of output: 201968


🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
base="ed849c7f04401536e1324688cf5d28b7af64e0b0"
head="b4e97e4774468707e67f30e3d13e48be8de91ca3"
merge_base="$(git merge-base "$base""$head")"echo"== Merge-tree conflict paths =="
git merge-tree --write-tree --name-only --messages "$base""$head"2>&1||trueechoecho"== Paths changed by main since the branch point and also by this PR =="
comm -12 \
<(git diff --name-only "$merge_base..$base"| sort) \
<(git diff --name-only "$merge_base..$head"| sort)echoecho"== Full-catalogue modality evidence =="
python3 - <<'PY'import jsonfrom pathlib import Pathroot = Path(".")full = json.loads((root / "public/therapy-compass-data/therapies.json").read_text())index = json.loads((root / "src/data/therapies-index.json").read_text())names = {"ECT", "rTMS", "Psychoanalysis", "Psychodynamic Psychotherapy"}for label, records in (("full-alias", full), ("server-index", index)): by_name = {record.get("name"): record for record in records} print(f"{label}: records={len(records)}") for name in sorted(names): record = by_name.get(name) print(f" {name}: modality={record.get('modality') if record else '<missing>'!r}, tags={record.get('tags') if record else '<missing>'!r}") echoes = [ record["name"] for record in records if record.get("modality") and record.get("modality") in record.get("tags", []) ] print(f" modality echoes tags: {len(echoes)}")PYechoecho"== Direct modality consumers and full-catalogue route selection =="
rg -n -C 4 --glob '*.{ts,tsx}' \
'(?:\.modality\b|modality:|catalogue:\s*"full"|screen === "(?:search|recommend|compare)")' \
src/components src/lib tests | head -n 500
echoecho"== Full asset generation and asset manifest context =="
sed -n '150,280p' scripts/build-therapies-index.mjs
sed -n '1,180p' src/components/therapy-compass/data/use-therapy-data.ts

Length of output: 2548


🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
base="ed849c7f04401536e1324688cf5d28b7af64e0b0"
head="b4e97e4774468707e67f30e3d13e48be8de91ca3"
merge_base="$(git merge-base "$base""$head")"
git diff --name-only "$merge_base..$base"| sort > /tmp/pr1532-base-paths.txt
git diff --name-only "$merge_base..$head"| sort > /tmp/pr1532-head-paths.txt
echo"== Paths changed by main since the branch point and also by this PR =="
comm -12 /tmp/pr1532-base-paths.txt /tmp/pr1532-head-paths.txt ||trueechoecho"== Full-catalogue modality evidence =="
python3 - <<'PY'import jsonfrom pathlib import Pathroot = Path(".")full = json.loads((root / "public/therapy-compass-data/therapies.json").read_text())index = json.loads((root / "src/data/therapies-index.json").read_text())names = {"ECT", "rTMS", "Psychoanalysis", "Psychodynamic Psychotherapy"}for label, records in (("full-alias", full), ("server-index", index)): by_name = {record.get("name"): record for record in records} print(f"{label}: records={len(records)}") for name in sorted(names): record = by_name.get(name) if record is None: print(f" {name}: <missing>") else: print(f" {name}: modality={record.get('modality')!r}, tags={record.get('tags')!r}") echoes = [ record["name"] for record in records if record.get("modality") and record.get("modality") in record.get("tags", []) ] print(f" modality echoes tags: {len(echoes)}")PYechoecho"== Direct modality consumers and full-catalogue route selection =="
rg -n -C 4 --glob '*.{ts,tsx}' \
'(?:\.modality\b|modality:|catalogue:\s*"full"|screen === "(?:search|recommend|compare)")' \
src/components src/lib tests | head -n 500
echoecho"== Full asset generation context =="
sed -n '150,280p' scripts/build-therapies-index.mjs

Length of output: 23520


🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
repo="BigSimmo/Database"
head="b4e97e4774468707e67f30e3d13e48be8de91ca3"echo"== Numbered finding locations =="
nl -ba scripts/build-therapies-index.mjs | sed -n '84,125p;160,205p'
nl -ba src/components/therapy-compass/data/use-therapy-data.ts | sed -n '35,75p'
nl -ba src/components/therapy-compass/screens/detail-screen.tsx | sed -n '40,55p'
nl -ba src/components/therapy-compass/screens/recommend-screen.tsx | sed -n '108,120p'
nl -ba src/components/therapy-compass/data/select.ts | sed -n '108,123p'
nl -ba tests/therapy-compass-pathways.test.ts | sed -n '205,232p'echoecho"== GitHub Actions runs for the reviewed head =="
gh api "repos/$repo/actions/runs?head_sha=$head&per_page=100" \
--jq '.workflow_runs[] | {name, status, conclusion, event, html_url, run_started_at, updated_at}' \
||trueechoecho"== Current GitHub PR snapshot =="
gh pr view 1532 --repo "$repo" \
--json state,headRefOid,baseRefOid,mergeable,mergeStateStatus,statusCheckRollup \
--jq '{state, headRefOid, baseRefOid, mergeable, mergeStateStatus, checks: [.statusCheckRollup[] | {name, status, conclusion, workflowName}]}'

Length of output: 1535


🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
repo="BigSimmo/Database"
head="b4e97e4774468707e67f30e3d13e48be8de91ca3"echo"== Numbered finding locations =="
cat -n scripts/build-therapies-index.mjs | sed -n '84,125p;160,205p'
cat -n src/components/therapy-compass/data/use-therapy-data.ts | sed -n '35,75p'
cat -n src/components/therapy-compass/screens/detail-screen.tsx | sed -n '40,55p'
cat -n src/components/therapy-compass/screens/recommend-screen.tsx | sed -n '108,120p'
cat -n src/components/therapy-compass/data/select.ts | sed -n '108,123p'
cat -n tests/therapy-compass-pathways.test.ts | sed -n '205,232p'echoecho"== GitHub Actions runs for the reviewed head =="
gh api "repos/$repo/actions/runs?head_sha=$head&per_page=100" \
--jq '.workflow_runs[] | {name, status, conclusion, event, html_url, run_started_at, updated_at}' \
||trueechoecho"== Current GitHub PR snapshot =="
gh pr view 1532 --repo "$repo" \
--json state,headRefOid,baseRefOid,mergeable,mergeStateStatus,statusCheckRollup \
--jq '{state, headRefOid, baseRefOid, mergeable, mergeStateStatus, checks: [.statusCheckRollup[] | {name, status, conclusion, workflowName}]}'

Length of output: 14072


@BigSimmo, I reviewed open PR #1532 at GitHub head b4e97e4774468707e67f30e3d13e48be8de91ca3.

Blocking finding

P1 — The full Therapy Compass payload still publishes inferred modality values.

Line 96 and Line 114 in scripts/build-therapies-index.mjs sanitize modality only in the server and browser index projections. However, Lines 182-184 hash public/therapy-compass-data/therapies.json without transforming it.

The full alias has all 205 tag-derived values. For example:

  • ECT: ACT
  • rTMS: ACT
  • Psychoanalysis: CBT
  • Psychodynamic Psychotherapy: CBT

Record-rich routes load this full asset. The value still renders on the detail screen at src/components/therapy-compass/screens/detail-screen.tsx, Line 49, and on the recommend screen at src/components/therapy-compass/screens/recommend-screen.tsx, Line 115. It also still adds a related-therapy score at src/components/therapy-compass/data/select.ts, Line 117.

The new coverage only checks src/data/therapies-index.json at tests/therapy-compass-pathways.test.ts, Lines 206-230. It cannot detect the incorrect full browser payload.

Generate the full catalogue from sanitized records, or sanitize modality in the source before writing and hashing all public full assets. Add a test that reads the full alias and current hashed full asset. It must assert that no record has a modality that also occurs in its tags. Then regenerate the assets.

Merge and CI state

  • PR #1532 has a real content conflict in docs/outstanding-issues.md.
  • This is the only path changed by both main and this PR since the merge base.
  • GitHub reports mergeable: CONFLICTING and mergeStateStatus: DIRTY.
  • Required PR mergeability is failed.
  • PR policy is successful.
  • No CI workflow ran for this head. Do not treat the current checks as a green validation.

Resolve the one documentation conflict, include the clinical fix in the same push, then re-snapshot the GitHub head and checks. Run npm run check:therapy-data-index, the focused Therapy Compass tests, npm run verify:cheap, and the required phone-chrome/UI gates after the sync.

  • Resolve the single merge conflict against main.
  • Sanitize modality in the full Therapy Compass payload.
  • Add regression coverage for the full alias and hashed full asset.
  • Regenerate the affected assets and run the offline gates.

Failed to handle agent chat message. Please try again.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ecc-tools

ecc-toolsBot commented Jul 31, 2026

Copy link
Copy Markdown

🔒 Upgrade Required

Private repository analysis requires Pro or Enterprise.

Upgrade: https://ecc.tools/pricing?plan=pro


ECC Tools keeps the core app open, and puts private repos, team features, and enterprise controls behind paid tiers.

@cursor

cursorBot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

PR #1532 babysit summary (heavy review-and-fix)

Tip:3dc8bfe2fa1b0bd0a16f2e9a86fa4bbdbcae3b79 on claude/pr-1489-review-786e01
Base:origin/main @ ed849c7fmerge-tree clean (was real conflict in docs/outstanding-issues.md only).
Ahead/behind: 6 / 0 after sync. Auto-merge: left armed (squash). Merge: left to you.

Sync

  • Merged origin/main once to clear DIRTY/CONFLICTING (required CI could not build refs/pull/1532/merge).
  • Preferred main’s shared outstanding-issues queue; renumbered this PR’s follow-ups #169#172#175#178 (next-id=179) because main had claimed #169#174.

Review findings

SeverityItemDisposition
P1Inferred modality was scrubbed only on index projections; detail/recommend load catalogue: "full" and still showed ECT→ACT etc.FixedcuratedModality now applied when writing the full public catalogue + hashed asset; tests pin the echo invariant on THERAPY_CATALOGUE_ASSETS.full as well as the server index. New full hash therapies.ac849069245cbf11.json; previous a9dc3ae40e9d29fa retained for grace.
P2Grace window comments said “one deploy” but rotation is one content-changing regeneration; alias fallback only helps post-fallback bundles.Dispositioned — comments aligned to content-driven rotation; mechanism left as designed for this tip (current+previous kept; aliases byte-identical).
sourceChanged still above top-reveal (#176)Pre-existing / tracked; not expanded here.
Phone short-runway UI: maxOffset 99 vs expected >140Not PR-introduced — same failure on pre-merge tip b4e97e47 in this environment (geometry/calibration); fails before any hide-on-scroll assertion.

Threads: 0 unresolved (none to fix/resolve). Bot noise ignored.

Required CI (this tip)

In progress after the conflict-clearing push (Change scope queued; PR mergeability / Gitleaks / Semgrep in progress). Missing checks while dirty are no longer the state — tip is mergeable.

Local gates (decisive lines)

  • npm run verify:cheapTest Files 449 passed (449) / Tests 4705 passed | 4 skipped (4709)
  • npm run verify:pr-localAll matched files use Prettier code style! + Client bundle secret surface check passed. + Offline RAG fixture and manifest validation passed (36 golden cases, 23 suites).
  • npm run check:therapy-data-indexTherapy indexes are current (205 records).
  • npm run check:pr-policy[pr-policy] self-test passed
  • verify:phone-chrome contracts — Test Files 9 passed (9) / Tests 116 passed (116); focused-browser 12 passed, 1 failed (env short-runway geometry above); full-ui not reached after focused-browser exit.

Residual risks

  • #175 still open: curate real modality values or drop the field entirely (chips now correctly absent).
  • #176sourceChanged ordering; #177 alias byte duplication; #178 operational+clinical bundling advisory.
  • Hosted Production UI may still see the short-runway geometry assert if CI shares this calibration; treat as env/test debt unless it fails only on this tip.

Ledger row for this head appended locally and left unpushed (would be a ledger-only tip). Merge left to you.

@BigSimmo

Copy link
Copy Markdown
OwnerAuthor

@cursoragent why does this show 42000 as code changes?

@cursor

cursorBot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Almost none of that is handwritten code. GitHub’s +42,071 is dominated by regenerated Therapy Compass JSON.

File≈ linesWhy
public/therapy-compass-data/therapies.json+18,400Full catalogue rewritten when modality was scrubbed (null on all 205 records)
public/therapy-compass-data/therapies.ac849069245cbf11.json+18,400New content-addressed copy of that same full payload
therapies-index.8455f92cf736cbfa.json+4,480New hashed index projection
Everything else (scripts, tests, phone-chrome, CI, docs)~1kActual review remediation

So ~41k of the 42k is the ~2.5 MB catalogue duplicated as alias + hash (and the index hash). GitHub counts every rewritten JSON line as an addition, even when the real clinical change is “set modality to null.”

The meaningful diff is the generator/loader/policy/scroll-hide changes — a few hundred lines, not 42k of product logic.

Open in WebOpen in Cursor

BigSimmoand others added 2 commits July 31, 2026 19:53
Writing the scrubbed full payload through pretty-printed syncTarget
turned a modality-null scrub into ~18k-line alias + hashed-twin diffs.
Restore the historical single-line JSON shape for the full catalogue,
pin it in --check and tests, prune the pretty intermediate hash, and
keep the deployed a9dc3ae generation as the grace previous.
@ecc-tools

ecc-toolsBot commented Jul 31, 2026

Copy link
Copy Markdown

🔒 Upgrade Required

Private repository analysis requires Pro or Enterprise.

Upgrade: https://ecc.tools/pricing?plan=pro


ECC Tools keeps the core app open, and puts private repos, team features, and enterprise controls behind paid tiers.

…to claude/pr-1489-review-786e01
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
@ecc-tools

ecc-toolsBot commented Jul 31, 2026

Copy link
Copy Markdown

🔒 Upgrade Required

Private repository analysis requires Pro or Enterprise.

Upgrade: https://ecc.tools/pricing?plan=pro


ECC Tools keeps the core app open, and puts private repos, team features, and enterprise controls behind paid tiers.

@cursor

cursorBot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Follow-up: fixed the ~42k “code changes” inflation

Tip:668a4895 (includes remote main sync 773ab4d8 + compact-catalogue fix)

Cause

The full Therapy catalogue on main is one minified JSON line (~2.5 MB). The modality scrub wrote it through pretty-printed syncTarget (JSON.stringify(..., null, 2)), so GitHub counted:

  • ~18.4k lines for therapies.json
  • ~18.4k lines for the new hashed twin
    36k of formatting churn, not product logic.

Fix

  • Full catalogue writes stay compact single-line (syncFullCatalogue); projections remain pretty
  • --check + a pathways test pin “no newlines in the full asset”
  • Pruned the pretty intermediate hash; grace previous stays the deployed therapies.a9dc3ae40e9d29fa.json
  • Current full: therapies.d0358686e452b00b.json

Diff size

  • Before: +42,071 / −437
  • After: on the order of ~+5.3k / −437 (remaining bulk is the hashed index projection from the original remediation, still pretty by design)

Checks

  • verify:cheap: Test Files 449 passed / Tests 4706 passed
  • check:therapy-data-index: Therapy indexes are current (205 records).
  • merge-tree vs origin/main: clean

Merge left to you. Ledger row for this head left local/unpushed (ledger-only tip).

@BigSimmo
BigSimmo enabled auto-merge (squash) July 31, 2026 12:10
@BigSimmo
BigSimmo merged commit 6c50596 into mainJul 31, 2026
25 checks passed
@BigSimmo
BigSimmo deleted the claude/pr-1489-review-786e01 branch July 31, 2026 12:10
BigSimmo added a commit that referenced this pull request Jul 31, 2026
#179: the full catalogue silently went from a single minified line to 18,400
pretty-printed ones when the modality scrub routed it through syncTarget.
Measured +123 KB raw but only +3.4 KB gzipped, so the real cost is ~37,000
lines of git churn per data revision — set against reviewable diffs on a
205-record clinical dataset, which is probably the better trade. Recorded so
the format is a decision rather than a side effect.
#180: that same change made the generator write its curated output back over
the file it reads as source. It is stable only because curatedModality is a
fixed point, and it matters because #175 asks someone to hand-curate modality
values in exactly that file — an edit the next run could discard with no gate
to catch it, since --check compares against what the generator would produce.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

2 participants

@BigSimmo@cursoragent