Skip to content

Fix answer search URL chat loading - #316

Merged
BigSimmo merged 5 commits into
mainfrom
cursor/fix-answer-search-chat-d1ea
Jul 6, 2026
Merged

Fix answer search URL chat loading#316
BigSimmo merged 5 commits into
mainfrom
cursor/fix-answer-search-chat-d1ea

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • Ensure answer-mode run=1 searches submit the URL query into the chat flow instead of rendering the answer home copy.
  • Add Playwright regression coverage for direct answer search URLs while the answer request is still in flight.
  • Merged latest origin/main, accepted the Bugbot Autofix guard for non-runnable answer searches, and formatted the final PR head.

Walkthrough

answer_search_url_recheck_merge_ready.mp4

Answer search URL recheck loading state

Verification

  • npm run format:check
  • npm run test:e2e:chromium -- tests/ui-smoke.spec.ts -g "answer search URL opens chat without the answer home copy"
  • npm run verify:cheap
  • npm run verify:ui when UI, routing, styling, browser behavior, reduced-motion, or forced-colors behavior changed
  • npm run check:production-readiness:ci
  • GitHub CI verify
  • GitHub CI ui-smoke
  • GitHub Secret Scan / Gitleaks
  • npm run verify:release before release or handoff confidence claims — not run; release gate is broader than this focused UI/routing fix.
  • npm run eval:retrieval:quality — not applicable; no retrieval/ranking/scoring behavior changed.
  • npm run eval:rag -- --limit 15 + npm run eval:quality -- --rag-only — not applicable; no answer generation or synthesis prompt changes.
  • npm run check:edge:functions locally — command exits cleanly but skips because Deno v2 is not installed in this VM; GitHub CI installs Deno and passed verify.

Clinical Governance Preflight

Not applicable; this change is limited to answer-mode URL submission and loading/home-state rendering.

Notes

  • Manual walkthrough confirms the answer home copy is absent and the submitted URL shows an active loading/chat state.
  • The PR is git-mergeable and checks are green; GitHub still reports mergeStateStatus: BLOCKED, likely due to repository merge policy/review requirements.

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
@supabase

supabase Bot commented Jul 6, 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 ↗︎.

@BigSimmo
BigSimmo marked this pull request as ready for review July 6, 2026 06:16
@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.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Indefinite answer loading skeleton
    • Gated submittedAnswerSearchActive on canRunSearch so answer-mode URLs that cannot auto-run show the answer home instead of a perpetual loading skeleton.

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 7828552. Configure here.

