Skip to content

fix(access): complete public retrieval scope and production access hardening - #275

Merged
BigSimmo merged 13 commits into
cursor/content-access-review-a385from
cursor/fix-access-review-issues-5c94
Jul 5, 2026
Merged

fix(access): complete public retrieval scope and production access hardening#275
BigSimmo merged 13 commits into
cursor/content-access-review-a385from
cursor/fix-access-review-issues-5c94

Conversation

@BigSimmo

@BigSimmoBigSimmo commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Summary

Completes the public access rollout from the content-access review:

  • Anonymous RAG retrievalPUBLIC_OWNER_FILTER_SENTINEL + retrieval_owner_matches() so anonymous/global retrieval scopes to public documents only
  • API hardening — document read rate limits, owner read scope, catalog auth-signal handling, signed-url guards, anonymous list field redaction
  • UIDocumentViewer public document loading/search for anonymous users; sign-in messaging for private docs
  • E2E — stabilized scope-sources stress test via answer options menu
  • Migrations — retrieval owner filter sentinel, search document chunks owner scope, public document promotion

Verification

  • npm run check:production-readiness — PASS
  • cursor/fix-access-review-issues-5c94 pushed through 85f247ad

Notes

  • Authenticated retrieval semantics unchanged; anonymous users limited to owner_id IS NULL documents
  • Apply new Supabase migrations on live before relying on anonymous RAG in production
Open in WebOpen in Cursor

BigSimmoand others added 11 commits July 3, 2026 21:00
The golden retrieval set was 100% lexical fast-path (embedding_skipped_rate=1.0), so
it could not measure whether a re-index changes vector/embedding retrieval quality.
- forceEmbedding option on searchChunksWithTelemetry (SearchChunksArgs): bypasses every
lexical text-fast-path so retrieval always exercises the embedding/vector stage.
Diagnostic/eval-only; folded into the search cache key; never set on production paths.
- eval-retrieval.ts: per-case `forceEmbedding` field + a global `--force-embedding` flag.
- 10 `vector-*` cases (psychiatric monographs: PTSD, OCD, panic, anorexia, GAD, Tourette,
postnatal, bipolar, ADHD, opioid) with forceEmbedding=true. Each is a clinical query that
must be answered by vector retrieval of the right monograph — verified live at
document_recall@5=1.0, content_recall@5=1.0, all via strategy=hybrid (embedding used).
Rationale: forcing embedding is the correct instrument for re-index measurement — you want
to measure the vector index directly, not have a lexical shortcut mask a regression. Wording
alone can't reliably force the vector path (the fast-path is driven by emergent lexical-match
strength), so the flag makes these probes deterministic.
Live golden eval: 34/34 pass (24 existing + 10 new), no regression. verify:cheap green (980).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wire forceEmbedding through eval runners and retrieval cache keys, bypass coverage/lexical shortcuts when forced, and add golden-case failure metrics so vector regressions cannot hide behind text-fast-path or cache hits.
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=[].
…board
Delete post-extraction dead code left in the monolith and trim unused imports. Also fix minor lint issues in favourites-hub, visual-evidence, and services-navigator.
@supabase

supabaseBot commented Jul 5, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy due to reaching the limit of concurrent preview branches.
Go to Project Integrations Settings ↗︎ if you wish to update this limit.


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

@BigSimmo
BigSimmo marked this pull request as ready for review July 5, 2026 14:45
@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.

