Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,19 +143,16 @@ Read and follow [External skill precedence](docs/agents/native-startup/external-
# Supabase project safety

- This repo targets the live Supabase project `PsychSift Production`.
- **No database change without the owner's explicit permission.** No AI tool, script or automation may change the live database or its settings unless the owner has said yes in words to that specific change. This covers migrations reaching `main`, SQL run against live, roles, grants and RLS policies, Supabase project and dashboard settings (auth, storage, API, network, backups, extensions, branching, integrations), database passwords, keys and access tokens, `supabase/drift-allowlist.json` entries, migration history repair, and resealing migrations (`npm run migrations:reseal`, `ALLOW_MIGRATION_RESEAL`, or any edit to an existing entry in `supabase/applied-migration-hashes.json`). Drafting a migration in an unmerged PR is allowed; a blanket or earlier yes does not cover a later change. See [the decision](docs/decisions/2026-10-15-database-changes-need-owner-permission.md).
- **No database change without the owner's explicit permission.** No AI tool, script or automation may change the live database or its settings unless the owner has said yes in words to that specific change. This covers migrations reaching `main`, SQL run against live, roles, grants and RLS policies, Supabase project/dashboard settings (auth, storage, API, network, backups, extensions, branching, integrations), database passwords/keys/tokens, `supabase/drift-allowlist.json` entries, migration history repair, and resealing migrations (`npm run migrations:reseal`, `ALLOW_MIGRATION_RESEAL`, or editing `supabase/applied-migration-hashes.json`). Drafting a migration in an unmerged PR is allowed; a blanket or earlier yes does not cover a later change. See [the decision](docs/decisions/2026-10-15-database-changes-need-owner-permission.md).
- **MERGING TO `main` DEPLOYS TO PRODUCTION.** The Supabase GitHub integration has **"Deploy to production" ENABLED** on branch **`main`** (confirmed 2026-08-21). Any migration merged to `main` applies to the live clinical database automatically within seconds (34 s in `docs/audit/live-drift-forensics-2026-08.md` §3.7), with no separate deploy step or hold window:
- **Treat merge approval as production-deploy approval.** Never merge a PR touching `supabase/migrations/**` outside an approved window, and never enable auto-merge on one.
- **Never write PR metadata promising a deferred deploy.** Phrases like "AWAITING DEPLOY WINDOW", "deployed manually after merge", "deployment is pending operator approval", and "not yet applied" describe a control this repo lacks and invite premature merges (as on PR #2502). State the merge gate instead ("merge only inside the approved window"). `scripts/pr-policy.mjs` hard-blocks deferred-deploy claims on PRs touching `supabase/migrations/**` (title always in scope; body statements must name the database subject; pre-merge approval phrasing and non-DB deploy constraints remain allowed).
- **Never write PR metadata promising a deferred deploy.** Phrases like "AWAITING DEPLOY WINDOW", "deployed manually after merge", "deployment is pending operator approval", and "not yet applied" invite premature merges (as on PR #2502). State the merge gate instead ("merge only inside the approved window"). `scripts/pr-policy.mjs` hard-blocks deferred-deploy claims on PRs touching `supabase/migrations/**` (title always in scope; body statements must name the database subject; pre-merge approval phrasing and non-DB deploy constraints remain allowed).
- **After such a PR merges, the schema-application gate is the post-merge `live-drift` workflow** (`.github/workflows/live-drift.yml`), which must complete with BOTH `npm run check:drift` and `npm run check:migration-history` green. `supabase migration list` reads recorded history only and cannot detect no-statements rows (`#Q5JHBJ`), whereas `check:drift` compares the live schema. A manual `supabase migration list --linked --project-ref sjrfecxgysukkwxsowpy` read is an optional provider-backed supplement requiring explicit user confirmation first.
- **Transactional execution only.** Each migration runs in one transaction, so bare `CREATE INDEX CONCURRENTLY` fails; use operator-prebuild + a validate-only guard migration (`20260804110240` pattern below).
- **Automatic branching is ON** (one preview DB per `supabase/**` PR, limit 3; Branching Compute is **not covered by the Spend Cap**). CI's `Migration replay` job (`db-reset-verify`, `supabase migration up --local`) independently replays the chain on every DB PR.
- Expected project ref: `sjrfecxgysukkwxsowpy`.
- Older unused project ref `qjgitjyhxrwxsrydablr` belongs to `Database`; treat it as stale and do not use it.
- Hosted migrations, `supabase/schema.sql`, `supabase/roles.sql`, CI, and deployment tooling must target role `postgres`; never assume a platform-reserved role. The single older applied migration is immutable and pinned by `npm run check:migration-role`.
- Bare-image storage scaffolding must discover its local schema owner at runtime and must never be reused as hosted migration SQL.
- Run `npm run check:migration-role` after changing Supabase SQL, migration tooling, CI replay, or disaster-recovery instructions.
- Run `npm run check:supabase-project` after changing Supabase env values.
- Expected project ref: `sjrfecxgysukkwxsowpy`. Older unused project ref `qjgitjyhxrwxsrydablr` belongs to `Database`; treat it as stale and do not use it.
- Hosted migrations, `supabase/schema.sql`, `supabase/roles.sql`, CI, and deployment tooling must target role `postgres`; never assume a platform-reserved role. The single older applied migration is immutable and pinned by `npm run check:migration-role`. Bare-image storage scaffolding must discover its local schema owner at runtime and must never be reused as hosted migration SQL.
- Run `npm run check:migration-role` after changing Supabase SQL, migration tooling, CI replay, or disaster-recovery instructions, and `npm run check:supabase-project` after changing Supabase env values.
- **Guard-migration contract.** Any mark-applied version, `supabase migration repair --status applied`, hand-applied SQL recorded as a migration, or history repair MUST ship a fail-fast validation guard migration in the same change, following `20260804110240_restore_rag_search_health_indexes.sql` (validates presence + `indisvalid`/`indisready` + normalized definition, never builds, `set local` timeouts, one `raise exception`). `schema_drift_snapshot()` v2 (`20260818090000`) reports no-statement `supabase_migrations` versions; `check:drift` fails unless `supabase/drift-allowlist.json` has a reviewed `migration_history` entry pointing at its guard (`guard.class` `validation` mandatory from 2026-08-18; `superseded`/`no_ddl` pre-contract only; never allowlist bare or widen class). Enforced by `tests/migration-history-guards.test.ts` and `tests/search-health-index-coverage.test.ts` + `supabase/search-health-unmonitored-indexes.json` (`required_indexes` changes via migration only). See `docs/database-drift-detection.md`.

## Supabase merge caution
Expand Down Expand Up @@ -204,13 +201,11 @@ surface, read `docs/rag-behaviour/` (README → behaviour-map → refuted-approa

# Railway project safety

- This repo deploys to the live Railway project `PsychSift` (`5deaad0b-675a-4c13-978e-5ca2b5b877f9`) in workspace `bigsimmo's Projects`. Full topology: `docs/deployment-architecture.md` §1.
- Production services `PsychSift` (Next.js app tier, serves `https://psychiatry.tools`) and `worker` (ingestion) auto-deploy from `BigSimmo/PsychSift` pushes to `main`; the `staging` environment runs the `app` service.
- The older Railway project `clinical-kb` (`4361c04f-dd3c-4ee9-9e97-49e4e5707b70`) is superseded with zero active deployments; treat it as stale — never `railway link` to it or deploy there.
- The similarly named Supabase project `PsychSift Production` is the database/auth tier, not a Railway project; see "Supabase project safety" above.
- Railway CLI token auth uses `RAILWAY_API_TOKEN` (personal account token; see `.env.example`). The project-scoped `RAILWAY_TOKEN` is for CI deploys only and cannot list or link projects; Cloud runtime acceptance no longer installs or probes the CLI, so that substitution rule is documentation-enforced until an operator workflow reintroduces CLI checks. Desktop/CLI MCP uses the secret-free `railway` entry (enable in `$CODEX_HOME/config.toml` or via a never-committed local edit — never commit `enabled = true`) plus `codex mcp login railway`; neither repository MCP file activates a hosted ChatGPT/Codex app.
- This repo deploys to the live Railway project `PsychSift` (`5deaad0b-675a-4c13-978e-5ca2b5b877f9`) in workspace `bigsimmo's Projects` (`docs/deployment-architecture.md` §1). Production services `PsychSift` (Next.js app, `https://psychiatry.tools`) and `worker` (ingestion) auto-deploy from `BigSimmo/PsychSift` pushes to `main`; `staging` runs `app`.
- The older Railway project `clinical-kb` (`4361c04f-dd3c-4ee9-9e97-49e4e5707b70`) is superseded (zero active deployments) — never `railway link` or deploy there. Supabase `PsychSift Production` is the DB/auth tier, not Railway.
- Railway CLI token auth (`.env.example`): prefer the project-scoped `RAILWAY_TOKEN` (one environment) for deploys, redeploys and logs in CI or remote shells; use `RAILWAY_API_TOKEN` (workspace over account scope) only for `railway list`/`link`, which a project token cannot do. Desktop/CLI MCP uses the secret-free `railway` entry (enable locally in `$CODEX_HOME/config.toml` — never commit `enabled = true`) plus `codex mcp login railway`.
- Railway deploys and mutations fall under the "API and provider confirmation boundary" below; verify target project/environment IDs before any mutation.
- **Safe, fast iteration.** Keep automatic Railway PR Environments disabled. Iterate locally with focused checks, use an explicitly requested isolated app preview when useful, and keep production deployment from protected `main`. Never copy production database/provider credentials or an ingestion worker into a routine PR preview. Any future automatic previews require an isolated base and Focused PR Environments, using the existing service watch paths. Follow [the preview policy and verified settings](docs/deployment-architecture.md#selective-railway-pr-previews); keep required CI and Supabase controls intact.
- **Safe, fast iteration.** Keep automatic Railway PR Environments disabled. Iterate locally with focused checks, use an explicitly requested isolated app preview when useful, and keep production deployment from protected `main`. Never copy production database/provider credentials or an ingestion worker into a routine PR preview. Follow [the preview policy and verified settings](docs/deployment-architecture.md#selective-railway-pr-previews); keep required CI and Supabase controls intact.

<!-- END:railway-project-safety -->

Expand Down
8 changes: 8 additions & 0 deletions data/repo-awareness-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -24783,6 +24783,14 @@
"outcome": "MERGED after #1268 (lockfile order). Dev bumps: bundle-analyzer/eslint-config-next 16.2.12, playwright 1.62, prettier 3.9.6.",
"checks": "hosted-pr-required,static,unit,build,circleci"
},
{
"date": "2026-10-17",
"ref": "docs/audit-remediation-20261014",
"head": "def6fabcc8235e8592fea2613d07170e23dd9836",
"scope": "prlanded",
"outcome": "Verified PR #3544 squash-merged at def6fabcc8235e8592fea2613d07170e23dd9836 with zero content diff against final PR head f519ae94fafab3e2ce7b221a054faa7d66939eea and zero orphaned commits",
"checks": "gh pr view 3544, git rev-list --parents -n 1 def6fabcc8235e8592fea2613d07170e23dd9836, git diff --stat def6fabcc8235e8592fea2613d07170e23dd9836 f519ae94fafab3e2ce7b221a054faa7d66939eea"
},
{
"date": "2026-07-14",
"ref": "worktrees (6244, 8ba3, b6ff, e6b5, repo-improvement-review-09945c)",
Expand Down
9 changes: 5 additions & 4 deletions docs/branch-review-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ Retention and rotation: [`branch-review-archival-policy.md`](branch-review-archi

## Summary

- Records: 711
- Distinct ref cells: 457
- Distinct reviewed heads: 693
- Records: 712
- Distinct ref cells: 458
- Distinct reviewed heads: 694
- Date range: `2026-08-12` to `2026-10-17`

Records per date, newest first:

- `2026-10-17` — 5 records
- `2026-10-17` — 6 records
- `2026-10-16` — 7 records
- `2026-10-15` — 3 records
- `2026-10-14` — 1 record
Expand Down Expand Up @@ -79,6 +79,7 @@ Scope and outcome are truncated; follow the record link for the full six-cell ro

| Date | Ref | Scope | Outcome | Record |
| --- | --- | --- | --- | --- |
| 2026-10-17 | docs/audit-remediation-20261014 | prlanded | Verified PR #3544 squash-merged at def6fabcc8235e8592fea2613d07170e23d… | [0dbb74fa](branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md) |
| 2026-10-17 | codex/cloud-policy-clarity | prlanded | PR #3581 (a5b118f952) and PR #3587 (7c719b2bc4) squash-merged cleanly… | [16df9092](branch-review-records/16df90928a34e2941ef9c2892b7f48d92e09e12f470af635ef15e4ee3677b0b9.record.md) |
| 2026-10-17 | claude/rag-ingestion-hardening | prlanded | PR #3596 squash-merged cleanly into main at 45fc04c42f0867bc9802ffc93f… | [1ae2c7f8](branch-review-records/1ae2c7f8f7762d8e1d81898ed83a701be7cbd007c80be5a3d83e39470ced9461.record.md) |
| 2026-10-17 | claude/rag-ingestion-hardening | RAG retrieval/summary/cache generation isolation and ingestion worker/edge hardening | resolved | [5349150e](branch-review-records/5349150e82f255e42866975fa7aa5e9fe76601433ebc427c75226677c5bef854.record.md) |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| 2026-10-17 | docs/audit-remediation-20261014 | def6fabcc8235e8592fea2613d07170e23dd9836 | prlanded | Verified PR #3544 squash-merged at def6fabcc8235e8592fea2613d07170e23dd9836 with zero content diff against final PR head f519ae94fafab3e2ce7b221a054faa7d66939eea and zero orphaned commits | gh pr view 3544, git rev-list --parents -n 1 def6fabcc8235e8592fea2613d07170e23dd9836, git diff --stat def6fabcc8235e8592fea2613d07170e23dd9836 f519ae94fafab3e2ce7b221a054faa7d66939eea |
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- **Status:** decided 2026-10-15
- **Source:** the owner, in chat
- **Implemented in:** `docs/agents/pull-request-workflow.md`, find "never blocks merges or delays the merge queue"

CodeRabbit stays as a review bot, but its reviews must stop acting as a barrier to merging.

Expand Down
33 changes: 28 additions & 5 deletions scripts/maintain-docs-system.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,11 @@ export function classifyRepositoryPath(relativePath, options = {}) {
lower === "src/app/api/search" ||
/^docs\/(rag|answer|search(?!-chrome)|query)/.test(lower) ||
(lower.startsWith("docs/") &&
/\b(rag|retrieval|grounding|rerank|citation|citations|query-classification)\b/.test(base))
/\b(rag|retrieval|grounding|rerank|citation|citations|query-classification)\b/.test(base)) ||
// No `search-` prefix: app-experience's explicit `tests/search-*` glob owns those tests.
/^tests\/(rag|answer|query-classification|retrieval|grounding|rerank|semantic-rerank|citation|citations|evidence|corpus-grounding|eval)(-|\.)/.test(
lower,
)
) {
return buildResult(
"search-and-answers",
Expand All @@ -201,7 +205,12 @@ export function classifyRepositoryPath(relativePath, options = {}) {
lower === "src/lib/ingest" ||
lower.startsWith("src/app/sources/") ||
lower === "src/app/sources" ||
/^docs\/(source|ingest|document)/.test(lower)
/^docs\/(source|ingest|document)/.test(lower) ||
// No `document-` prefix: app-experience's `tests/document-*` glob owns those tests, and
// source-intake claims its document tests by explicit globs (e.g. `tests/document-enrichment-*`).
/^tests\/(ingest|ingestion|upload|reindex|chunk|chunking|extract|extracted|docling|ocr|pdf|xlsx|docx|table|indexing|enrichment|storage-cleanup|storage-upload)(-|\.)/.test(
lower,
)
) {
return buildResult(
"sources-and-ingestion",
Expand All @@ -220,7 +229,11 @@ export function classifyRepositoryPath(relativePath, options = {}) {
/^src\/app\/api\/(cme|roster|teaching|work)(\/|$)/.test(lower) ||
/^src\/components\/(cme|roster|my-day|teaching|work-frame)(\/|$)/.test(lower) ||
/^src\/lib\/(cme|roster|teaching|work-frame)(\/|$)/.test(lower) ||
/^docs\/(personal|workspace|diary|cme)/.test(lower)
/^docs\/(personal|workspace|diary|cme)/.test(lower) ||
// No bare `work-` prefix: Work tests span several systems (App experience, data platform,
// design system), so an unmatched one falls back to the generic delivery owner until a
// manifest rule names its real owner.
/^tests\/(cme|roster|my-day|teaching|open-shifts|diary|workspace|calendar|handover|notes)(-|\.)/.test(lower)
) {
return buildResult(
"personal-practice",
Expand All @@ -242,6 +255,9 @@ export function classifyRepositoryPath(relativePath, options = {}) {
) ||
/^docs\/(clinical(?!-safety|-governance|-hazard|-sign-off)|medication|therapy|psychiatry|formulation|diagnosis|dsm|differential|dictionary|care-plan|scales|calculators|ect|sleep|ranzcp)/.test(
lower,
) ||
/^tests\/(medications|medicine|medicines|therapy|psychiatry|formulation|diagnosis|dsm|differential|differentials|dictionary|care-plan|calculator|calculators|forms|services|mha|specifier|specifiers|tall-man|clozapine|lithium|ect|scales|sleep|ranzcp|new-starters|on-call)(-|\.)/.test(
lower,
)
) {
return buildResult(
Expand All @@ -265,7 +281,10 @@ export function classifyRepositoryPath(relativePath, options = {}) {
lower,
) ||
lower === "scripts/maintain-docs-system.mjs" ||
lower === "tests/maintain-docs-system.test.ts"
lower === "tests/maintain-docs-system.test.ts" ||
/^tests\/(decisions|retired-rules|instruction|ledger|outstanding-issues|branch-review|database-skills|check-docs)(-|\.)/.test(
lower,
)
) {
return buildResult(
"knowledge",
Expand All @@ -282,12 +301,16 @@ export function classifyRepositoryPath(relativePath, options = {}) {
lower === "src/app/design-tokens.css" ||
/^docs\/(design|brand|ui|search-chrome|search-results-bar|filter-contract|wiring-conventions|frontend-architecture|pwa|navigation)/.test(
lower,
) ||
/^tests\/(design-system|type-scale|icon-scale|theme|brand|ui-style-contract|phone-chrome|search-chrome|search-results-bar|navigation|header|dock|pwa)(-|\.)/.test(
lower,
)
) {
const isDesignTokensOrSystem =
lower === "src/app/globals.css" ||
lower === "src/app/design-tokens.css" ||
/^docs\/(design|brand|ui)/.test(lower);
/^docs\/(design|brand|ui)/.test(lower) ||
/^tests\/(design-system|type-scale|icon-scale|theme|brand|ui-style-contract)(-|\.)/.test(lower);
return buildResult(
"shell-and-design",
isDesignTokensOrSystem ? "design-system" : "app-experience",
Expand Down
Loading
Loading