Comment thread src/components/ClinicalDashboard.tsx Outdated
cursoragent and others added 4 commits July 6, 2026 06:19
…rch-chat-d1ea

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Gate submittedAnswerSearchActive on canRunSearch so auto-run URLs that
cannot start a search show the answer home instead of a perpetual loading
skeleton when the auto-run effect exits without calling ask.
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
@BigSimmo
BigSimmo enabled auto-merge July 6, 2026 07:41
@BigSimmo
BigSimmo merged commit d421527 into main Jul 6, 2026
5 checks passed
@BigSimmo
BigSimmo deleted the cursor/fix-answer-search-chat-d1ea branch July 8, 2026 16:25
BigSimmo pushed a commit that referenced this pull request Aug 14, 2026
Immutable inbox request; docs/outstanding-issues.md is untouched and is
reconciled separately after this PR lands.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BKNFogaYfCQBvFVqFQnfRt
BigSimmo added a commit that referenced this pull request Aug 14, 2026
BigSimmo pushed a commit that referenced this pull request Aug 14, 2026
…be evidence (#316, #231)

Fills the 2026-08-14 owner-authorized incident evidence into the live-drift
forensics record: Phase 1.1 migration-history fingerprint (20260705180000
executed with 14 statements; the two trigram indexes existed at the 2026-08-04
guard and were dropped by 2026-08-09), Phase 1.3 partial inventory, Phase 4
partial restore (CREATE INDEX CONCURRENTLY, both indisvalid/indisready), and
Phase 5 before/after probes (supabase_rpc_latency_ms 31610 -> 1535 text /
8519 hybrid). Carries the PR #1939 review ledger record and queues merge-safe
issue updates for #316 and #231.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JpjrUp4fYmiDGfc6NBqACX
BigSimmo added a commit that referenced this pull request Aug 14, 2026
…hvja

docs(audit): 2026-08-14 incident forensics and live index restore evidence (#316, #231)
BigSimmo pushed a commit that referenced this pull request Aug 14, 2026
Four merge-safe inbox requests; docs/outstanding-issues.md is untouched and is
reconciled separately after this PR lands.

- update #316: Phase 0 closed, including the forced-dispatch proof (run
  31813064485 -> auto-created issue #1963). Also supersedes the stale 2026-08-09
  drift figures with measured ones: 10 RPC mismatches unchanged, 20 missing
  indexes, 2 unexpected, and the two trigram indexes confirmed restored.
- done #331: its comparison-bug hypothesis is refuted; the staleness was real
  and wrapping-only, inherited from main by every branch.
- update #333: the regeneration half is done here; its real question - the check
  runs in verify:pr-local but in no CI job - stays open.
- update #292: records the #1938/#1939 Phase 0 duplicate against the existing
  duplicate-work row rather than opening a near-identical new one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BKNFogaYfCQBvFVqFQnfRt
BigSimmo pushed a commit that referenced this pull request Aug 14, 2026
…e record

Two pending mutations targeted #316 - this branch's dispatch-proof update and
the incident session's restoration update from PR #1960 - which the inbox
correctly refuses to apply without an explicit decision. Cancelled both and
queued a single combined update so the row carries one coherent account.

The combined text keeps the incident findings verbatim (both indexes restored
and validated, supabase_rpc_latency_ms 31610 -> 1535 text / 8519 hybrid, the
drop window, the outstanding dashboard-audit attribution) and corrects two
details that PR #1960's own review and the 2026-08-14 dispatch have since
settled: the 20260804110240 guard validates four OTHER indexes and never checks
this pair, so it gives no existence bound for 2026-08-04; and the missing-index
count is measured at 20, not 21.

Also cancels a placeholder request queued in error by a failed shell
substitution.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BKNFogaYfCQBvFVqFQnfRt
BigSimmo added a commit that referenced this pull request Aug 15, 2026
BigSimmo added a commit that referenced this pull request Aug 15, 2026
BigSimmo added a commit that referenced this pull request Aug 15, 2026
BigSimmo added a commit that referenced this pull request Aug 17, 2026
…) (#2044)

* docs(db): add coordination handover for multi-chat remediation oversight

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L7umYGe6hbCfq3NmpZ4Gz4

* docs(db): re-baseline the remediation coordination board to main (#316)

Carries the coordination handover onto the coordination-chat branch and corrects it
against the repository record as of main f5b0932: the tracking anchor is #316 (not
#312), Phase 0 is complete (#1938/#1939/#1951/#1978), Phase 1 is partial with 1.2 the
only executable next step, Phase 3 is blocked on ten UNCLASSIFIED RPCs, and Phase 4/5
have incident-scope partial evidence. The originating "never executed" verdict is
marked superseded by the Phase 1.1 fingerprint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(ledger): record review of the coordination board PR (#2044)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 17, 2026
…x-monitoring ratchet (remediation Phase 6) (#2058)

* feat(db): migration-history probe, guard-migration contract, and index-monitoring ratchet (remediation Phase 6)

Phase 6 of docs/database-remediation-plan.md, repo-side only. The 6.1 migration is authored and
mirrored but NOT deployed; deployment is a separately approved production window after Phase 4.

- 6.1 `20260818090000_schema_drift_snapshot_history_probe.sql`: schema_drift_snapshot() v2 also
  returns `migration_history` (supabase_migrations versions whose statements are NULL/empty — the
  mark-applied / history-repair fingerprint from forensics §1.1) plus `migration_history_probe`
  (ok | no_history_table | no_statements_column). Mirrored into schema.sql; drift-manifest.json
  regenerated from a Docker replay (probe executed: no_history_table, snapshot_version 2).
- check:drift reports every live no-statements version as `! [migration_history] no_statements`
  unless a structurally valid `migration_history` allowlist entry (reason + guard {class,
  migration, objects}) covers it; the category is never compared manifest-vs-live; a live
  snapshot without the probe prints an info line naming the pending deploy.
- 6.2 Guard-migration contract in docs/database-drift-detection.md + AGENTS.md; guard classes
  validation (mandatory from 2026-08-18) / superseded / no_ddl; tests/migration-history-guards.test.ts
  verifies each allowlisted version's guard file really covers its objects. Seeded five §1.1
  versions with repo-provable superseded guards; the remaining §1.1 rows and the 2026-07-12 batch
  are deliberately unallowlisted (expected first-run findings — they need real guard migrations).
- 6.3 tests/search-health-index-coverage.test.ts + supabase/search-health-unmonitored-indexes.json:
  every repo-defined index on documents, document_chunks, document_index_units,
  document_embedding_fields, document_memory_cards, rag_retrieval_logs is monitored by
  search_schema_health() or explicitly listed with reason + disposition (44 entries, 8
  monitor-candidates incl. the three §1.3-absent indexes on those tables). Failed with exactly 44
  names before the list existed.
- Residual queued via issues:add (deploy window, first-run triage, guard migrations for
  pre-contract rows). #316/#56 untouched (owned by other sessions).

RAG impact: no retrieval behaviour change — observability-only snapshot extension and repo-side tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(ledger): record Phase 6 self-review for PR #2058

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 18, 2026
BigSimmo added a commit that referenced this pull request Aug 18, 2026
…e chain does not reproduce schema.sql (Phase 2, #56) (#2093)

* feat(db): replay the full migration chain onto staging to parity (Phase 2, #56)

Phase 2 of docs/database-remediation-plan.md, run in an owner-authorized
staging window. Target was Clinical KB Staging (ikoiolksxqxfxgiyqpnu) via the
Supabase MCP connector, with the ref re-verified on every call; production
(sjrfecxgysukkwxsowpy) was never a mutation target.

The gap re-measured as 28 versions at the start of the window, not the 26
recorded on 2026-08-17 — ten earlier history holes plus eighteen versions after
20260719055623. The whole chain was replayed in version order. Staging now
holds 194 rows in supabase_migrations.schema_migrations, latest 20260814151000,
zero statements IS NULL, and a two-way version diff against supabase/migrations
is empty. Every replayed row was read back and its md5 compared against md5sum
of the repository file: all 28 match byte-for-byte.

supabase db push was unavailable (SUPABASE_ACCESS_TOKEN absent per #183, staging
DB password operator-only) and MCP apply_migration was rejected because it
stamps connector-generated versions, which docs/staging-setup.md forbids. Each
migration was executed verbatim via execute_sql with an explicit schema_migrations
row carrying the repository's own version and name.

check:drift against staging is not yet proven. scripts/check-drift.ts forwarded
only three of the five identity keys to checkSupabaseProjectConfig, so any
staging URL was rejected as a production mismatch; that narrowing is fixed here,
mirroring scripts/check-supabase-project.ts. The remaining blocker is the staging
service-role key, which is not in this environment and which the MCP connector
cannot supply. The gate was deliberately not run rather than risk pointing it at
production via the only local .env.local.

Six findings from the clean replay are recorded, none patched — notably that the
20260804110240 guard passed with no prebuild because staging never lost the
indexes production lost, that four migrations exist as duplicate earlier/later
version pairs which a plain --include-all push would apply in the wrong effective
order, and that 20260724120000 silently drops the work_mem setting 20260724000000
applies.

No schema file, migration, or drift manifest was changed. No production clinical
document was copied to staging and no ingestion worker was started.

* docs(db): record the staging drift result — the chain does not reproduce schema.sql

check:drift now runs against staging and is red with 19 findings. Because
staging carries the complete, byte-verified migration chain, this is not
staging staleness: it is the committed chain and supabase/schema.sql
disagreeing, and check:drift builds its expected side from schema.sql.

Seven match_* def_hash mismatches are SET work_mem, which pg_get_functiondef
renders and def_hash does not strip. grep -c work_mem supabase/schema.sql
returns 0 and only 20260724000000 sets it, so schema.sql is the stale side and
the fix is repo-side, not a production deploy. The eighth work_mem target,
match_document_table_facts_text, is absent from the drift list precisely
because 20260724120000 re-created it without restating work_mem — the
exception confirms the mechanism.

Eight further objects are declared in schema.sql that no migration creates or
drops: five document_embedding_fields indexes, documents_status_idx, and the
documents_updated_at and ingestion_jobs_updated_at set_updated_at triggers.
Three table column-set mismatches and one index def mismatch remain
unclassified.

This bears on #316's recorded work_mem hypothesis, now measured on staging for
seven of production's ten mismatched RPCs with no production call. It does not
close Phase 1.2 and #316 was deliberately not updated from this session.

The superseded #56 inbox request is cancelled and replaced rather than edited,
per the immutable-request rule.

Measurement base: ed43a64. origin/main has since advanced to 6b72b3a (195
migrations, including a schema_drift_snapshot history probe); re-measuring
against that manifest is recorded as follow-up.

* docs(ledger): record the Phase 2 staging-parity review
BigSimmo added a commit that referenced this pull request Aug 18, 2026
BigSimmo added a commit that referenced this pull request Aug 18, 2026
…traps and the #183 rider (#316)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 18, 2026
BigSimmo pushed a commit that referenced this pull request Aug 18, 2026
…nchor

Two stale pointers in the playbook's context briefing, both of which misdirect a
fresh session before it reads anything else.

The phase status block still said Phase 1.2 was outstanding and gating Phase 3,
and named "complete 1.2, then Phase 2" as the next step. Both have since landed:
1.2 in PR #2087 (all ten mismatches attribute-only SET work_mem, zero body
divergence, zero repo-ahead, zero UNCLASSIFIED) and Phase 2 in PR #2093 (staging
at full parity, check:drift against staging red with 19 items — the finding the
phase existed to produce, with a re-measure owed once staging carries
20260818090000). Phase 6 is repo-side complete with its migration deploy still
owed. The block now records that and defers to
docs/database-remediation-coordination.md as the live board rather than becoming
a second source of truth beside it.

It also flags that Phase 3 has been reframed: zero repo-ahead bodies means no
eval canary, which the Phase 3 prompt further down this file still assumes. That
prompt and the traps list are deliberately left untouched here — the reframing
and its owner decisions belong to the coordination board, and duplicating them
would recreate the drift this change is repairing.

The tracking anchor quoted the row title "Live DB is missing 21 repo-defined
indexes and 10 retrieval RPC bodies diverge". The row has since been retitled to
"Live DB has 20 currently missing repo-defined indexes and 10 retrieval RPC
bodies diverge; weekly live-drift has been red since 2026-07-26 with no routing",
so the exact-title lookup the playbook instructs could no longer match. The "21"
was preserved deliberately in #1979 because it was the lookup key; correcting the
row is what broke it. Anchor updated to the current title, verified character for
character against the row on main.

No issues:update queued: #316 and #56 are owned by other running chats, and a
second pending mutation on either row would make the inbox refuse the batch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BKNFogaYfCQBvFVqFQnfRt
BigSimmo added a commit that referenced this pull request Aug 18, 2026
… schema-only objects, and three chain-stale columns (#316) (#2106)

* feat(db): codify live SET work_mem on the ten match_* RPCs, the eight schema-only objects, and three chain-stale columns (#316)

Database remediation Phase 3, reframed as repo-side codification (owner decisions
D1 codify-as-live, D2 work_mem canary exemption). No function body changed; no
hosted value changed; no production access.

- supabase/schema.sql: `set work_mem = '<live value>'` on all ten match_*
  definitions (128MB on chunks_hybrid, embedding_fields_hybrid,
  index_units_hybrid, index_units_hybrid_v2; 64MB on the other six), including
  the effective uppercase blocks for chunks_hybrid and table_facts_text.
- 20260818110000_codify_live_rpc_work_mem: ALTER FUNCTION ... SET work_mem per
  function, versioned after every recreate. Regenerated drift-manifest def_hash
  for all ten equals the live production def_hash (issue #1963, run
  32051068106) byte-for-byte.
- 20260818111000_codify_schema_only_indexes_and_triggers: the five
  document_embedding_fields indexes, documents_status_idx, and the
  documents_updated_at / ingestion_jobs_updated_at triggers, verbatim from
  schema.sql (forensics 2.3 b); unmonitored-list reasons refreshed.
- 20260818112000_reconcile_chain_stale_table_columns: document_chunks
  .token_estimate (never in any migration) and the rag_visual_eval_cases/runs id
  defaults (20260705230000 bound extensions.gen_random_uuid via search_path
  order) - all idempotent on production.
- forensics section Phase 3 written; #316 update + #183 rider queued as inbox
  requests. Staging proof deliberately not run: Phase 2 re-measure absent on main.

RAG impact: no retrieval behaviour change - codifying already-live SET work_mem
attributes and mirror-only objects; no function body changed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(ledger): review record for PR #2106 (Phase 3 codification)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(issues): queue two Phase 3 follow-ups — check:drift column-diff clip, PR template RAG impact guidance

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(db): close guard-migration loophole and add lock timeouts for PR #2106

Review of the Phase 3 codification migrations found the forensics runbook
offered mark-applied-by-CLI as an equal alternative to db push for the three
new migrations, which would violate the guard-migration contract in
AGENTS.md since none of them ships a validation guard. Narrow the runbook to
require db push (real execution) and forbid migration repair for these
versions.

Also add SET LOCAL lock_timeout / statement_timeout to the two migrations
that take ACCESS EXCLUSIVE locks on hot tables (documents, ingestion_jobs,
document_chunks), matching the existing 20260804110240 guard pattern, so a
production window fails fast instead of queueing behind a long transaction.

No schema.sql change, no function body change, no live Supabase access.

RAG impact: no retrieval behaviour change — same scope as the parent PR
(SET work_mem attribute codification only; this commit only tightens the
production-application runbook and adds lock timeouts to unrelated schema
codification migrations).

* docs(ledger): review record for PR #2106 fix commit

Records the supabase-schema-guardian review of the Phase 3 codification
migrations and the follow-up fix commit at the correct HEAD.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 18, 2026
…ws refreshed, single trgm residual (#316)

Second owner-authorised staging window on ikoiolksxqxfxgiyqpnu: applied
20260818113000 (three hashes now equal manifest/live), refreshed the
111000/112000 history-row text to the merged files, all four rows md5 = repo;
final offline drift comparison = UNEXPECTED DRIFT (1), document_chunks_content_trgm_idx
only. #316 request superseded by one final update.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 18, 2026
BigSimmo pushed a commit that referenced this pull request Aug 18, 2026
One of the two pending #316 requests (10e480da) already had a cancel
from the original batch (8b0650ed, 'superseded within PR #2111').
Cancelled the other stale one (22946f19, whose baseRowFingerprint no
longer matched the current row) and reissued its content -- the more
complete of the two, describing the finished two-window staging proof
-- as a fresh update request against the row's current content.
BigSimmo pushed a commit that referenced this pull request Aug 18, 2026
…fixes)

Runs npm run issues:reconcile from the current main base (9c79fa0),
resolving the branch's original 7-request reconciliation batch plus
the 4 new inbox requests that landed on main after this PR was opened
(the reason it had gone stale). Also resolved a duplicate-target
collision on #316: two pending requests shared the same stale
baseRowFingerprint, one already superseded by an existing cancel from
the original batch, the other reissued fresh with a correct fingerprint
carrying its more complete content forward.

Applied 67 requests total. Verified: check:outstanding-issues (0
pending, 325 applied, guard passed), docs:check-links (full batch-apply
simulation, 1902 references resolve), prettier clean.
BigSimmo added a commit that referenced this pull request Aug 18, 2026
BigSimmo added a commit that referenced this pull request Aug 18, 2026
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 18, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 18, 2026
…he PITR gap (#316)

Board: Phase 4 row moved to COMPLETE 2026-08-19 for production and staging,
with the measured outcome (20 rebuilt, 2 orphans dropped, live-drift 37 -> 16,
staging drift 19 -> 0) and both escalations recorded rather than summarised
away. D4 is recorded as decided OFF and confirmed empirically in that window,
so the explicit-window model the plan assumes is live again and every future
phase needs its own approved window and its own push.

Adds a next-dispatch pointer: the remaining live-drift findings are exactly the
fifteen migration_history rows (#Q5JHBJ), and Phase 4 earned no allowlist entry
for any of them - measured, not skipped, since the intersection between the
objects those versions create and the twenty-two Phase 4 guards validate is
empty.

Queues a P2 for the owner: point-in-time recovery is off on the live project,
so the plan's standing 'restore point before any mutating phase' rule cannot be
met. Phase 4 was safe regardless because every statement was index-only with an
exact one-statement inverse, but that reasoning does not generalise to any
future window that mutates data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 18, 2026
…am index (#316)

The 20260819100200 trigram guard failed the Supabase Preview check on PR #2151,
and it was correct to. A preview branch builds from the migration chain alone,
and the chain permanently produces the wrong definition of
document_chunks_content_trgm_idx.

Root cause: 20260606000000 creates it first as
lower(coalesce(section_heading,'') || ' ' || content); 20260622000000 and
20260705180000 both carry the canonical coalesce(content,'') form but use
CREATE INDEX IF NOT EXISTS, so they are no-ops, and no migration anywhere drops
the index. schema.sql, the drift manifest and production hold the canonical
form; every environment built from migrations alone holds the 2026-06-06 one.
That is not cosmetic - the older expression is NULL for any row with NULL
content, so those chunks are absent from the trigram index entirely.

Forensics 3.3(d) had already seen this and scoped it as staging-only, repairing
it by hand there. It was never staging-only: it is db reset, DR replay, CI
migration replay, and the preview branch. The guard is what converted a silent
environment-specific divergence into a reproducible failure.

The repair is conditional and never runs a write-blocking build on a populated
hosted database: no-op when already canonical, drop-and-recreate when the form
is wrong and the table is empty, and a loud raise when the form is wrong and the
table has rows. Ordered at 100150 so a fresh replay is canonical before 100200
validates it.

Verified by replaying the entire chain into the same scratch Postgres image the
manifest generator uses: without the fix it fails exactly as CI did, with it
204/204 apply and the index is canonical. The no-op path was proven on
production itself - the index OID is unchanged at 1491258 across the push, with
search_schema_health() still ok. Staging took the same migration by the Phase 2
method and its drift comparison stays green.

schema.sql and drift-manifest.json are unchanged: the mirror was already right,
and it was the chain that disagreed with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 18, 2026
check-docs-links failed CI because the inbox refused to plan its batch: two
update mutations were pending on #316 at once - 7a93a5a2 from the 2026-08-18
coordination session, which arrived via a main merge, and b048dbdd from this
Phase 4 session. That is the exact collision the playbook warns about, and it
blocks every ledger read until someone makes an explicit cancellation decision.

Both are cancelled and replaced by one merged update, so neither session's
result is lost. 7a93a5a2 was also partly stale: it recorded D4 as an open owner
decision and listed Phase 4 as remaining, and both are now settled. Its
still-current facts - the RPC-divergence track closing on 2026-08-18 and the
Supabase auto-deploy finding - are carried forward verbatim, alongside the
Phase 4 outcome, the chain-defect fix, and the two owner escalations.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 18, 2026
…guard migrations (#316) (#2151)

* feat(db): Phase 4 — restore 20 missing indexes, drop 2 orphans, land guards (#316)

Owner-authorised off-peak production window against Clinical KB Database
(sjrfecxgysukkwxsowpy). D4 auto-deploy is OFF, so nothing reached production on
merge; every hosted change was made by an explicit named step.

Rebuilt all 20 missing_live indexes with CREATE INDEX CONCURRENTLY using canonical
definitions cross-read against their defining migrations — Batch A 14/14, Batch B
6/6, every one indisvalid AND indisready with normalised pg_get_indexdef matching
canonical. Zero invalid builds, zero retries, zero skips, zero lock waits. No
transactional build was attempted; #102's bare-column indexes were held out.

Dropped both unexpected_live indexes concurrently rather than codifying them: the
repo chain already commands both drops and each is a strict leading-column subset
of a present canonical index. Live now reports 210 public indexes against the
manifest's 210 repo-defined, zero invalid anywhere.

Codified in four migrations, pushed to production by real supabase db push (never
migration repair --status applied; all four history rows carry executed
statements). 20260819100200 discharges the plan 4.4 debt by guarding the two
trigram indexes restored 2026-08-14 that 20260804110240 never checked.
20260819100300 extends search_schema_health() required_indexes 22 -> 30, adopting
all 8 Phase 6.3 monitor-candidates; production reports ok true, missing [].

Staging brought to full parity in the same task: the trigram index was rebuilt into
the canonical coalesce(content,'') form and the drift comparison is now green with
zero unexpected drift, down from 19.

Live-drift run 32171070287: unexpected drift 37 -> 16, missing_live 20 -> 0,
unexpected_live 2 -> 0.

Two escalations recorded rather than absorbed: PITR is not enabled on production
(only daily physical backups), and the migration_history block did not drop because
no guard here validates any object those 15 versions create — an empty intersection,
so no allowlist entry was earned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ledger): record the Phase 4 index-restoration review (#316)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(db): mark Phase 4 complete on the coordination board and queue the PITR gap (#316)

Board: Phase 4 row moved to COMPLETE 2026-08-19 for production and staging,
with the measured outcome (20 rebuilt, 2 orphans dropped, live-drift 37 -> 16,
staging drift 19 -> 0) and both escalations recorded rather than summarised
away. D4 is recorded as decided OFF and confirmed empirically in that window,
so the explicit-window model the plan assumes is live again and every future
phase needs its own approved window and its own push.

Adds a next-dispatch pointer: the remaining live-drift findings are exactly the
fifteen migration_history rows (#Q5JHBJ), and Phase 4 earned no allowlist entry
for any of them - measured, not skipped, since the intersection between the
objects those versions create and the twenty-two Phase 4 guards validate is
empty.

Queues a P2 for the owner: point-in-time recovery is off on the live project,
so the plan's standing 'restore point before any mutating phase' rule cannot be
met. Phase 4 was safe regardless because every statement was index-only with an
exact one-statement inverse, but that reasoning does not generalise to any
future window that mutates data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(db): make the migration chain produce the canonical content trigram index (#316)

The 20260819100200 trigram guard failed the Supabase Preview check on PR #2151,
and it was correct to. A preview branch builds from the migration chain alone,
and the chain permanently produces the wrong definition of
document_chunks_content_trgm_idx.

Root cause: 20260606000000 creates it first as
lower(coalesce(section_heading,'') || ' ' || content); 20260622000000 and
20260705180000 both carry the canonical coalesce(content,'') form but use
CREATE INDEX IF NOT EXISTS, so they are no-ops, and no migration anywhere drops
the index. schema.sql, the drift manifest and production hold the canonical
form; every environment built from migrations alone holds the 2026-06-06 one.
That is not cosmetic - the older expression is NULL for any row with NULL
content, so those chunks are absent from the trigram index entirely.

Forensics 3.3(d) had already seen this and scoped it as staging-only, repairing
it by hand there. It was never staging-only: it is db reset, DR replay, CI
migration replay, and the preview branch. The guard is what converted a silent
environment-specific divergence into a reproducible failure.

The repair is conditional and never runs a write-blocking build on a populated
hosted database: no-op when already canonical, drop-and-recreate when the form
is wrong and the table is empty, and a loud raise when the form is wrong and the
table has rows. Ordered at 100150 so a fresh replay is canonical before 100200
validates it.

Verified by replaying the entire chain into the same scratch Postgres image the
manifest generator uses: without the fix it fails exactly as CI did, with it
204/204 apply and the index is canonical. The no-op path was proven on
production itself - the index OID is unchanged at 1491258 across the push, with
search_schema_health() still ok. Staging took the same migration by the Phase 2
method and its drift comparison stays green.

schema.sql and drift-manifest.json are unchanged: the mirror was already right,
and it was the chain that disagreed with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(issues): resolve the two-pending-mutations collision on #316

check-docs-links failed CI because the inbox refused to plan its batch: two
update mutations were pending on #316 at once - 7a93a5a2 from the 2026-08-18
coordination session, which arrived via a main merge, and b048dbdd from this
Phase 4 session. That is the exact collision the playbook warns about, and it
blocks every ledger read until someone makes an explicit cancellation decision.

Both are cancelled and replaced by one merged update, so neither session's
result is lost. 7a93a5a2 was also partly stale: it recorded D4 as an open owner
decision and listed Phase 4 as remaining, and both are now settled. Its
still-current facts - the RPC-divergence track closing on 2026-08-18 and the
Supabase auto-deploy finding - are carried forward verbatim, alongside the
Phase 4 outcome, the chain-defect fix, and the two owner escalations.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
BigSimmo added a commit that referenced this pull request Aug 20, 2026
…ift can pass (#316) (#2198)

The live-drift workflow's "Align migration history for Supabase Preview" step
has never been able to pass on this project. It read
supabase_migrations.schema_migrations directly through PostgREST with
Accept-Profile, and this project has never exposed that schema to the Data API,
so the read returns 406 PGRST106 every time.

The defect stayed hidden because the drift comparison ran first and always
failed, leaving this step skipped. Phase 6.2 cleared the last drift finding on
2026-08-19, the step ran for the first time ever, and it is now the sole reason
the job concludes failure - and therefore the sole reason pinned issue #1963
stays open against a database whose drift block is empty (run 32378402265,
2026-08-20: "Compare live schema drift: success", "No unexpected schema drift").

20260820120000 adds public.migration_history_versions(): stable, security
definer, search_path pinned to '', dynamic read guarded by to_regclass,
returning {probe, versions} for every history row, revoked from public/anon/
authenticated and granted to service_role alone - the established
schema_drift_snapshot() pattern. Exposing supabase_migrations to the Data API
would widen the public PostgREST surface of a clinical project for one weekly
read; routing through the management API would put an account-scoped token into
CI. Both are recorded as rejected in the forensics file.

check-migration-history-alignment.ts now prefers the RPC and falls back to the
old read only when the function itself is absent. Every other outcome raises,
including probe: no_history_table - a check that reports "aligned" because it
could not look is worse than the red job it replaces.

The migration is NOT deployed: D4 is off, so db push runs from this branch in an
approved window BEFORE merge, the order Phase 4 used. Until it is applied,
check:drift would report migration_history_versions as a missing function.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
BigSimmo pushed a commit that referenced this pull request Aug 21, 2026
… auto-deploy record

Two smallest-safe fixes for the same underlying fact: merging to `main` applies
migrations to the live clinical database automatically, within seconds, with no
deploy step in between.

1. ENFORCEMENT. AGENTS.md says never enable auto-merge on a PR touching
   `supabase/migrations/**`, but nothing enforced it: `scripts/guard-push.mjs` had
   no migration awareness at all, and its auto-merge guard only ever blocked
   force-pushes. `autoMergeVerdict` now takes a `carriesMigration` flag and returns
   `auto-merge-armed-migration` (block, no override) when auto-merge is armed and the
   push carries a hosted migration. The changed-file list was already computed one
   line above the call site, so this threads an existing value through rather than
   adding work to the hook.

   Deliberately narrow: `supabase/schema.sql` is NOT a migration path. It is a mirror
   the integration does not apply, and treating it as one would block ordinary
   schema-mirror pushes for no safety gain. An unarmed PR touching migrations is also
   not blocked — the risk is the unattended merge, not the migration.

   Four cases pinned in `tests/guard-push.test.ts`, including that an ordinary
   fast-forward is still allowed without a migration and blocked with one. The
   fast-forward carve-out exists because GitHub re-validates required checks; that
   does not make an unattended production schema change acceptable. 46/46 pass.

2. LEDGER CORRECTION. `#316` asserts "D4 IS NOW DECIDED: auto-deploy is OFF",
   inferred 2026-08-19 from migrations sitting pending. AGENTS.md now records the
   opposite from a direct dashboard read on 2026-08-21, and notes two earlier sessions
   inferred this wrongly in both directions — this row is one of them. A P1 row
   asserting the safe-sounding answer is how the next migration window gets planned on
   a false premise.

   Queued as an inbox update request, not a direct ledger edit. `updateIssue` replaces
   a cell wholesale, so the correction is PREPENDED to the existing 5,609-character
   evidence record and the original is preserved verbatim — verified by asserting the
   new detail ends with the old one byte-for-byte. Nothing is overwritten.

   The correction also records the combination neither document states: auto-deploy is
   ON while PITR is OFF on the same project (~24h worst-case RPO over 2,851 documents
   and 70,120 chunks), so a bad migration merged to main reaches the live corpus
   unattended and cannot be restored to a fine-grained point. That decision is the
   owner's and stays open.

This closes the automation path only. A human can still arm auto-merge or press
Merge, so the operative controls remain the AGENTS.md rule and the PITR decision.

Verification: 46/46 on tests/guard-push.test.ts, lint clean, typecheck clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKbNfTZM1vzUTRsuAS4Mxv
BigSimmo added a commit that referenced this pull request Aug 21, 2026
…and D4 settled to fact (#316) (#2250)

* docs(db): Phase 5 close-out — measurement baselines, staging parity, D4 settled (#316)

Discharges the last follow-on on `#316` and records the evidence.

- Phase 5 close-out in the forensics dossier: like-for-like end-to-end
  before/after probes (text fast path 31,610 -> 955 ms; hybrid 21,757 ->
  6,720 ms), a new EXPLAIN forward baseline for all four RPCs
  `explain_retrieval_rpc` supports, and the `rag_retrieval_logs` miss-scan
  baseline that §1.3 left pending.
- Records two instrument limits honestly: `explain_retrieval_rpc` exposes only
  an outer `Function Scan` (so plan flips are not observable through it) and
  raises `22023` for the `_v2` RPC family. Extending it is production DDL and
  was deliberately not written in a read-only phase.
- Finding, not absorbed: all 22 restored indexes report `idx_scan = 0` against
  never-reset statistics, including both trigram indexes credited with the
  incident fix, which makes the co-administered `ANALYZE` the better-supported
  explanation for the recovery. Queued as its own ledger item.
- Staging brought to parity: `20260820120000` applied to
  `ikoiolksxqxfxgiyqpnu` by real `db push`; 211 rows, function present,
  `stmt_count 3` matching production.
- Alarm observed clear: live-drift run `32514326022` green on `main`, first
  success since 2026-07-19, pinned issue #1963 auto-closed.
- D4 corrected to the 2026-08-21 dashboard fact ("Deploy to production"
  ENABLED, production branch `main`, automatic branching ON) in both the
  coordination board and the forensics dossier, with the superseded
  safe-either-way reasoning retained and marked rather than deleted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ledger): record the Phase 5 close-out review for claude/phase-5-closeout

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(db): correct three Codex review findings on the Phase 5 close-out

- P1: drop the stale "every future migration needs its own `db push`"
  sentence. With D4 confirmed ON the merge IS the deployment, so a pre-merge
  push puts live ahead of the reviewed repo state and a post-merge push is a
  redundant production mutation. The gate is the post-merge `live-drift` run,
  matching AGENTS.md.
- P2: stop presenting cumulative `pg_stat_user_indexes.idx_scan` as plan-flip
  evidence. It aggregates every workload on the table and no before/after
  delta was captured, so it can show an index is never chosen by anything but
  cannot show that this query changed plan. Plan §5.1's plan-flip deliverable
  is now marked explicitly OPEN rather than discharged.
- P2: correct a false coverage claim. `match_document_index_units_hybrid_v2`
  delegates to `match_document_index_units_hybrid_scoped` over
  `document_index_units`, which none of the four supported RPCs touches, so
  that path has no EXPLAIN baseline at all — not a partial stand-in. Only
  `document_chunks` has a usable v1 sibling.
- Phase 5 status now reads "COMPLETE, two deliverables explicitly OPEN".
- Ledger: cancelled the inbox request carrying the same false claim and
  queued a corrected one, re-graded P3 -> P2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(db): address PR #2250 review — D4 db-push contradiction, measurement limits, timezone

Codex + CodeRabbit review findings on the Phase 5 close-out documentation.

- Remove the mandatory separate production `db push` from the coordination
  board's "Next dispatches". D4 is settled: merging a migration PR to `main`
  IS the production deployment, so a pre-merge push puts the live schema ahead
  of reviewed repo state and a post-merge push is a redundant production
  mutation. Approved-window and green post-merge `live-drift` requirements are
  kept; `db push` is reserved for authorised staging or recovery work.
- Stop treating cumulative `idx_scan` counters as query-plan evidence. Plan
  §5.1's seq-scan -> index-scan deliverable is now recorded as explicitly OPEN,
  with the reason the index-usage read cannot substitute for an inner plan and
  what would actually close it.
- Correct the `_v2` RPC coverage claim. `match_document_index_units_hybrid_v2`
  delegates to `match_document_index_units_hybrid_scoped`, which reads
  `document_index_units`; none of the four profiled RPCs touches that table, so
  it has no EXPLAIN baseline. Only the `document_chunks` half is covered.
- Qualify the "counters have never been reset" conclusion.
  `pg_stat_database.stats_reset IS NULL` rules out a database-wide reset only;
  `pg_stat_reset_single_table_counters(oid)` resets a single relation without
  touching it. The zero-scan observation and the ANALYZE attribution stand as
  well-supported rather than proven, and the follow-up records how to settle it.
- Make the Perth/UTC boundary explicit rather than changing dates. The window
  ran across local midnight: 2026-08-22 Perth is 2026-08-21 UTC, which is why
  records dated 2026-08-21 describe 2026-08-22 measurements.
- Add `text` language identifiers to four fenced blocks (markdownlint MD040).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ApB8NBygQn9cosxCQ8omk9

* docs(ledger): supersede the Phase 5 close-out review record with the decisive gate line

The prior record's checks cell read only "verify:pr-local (11/11, failed: none)".
Repo policy is that evidence is never compressed, so the record now carries the
gate's own summary output verbatim.

The earlier record could not be edited to carry it: check:branch-review-ledger
pins each record's filename to the SHA-256 of its row and rejects any prose
outside that single table row, so an in-place edit fails the gate (reproduced —
"filename must be the SHA-256 content address for its record row"). The
sanctioned route is ledger:append --supersede, which is what this is. It also
records the correct head for the review sweep.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ApB8NBygQn9cosxCQ8omk9

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to 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