@BigSimmo
BigSimmo merged commit d9c9084 into cursor/content-access-review-a385Jul 5, 2026
1 check passed
@BigSimmo
BigSimmo deleted the cursor/fix-access-review-issues-5c94 branch July 9, 2026 12:35
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
…e-local rows
Archived: #179 (compact catalogue restored AND gated at build-therapies-index
.mjs:240-244).
Re-measured: #213 (only 3 empty catches left), #180 (re-confirmed live with
exact source/target lines), #275.
Annotated four machine-local rows (#152, #169, #236, #260) so a cloud session
cannot mistake a fresh container for evidence and close them wrongly.
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 14, 2026
…bt rows (#1942)
* refactor(tokens): re-land the --shadow-tight retirement onto --e1
PR #1803 retired the --shadow-tight role alias in favour of the --e1
elevation tier across 49 files and squash-merged as 9d8370a on
2026-08-10. The acf78bf merge on 2026-08-11 silently reverted it, along
with six other PRs. This re-applies the retirement against current main:
130 call sites across 67 files, plus both declarations.
The alias was a pure pass-through -- `--shadow-tight: var(--e1)` in the
light and dark role blocks -- so the substitution is value-preserving.
Confirmed for forced-colors too rather than assumed: the
`@media (forced-colors: active)` block scopes `:root, .dark`, the same
`html` element the alias is declared on, so `--shadow-tight` already
resolved through the flattened `--e1: none` there. The .ckb-v2
redeclaration hazard does not bite for the same reason -- .ckb-v2 sits on
<html> and .ckb-v2.ckb-v2 outspecifies :root, so both spellings
substitute against the winning v2 tier.
Two comments survived acf78bf while the code they describe did not: the
globals.css note that "the resting-hairline role is gone", and the token
test's "unlike the --shadow-tight assertion above". Both are accurate
again.
The token contract test now sweeps the tracked src tree for both
spellings (declaration and var() consumer) instead of only asserting the
declaration. A declaration-only check would have caught this particular
revert, but only because the declarations happened to come back with the
call sites; sweeping both makes the gate independent of which half of a
bad merge lands. Mutation-verified in both directions.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XsBPUoxpsvTwvFMJzrNoyz
* chore(design-system): re-pin the contract ratchets to their measured values
`scripts/design-system-contract-baseline.json` is a ceiling, so paying
debt down leaves silent headroom behind. Ledger #302 records that
pattern: legacyShadowAliases was pinned at 220 against a measured 193,
27 units of unguarded slack, up from 3 units on 2026-08-10.
With the previous commit's --shadow-tight retirement applied the gap is
wider still -- 220 pinned against 119 measured -- because the reland pays
down the debt the acf78bf revert had re-hidden. Four other ratchets had
accumulated slack from unrelated work in the same window.
legacyShadowAliases 220 -> 119
edgeOwnershipConflicts 27 -> 25
rawPaddingLiterals 67 -> 63
rawGapLiterals 34 -> 32
layoutTransitionExceptions 12 -> 11
Regenerated with --print-debt-baseline rather than hand-edited, so the
per-path debtByPath counts move with the totals -- those are what
findDebtPathRegressions compares, and the retirement moved them
wholesale. Every metric in the diff decreases; nothing is absorbed
upward.
This is not the baseline refresh #262 warns against. That stop rule
forbids refreshing to hide the movement; this pins the movement in so it
cannot silently drift back a second time.
Mutation-verified: reintroducing one alias in button.tsx now fails at
both the total (119 -> 120) and the per-path level. Under the old 220
ceiling the same addition passed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XsBPUoxpsvTwvFMJzrNoyz
* refactor(tokens): hold the search-band count bubble in a spacing token
The active-filter badge sized itself with a raw `h-[1.0625rem]
min-w-[1.0625rem]` pair. Ledger #275 tracks that value as leaked debt:
it had reached five files, so the fix has always been to tokenise once
rather than edit a call site.
Re-measured on merged main, the badge role is down to a single call
site. #170's convergence landed in the meantime -- document-search-
results.tsx now renders the shared control and therapy-compass/
filter-sheet.tsx was deleted outright -- so the leak this row was
written about has already been reabsorbed by the extraction. Holding
the value in @theme is what stops it leaving again.
Two arbitrary values in the same component are deliberately left raw:
pr-[0.6875rem] and min-[414px]:max-[429px] -- the repo defines no
--breakpoint-* tokens at all, and eight peer sites use the same raw
min-[]/max-[] form (359px, 389px, 414px). Naming one window while the
peers stay raw is the same drift #275 warns about on another axis, and
Tailwind named breakpoints would add variants across the whole utility
surface. That belongs in a repo-wide decision, filed separately.
The three remaining 1.0625rem hits in mode-nav.tsx and nav-slot-ink.tsx
are NOT this token. They size <Icon> glyphs -- a 17px icon against a
12/14/16/20/24 --spacing-icon-* scale -- so folding them under a badge
token would merge two roles that only happen to share a number.
check:icon-scale deliberately does not flag arbitrary h-[Nrem], so they
are a real but separate finding, filed rather than guessed at.
The token is also registered in CLINICAL_TWMERGE_THEME.spacing, which
tests/tailwind-merge-config.test.ts asserts against the @theme block --
without it `cn()` cannot resolve a conflict on the new utility. Safe by
that file's own `tap` reasoning: the single call site is a static string
carrying no competing h-*/min-w-* class and never passes through `cn()`,
so there is no same-variant pair for declaration to hand to the later
class. The entry is protective for future use, not load-bearing today.
Value-preserving, and proven rather than inferred: compiling globals.css
through @tailwindcss/postcss emits
.h-search-band-badge { height: var(--spacing-search-band-badge) }
.min-w-search-band-badge { min-width: var(--spacing-search-band-badge) }
No ratchet moved, so the ceilings pinned in the previous commit still sit
at zero slack.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XsBPUoxpsvTwvFMJzrNoyz
* docs(design-system): close out DS Track A3 and refresh the stale gate rows
Track A3 is `#262`. Its three parts are now all settled, each checked
against code rather than against the row that describes it.
Part 1 is the --shadow-tight retirement re-landed earlier in this PR.
Part 3 shipped in PR #1780 per `#301`: rawPaddingLiterals,
rawRadiusLiterals and rawLineHeightLiterals are live baseline keys
enforced over both the class and CSS-declaration spellings, plus
rawGapLiterals beyond the original ask.
Part 2 needs no work, and that had already been adjudicated -- GATES.md
section 3 records it, which is why nothing here builds it. The decidable
half of step selection shipped on 9 Aug inside check:design-system-
contract: a declared @theme step no production surface selects fails the
build. The remaining half -- which existing step a component picks -- is
documented there as something "nothing mechanical can" gate, being a
judgement about the rendered design rather than a property of the source,
with a standing instruction not to duplicate the arbitrary-value check
check:type-scale already ships. Reading `#262` alone would have sent a
session to build it; that is the `#301` failure mode, so the closure
record says so explicitly.
Section 3's live status rows carried numbers this PR moved. `#301`'s
lesson is that a row understating shipped work is a duplicate-work
generator, so they are corrected in the same change:
legacyShadowAliases 224 -> 119, and the alias is now retired
outright rather than "224 left to retire"
edgeOwnershipConflicts 27 -> 25
rawPaddingLiterals 67 -> 63
rawGapLiterals 34 -> 32
layoutTransitionExceptions 12 -> 11
Section 5 is left alone deliberately: it is a dated record measured
against 8db1e53, not a live status surface, and rewriting its figures
would destroy the provenance it exists to hold.
Ledger records are queued as immutable inbox requests: `#262`, `#302` and
`#275` closed; two carve-outs split out of `#275` filed as their own rows
(the repo-wide breakpoint-token decision, and three 17px mode-nav icon
glyphs that sit off the --spacing-icon-* scale with no gate covering
them). The queued re-land request 210e3db5 is cancelled rather than
reconciled -- its headline "67 files on main still use the retired alias"
is false as of this branch, so it would open a row wrong on arrival. The
request file and the cancellation both survive as provenance for the
acf78bf merge loss.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XsBPUoxpsvTwvFMJzrNoyz
* chore(ledger): record the design-token relands review
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XsBPUoxpsvTwvFMJzrNoyz
* fix(issues): retarget the reland record after main reconciled it mid-flight
CI failed `docs:check-links` on this branch with
Error: cancel request 2e791c01... targets missing pending request
210e3db5...
`check-docs-links.mjs` replays the inbox batch to resolve link targets, so
an unresolvable request fails it. The cause was a race, not a bad record:
PR #1936 reconciled 75 queued requests -- 210e3db5 among them -- while
this branch was already in flight. Reconciling moves the request file
into `docs/outstanding-issues-inbox/applied/` and allocates it a canonical
row, so by the time this branch merged main there was no pending request
left for the cancellation to name.
Cancelling was the right call against a pending request and is the wrong
one against a reconciled row. The cancel is dropped and replaced with a
`done` against `#319`, the row 210e3db5 became. That is also the better
record: the work is finished rather than withdrawn, so the ledger should
carry its outcome and its guard, which a cancellation would have thrown
away.
Also merges origin/main (this branch was 3 behind) and files two findings
the PR preflight surfaced, both deliberately not fixed here:
- `check:medication-lexicon-report` has been failing on main for every
local `verify:pr-local`, and no CI job runs it -- a grep over
.github/workflows finds nothing. It is the last step of the local
chain, so it fails preflights while CI stays green. The stale file is
a clinical-facing generated document; regenerating it inside a
CSS-token PR would bundle a clinical-risk artefact with unrelated
chores.
- Claude Code web containers can ship Node 22 with no node_modules,
which fails `npm ci` on engine-strict before any repo script can run.
Re-verified after the merge: the tracked tree still holds zero
`--shadow-tight` references, and every pinned ratchet still measures
exactly its baseline, so the merge moved no metric and the pins stay
honest.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XsBPUoxpsvTwvFMJzrNoyz
* docs(design): retire shadow-tight guidance
* docs(design): retire shadow-tight guidance
* docs(design): retire shadow-tight guidance
* docs(design): retire shadow-tight guidance
---------
Co-authored-by: Claude <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.

1 participant

@BigSimmo