From d0430df0bfb58b05d2cdc9ed7d435a90013a2cef Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 17 Oct 2026 13:49:18 +0800 Subject: [PATCH 01/11] chore(ledger): record prlanded verification for PR #3544 --- ...7d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md diff --git a/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md b/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md new file mode 100644 index 0000000000..67bf1cbbf7 --- /dev/null +++ b/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md @@ -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 | From 30fe3c62bcde45134ab84c235d32f0f64a042a34 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 17 Oct 2026 20:00:01 +0800 Subject: [PATCH 02/11] chore(docs): route domain test paths, anchor landed decisions, and expand AGENTS.md headroom --- AGENTS.md | 23 +++++++--------- data/repo-awareness-snapshot.json | 10 ++++++- docs/branch-review-index.md | 9 ++++--- ...erabbit-stays-but-does-not-block-merges.md | 2 +- .../2026-10-15-no-default-ai-coding-tool.md | 2 +- ...no-separate-github-account-for-ai-tools.md | 2 +- .../2026-10-15-remove-codspeed-check.md | 2 +- ...-10-15-specifiers-need-a-named-sign-off.md | 2 +- .../2026-10-16-keep-migration-history.md | 2 +- scripts/maintain-docs-system.mjs | 27 +++++++++++++++---- tests/maintain-docs-system.test.ts | 18 +++++++++++++ 11 files changed, 69 insertions(+), 30 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6316e00ceb..2420642649 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 @@ -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 uses `RAILWAY_API_TOKEN` (personal account token; `.env.example`). Project-scoped `RAILWAY_TOKEN` is for CI deploys only and cannot list/link projects. 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. diff --git a/data/repo-awareness-snapshot.json b/data/repo-awareness-snapshot.json index 6c72684ee5..3550f82a21 100644 --- a/data/repo-awareness-snapshot.json +++ b/data/repo-awareness-snapshot.json @@ -16335,7 +16335,7 @@ "date": "2026-10-17", "ref": "claude/add-prlanded-skill", "head": "7e6fd2d557d53e22dfa6ea37b8921007fe4b0dfa", - "scope": "prlanded", + "scope": "Canonical prlanded skill and landed ledger records", "outcome": "PASS (0 blocking findings; added .agents/skills/prlanded canonical skill, registered cross-surface twin in list-database-skills.mjs, updated skill inventory tests, and recorded prlanded proofs for PRs #3581/#3587 and #3596)", "checks": "npm run check:skills, vitest run tests/database-skills.test.ts tests/repository-skill-inventory.test.ts (15/15), npm run docs:maintain:check, check-format-changed" }, @@ -24747,6 +24747,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)", diff --git a/docs/branch-review-index.md b/docs/branch-review-index.md index d5249e8369..6ff2147f3d 100644 --- a/docs/branch-review-index.md +++ b/docs/branch-review-index.md @@ -15,14 +15,14 @@ Retention and rotation: [`branch-review-archival-policy.md`](branch-review-archi ## Summary -- Records: 708 -- Distinct ref cells: 454 -- Distinct reviewed heads: 690 +- Records: 709 +- Distinct ref cells: 455 +- Distinct reviewed heads: 691 - 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` — 4 records - `2026-10-15` — 3 records - `2026-10-14` — 1 record @@ -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) | diff --git a/docs/decisions/2026-10-15-coderabbit-stays-but-does-not-block-merges.md b/docs/decisions/2026-10-15-coderabbit-stays-but-does-not-block-merges.md index c52cf09e2e..a3b533741d 100644 --- a/docs/decisions/2026-10-15-coderabbit-stays-but-does-not-block-merges.md +++ b/docs/decisions/2026-10-15-coderabbit-stays-but-does-not-block-merges.md @@ -1,7 +1,7 @@ # Decision: Keep CodeRabbit, but its reviews must not block a merge - **Status:** decided 2026-10-15 -- **Source:** the owner, in chat +- **Source:** `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. diff --git a/docs/decisions/2026-10-15-no-default-ai-coding-tool.md b/docs/decisions/2026-10-15-no-default-ai-coding-tool.md index ce68eb35be..95e7cfbec9 100644 --- a/docs/decisions/2026-10-15-no-default-ai-coding-tool.md +++ b/docs/decisions/2026-10-15-no-default-ai-coding-tool.md @@ -1,7 +1,7 @@ # Decision: No single default AI coding tool - **Status:** decided 2026-10-15 -- **Source:** the owner, in chat +- **Source:** `docs/agents/native-startup/recording-decisions.md`, find "Only the repository reaches every tool (Claude, Codex, Cursor, Antigravity, Gemini and the review bots)." The owner chose not to name one default AI coding tool. The tools in use stay in use. diff --git a/docs/decisions/2026-10-15-no-separate-github-account-for-ai-tools.md b/docs/decisions/2026-10-15-no-separate-github-account-for-ai-tools.md index e261c7d010..d0f09199ff 100644 --- a/docs/decisions/2026-10-15-no-separate-github-account-for-ai-tools.md +++ b/docs/decisions/2026-10-15-no-separate-github-account-for-ai-tools.md @@ -1,7 +1,7 @@ # Decision: AI tools keep working under the owner's GitHub account, with the current approval rules - **Status:** decided 2026-10-15 -- **Source:** the owner, in chat +- **Source:** `AGENTS.md`, find "Never run, modify, test, or otherwise interact with OpenAI, Supabase, GitHub/GitLab, hosted CI, production-like services, or provider-backed workflows without explicit user confirmation." The owner declined a second GitHub account for the AI tools and declined a new code owners review rule for the risky areas. The existing approval rules in AGENTS.md stay as they are. diff --git a/docs/decisions/2026-10-15-remove-codspeed-check.md b/docs/decisions/2026-10-15-remove-codspeed-check.md index 4e0661670b..aa4b517675 100644 --- a/docs/decisions/2026-10-15-remove-codspeed-check.md +++ b/docs/decisions/2026-10-15-remove-codspeed-check.md @@ -1,7 +1,7 @@ # Decision: Remove the CodSpeed speed check - **Status:** decided 2026-10-15 -- **Source:** the owner, in chat +- **Source:** `docs/codebase-index.md`, find "CodSpeed CPU-simulation benchmarks" The CodSpeed benchmark workflow was never signed in to its service and has failed on every run since it was added. The owner agreed to remove it. diff --git a/docs/decisions/2026-10-15-specifiers-need-a-named-sign-off.md b/docs/decisions/2026-10-15-specifiers-need-a-named-sign-off.md index 2024312318..d6bf837349 100644 --- a/docs/decisions/2026-10-15-specifiers-need-a-named-sign-off.md +++ b/docs/decisions/2026-10-15-specifiers-need-a-named-sign-off.md @@ -1,7 +1,7 @@ # Decision: DSM specifiers count as signed off only under a named clinician - **Status:** decided 2026-10-15; superseded by 2026-10-16-psych-sift-display-name-sign-off.md -- **Source:** the owner, in chat +- **Source:** `src/lib/admin/rule-sign-off.ts`, find "Signed by a system or role name, not a named clinician" The 89 DSM specifier records stamped with the product name PsychSift (71 items and 18 universal specifiers) show as not signed off, and their definitions stay withheld, until the owner re-signs each one in diff --git a/docs/decisions/2026-10-16-keep-migration-history.md b/docs/decisions/2026-10-16-keep-migration-history.md index 9178baf6ea..9f0d038f57 100644 --- a/docs/decisions/2026-10-16-keep-migration-history.md +++ b/docs/decisions/2026-10-16-keep-migration-history.md @@ -1,7 +1,7 @@ # Decision: Keep the full database migration history instead of folding it into one snapshot - **Status:** decided 2026-10-16 -- **Source:** the owner, in chat +- **Source:** `AGENTS.md`, find "never edit a migration already on `main`" The owner chose not to fold the older database migration history into one starting snapshot, because rewriting the protected applied migration hashes, migration history and drift checks carries more risk diff --git a/scripts/maintain-docs-system.mjs b/scripts/maintain-docs-system.mjs index b11273b53f..e2ef493ca4 100644 --- a/scripts/maintain-docs-system.mjs +++ b/scripts/maintain-docs-system.mjs @@ -177,7 +177,10 @@ 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)) || + /^tests\/(rag|answer|search(?!-chrome|-results-bar)|query-classification|retrieval|grounding|rerank|semantic-rerank|citation|citations|evidence|corpus-grounding|eval)(-|\.)/.test( + lower, + ) ) { return buildResult( "search-and-answers", @@ -201,7 +204,10 @@ 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) || + /^tests\/(ingest|ingestion|document|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", @@ -220,7 +226,8 @@ 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) || + /^tests\/(cme|roster|my-day|teaching|open-shifts|work|diary|workspace|calendar|handover|notes)(-|\.)/.test(lower) ) { return buildResult( "personal-practice", @@ -242,6 +249,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( @@ -265,7 +275,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", @@ -282,12 +295,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", diff --git a/tests/maintain-docs-system.test.ts b/tests/maintain-docs-system.test.ts index 0d598203d4..03c502ae21 100644 --- a/tests/maintain-docs-system.test.ts +++ b/tests/maintain-docs-system.test.ts @@ -165,6 +165,24 @@ describe("maintain-docs-system pipeline", () => { expect(result.system).toBe("search-and-answers"); expect(result.systemFile).toBe("docs/organisation/systems/search-and-answers.json"); }); + + it("routes new domain-specific tests/* paths to their owning system area instead of falling through to delivery", () => { + const testCases = [ + { path: "tests/query-classification-new.test.ts", expectedResolved: "answer-engine" }, + { path: "tests/xlsx-sheet-dictionary-projection-new.test.ts", expectedResolved: "source-intake" }, + { path: "tests/cme-accreditation-summary-new.test.ts", expectedResolved: "personal-practice" }, + { path: "tests/calculators-lithium-toxicity-new.test.ts", expectedResolved: "clinical-content" }, + { path: "tests/branch-review-ledger-new.test.ts", expectedResolved: "knowledge" }, + { path: "tests/design-system-token-new.test.ts", expectedResolved: "design-system" }, + { path: "tests/phone-chrome-scroll-new.test.ts", expectedResolved: "app-experience" }, + ]; + + for (const tc of testCases) { + const result = classifyRepositoryPath(tc.path); + expect(result.resolvedSystem).toBe(tc.expectedResolved); + expect(result.resolvedSystemFile).toBe(`docs/organisation/systems/${tc.expectedResolved}.json`); + } + }); }); describe("placeUnplacedFiles", () => { From d6530defd4ef251ee76faa706cf54d4b71110d5c Mon Sep 17 00:00:00 2001 From: "qodo-code-review[bot]" <151058649+qodo-code-review[bot]@users.noreply.github.com> Date: Sat, 17 Oct 2026 12:08:45 +0000 Subject: [PATCH 03/11] fix: Retain the migration decision's chat attribution --- docs/decisions/2026-10-16-keep-migration-history.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/decisions/2026-10-16-keep-migration-history.md b/docs/decisions/2026-10-16-keep-migration-history.md index 9f0d038f57..9178baf6ea 100644 --- a/docs/decisions/2026-10-16-keep-migration-history.md +++ b/docs/decisions/2026-10-16-keep-migration-history.md @@ -1,7 +1,7 @@ # Decision: Keep the full database migration history instead of folding it into one snapshot - **Status:** decided 2026-10-16 -- **Source:** `AGENTS.md`, find "never edit a migration already on `main`" +- **Source:** the owner, in chat The owner chose not to fold the older database migration history into one starting snapshot, because rewriting the protected applied migration hashes, migration history and drift checks carries more risk From 218b6a90471e2916c072a457740813eceb594bd1 Mon Sep 17 00:00:00 2001 From: "qodo-code-review[bot]" <151058649+qodo-code-review[bot]@users.noreply.github.com> Date: Sat, 17 Oct 2026 12:08:48 +0000 Subject: [PATCH 04/11] fix: Retain the CodSpeed decision's chat attribution --- docs/decisions/2026-10-15-remove-codspeed-check.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/decisions/2026-10-15-remove-codspeed-check.md b/docs/decisions/2026-10-15-remove-codspeed-check.md index aa4b517675..4e0661670b 100644 --- a/docs/decisions/2026-10-15-remove-codspeed-check.md +++ b/docs/decisions/2026-10-15-remove-codspeed-check.md @@ -1,7 +1,7 @@ # Decision: Remove the CodSpeed speed check - **Status:** decided 2026-10-15 -- **Source:** `docs/codebase-index.md`, find "CodSpeed CPU-simulation benchmarks" +- **Source:** the owner, in chat The CodSpeed benchmark workflow was never signed in to its service and has failed on every run since it was added. The owner agreed to remove it. From 5f4cfb7c1c37b6eb65582f587153dc6104c0cfc1 Mon Sep 17 00:00:00 2001 From: "qodo-code-review[bot]" <151058649+qodo-code-review[bot]@users.noreply.github.com> Date: Sat, 17 Oct 2026 12:08:52 +0000 Subject: [PATCH 05/11] fix: Retain the coding-tool decision's chat attribution --- docs/decisions/2026-10-15-no-default-ai-coding-tool.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/decisions/2026-10-15-no-default-ai-coding-tool.md b/docs/decisions/2026-10-15-no-default-ai-coding-tool.md index 95e7cfbec9..ce68eb35be 100644 --- a/docs/decisions/2026-10-15-no-default-ai-coding-tool.md +++ b/docs/decisions/2026-10-15-no-default-ai-coding-tool.md @@ -1,7 +1,7 @@ # Decision: No single default AI coding tool - **Status:** decided 2026-10-15 -- **Source:** `docs/agents/native-startup/recording-decisions.md`, find "Only the repository reaches every tool (Claude, Codex, Cursor, Antigravity, Gemini and the review bots)." +- **Source:** the owner, in chat The owner chose not to name one default AI coding tool. The tools in use stay in use. From c1d43f08bb9bba42f599c49cfc078aeb4e1cc7ea Mon Sep 17 00:00:00 2001 From: "qodo-code-review[bot]" <151058649+qodo-code-review[bot]@users.noreply.github.com> Date: Sat, 17 Oct 2026 12:08:55 +0000 Subject: [PATCH 06/11] fix: Retain the GitHub-account decision's chat attribution --- .../2026-10-15-no-separate-github-account-for-ai-tools.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/decisions/2026-10-15-no-separate-github-account-for-ai-tools.md b/docs/decisions/2026-10-15-no-separate-github-account-for-ai-tools.md index d0f09199ff..e261c7d010 100644 --- a/docs/decisions/2026-10-15-no-separate-github-account-for-ai-tools.md +++ b/docs/decisions/2026-10-15-no-separate-github-account-for-ai-tools.md @@ -1,7 +1,7 @@ # Decision: AI tools keep working under the owner's GitHub account, with the current approval rules - **Status:** decided 2026-10-15 -- **Source:** `AGENTS.md`, find "Never run, modify, test, or otherwise interact with OpenAI, Supabase, GitHub/GitLab, hosted CI, production-like services, or provider-backed workflows without explicit user confirmation." +- **Source:** the owner, in chat The owner declined a second GitHub account for the AI tools and declined a new code owners review rule for the risky areas. The existing approval rules in AGENTS.md stay as they are. From 03b55b72d4937044048522be72a2d291981859c3 Mon Sep 17 00:00:00 2001 From: "qodo-code-review[bot]" <151058649+qodo-code-review[bot]@users.noreply.github.com> Date: Sat, 17 Oct 2026 12:08:58 +0000 Subject: [PATCH 07/11] fix: Retain the specifier decision's chat attribution --- docs/decisions/2026-10-15-specifiers-need-a-named-sign-off.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/decisions/2026-10-15-specifiers-need-a-named-sign-off.md b/docs/decisions/2026-10-15-specifiers-need-a-named-sign-off.md index d6bf837349..2024312318 100644 --- a/docs/decisions/2026-10-15-specifiers-need-a-named-sign-off.md +++ b/docs/decisions/2026-10-15-specifiers-need-a-named-sign-off.md @@ -1,7 +1,7 @@ # Decision: DSM specifiers count as signed off only under a named clinician - **Status:** decided 2026-10-15; superseded by 2026-10-16-psych-sift-display-name-sign-off.md -- **Source:** `src/lib/admin/rule-sign-off.ts`, find "Signed by a system or role name, not a named clinician" +- **Source:** the owner, in chat The 89 DSM specifier records stamped with the product name PsychSift (71 items and 18 universal specifiers) show as not signed off, and their definitions stay withheld, until the owner re-signs each one in From a1b12587dab9b4b8595e355f5e663a028fb2e332 Mon Sep 17 00:00:00 2001 From: "qodo-code-review[bot]" <151058649+qodo-code-review[bot]@users.noreply.github.com> Date: Sat, 17 Oct 2026 12:09:03 +0000 Subject: [PATCH 08/11] fix: Narrow the landed outcome to recorded checks --- data/repo-awareness-snapshot.json | 2 +- ...d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/repo-awareness-snapshot.json b/data/repo-awareness-snapshot.json index 3550f82a21..963fe8dfc3 100644 --- a/data/repo-awareness-snapshot.json +++ b/data/repo-awareness-snapshot.json @@ -24752,7 +24752,7 @@ "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", + "outcome": "Verified PR #3544 squash-merged at def6fabcc8235e8592fea2613d07170e23dd9836 with zero content diff against final PR head f519ae94fafab3e2ce7b221a054faa7d66939eea", "checks": "gh pr view 3544, git rev-list --parents -n 1 def6fabcc8235e8592fea2613d07170e23dd9836, git diff --stat def6fabcc8235e8592fea2613d07170e23dd9836 f519ae94fafab3e2ce7b221a054faa7d66939eea" }, { diff --git a/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md b/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md index 67bf1cbbf7..4539c089e9 100644 --- a/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md +++ b/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md @@ -1 +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 | +| 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 | gh pr view 3544, git rev-list --parents -n 1 def6fabcc8235e8592fea2613d07170e23dd9836, git diff --stat def6fabcc8235e8592fea2613d07170e23dd9836 f519ae94fafab3e2ce7b221a054faa7d66939eea | From 66270dfef3e163f71700c1dfca4818625ccd3d70 Mon Sep 17 00:00:00 2001 From: Grok Bot Date: Sat, 17 Oct 2026 20:46:49 +0800 Subject: [PATCH 09/11] Revert "fix: Narrow the landed outcome to recorded checks" This reverts commit a1b12587dab9b4b8595e355f5e663a028fb2e332. Branch-review records are content-addressed: the filename is the SHA-256 of the record row. Editing the row in place broke check:branch-review-ledger. Restore the tool-written row (and its snapshot mirror); a correction must be a new record written by the ledger tool, never an in-place edit. --- data/repo-awareness-snapshot.json | 2 +- ...d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/repo-awareness-snapshot.json b/data/repo-awareness-snapshot.json index 963fe8dfc3..3550f82a21 100644 --- a/data/repo-awareness-snapshot.json +++ b/data/repo-awareness-snapshot.json @@ -24752,7 +24752,7 @@ "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", + "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" }, { diff --git a/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md b/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md index 4539c089e9..67bf1cbbf7 100644 --- a/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md +++ b/docs/branch-review-records/0dbb74fa24e427d3d012744657555374a0da336ad41ba1439663c24cf88e5342.record.md @@ -1 +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 | gh pr view 3544, git rev-list --parents -n 1 def6fabcc8235e8592fea2613d07170e23dd9836, git diff --stat def6fabcc8235e8592fea2613d07170e23dd9836 f519ae94fafab3e2ce7b221a054faa7d66939eea | +| 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 | From 168fbc12238d1d460f8eab7c94023113ef2fa29f Mon Sep 17 00:00:00 2001 From: Grok Bot Date: Sat, 17 Oct 2026 20:51:34 +0800 Subject: [PATCH 10/11] fix(docs): keep ambiguous work-* tests unplaced; align Railway token guidance with .env.example - maintain-docs-system: drop the bare tests/work- prefix from personal-practice routing; Work tests span App experience, data platform and design system, so an unmatched one is left for explicit ownership (exact manifest rules still win) - AGENTS.md: the project-scoped RAILWAY_TOKEN is the preferred (narrowest) token for deploys in CI or remote shells, per .env.example; RAILWAY_API_TOKEN only for railway list/link --- AGENTS.md | 2 +- scripts/maintain-docs-system.mjs | 4 +++- tests/maintain-docs-system.test.ts | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 2420642649..fde46d9522 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -203,7 +203,7 @@ surface, read `docs/rag-behaviour/` (README → behaviour-map → refuted-approa - 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 uses `RAILWAY_API_TOKEN` (personal account token; `.env.example`). Project-scoped `RAILWAY_TOKEN` is for CI deploys only and cannot list/link projects. 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 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. Follow [the preview policy and verified settings](docs/deployment-architecture.md#selective-railway-pr-previews); keep required CI and Supabase controls intact. diff --git a/scripts/maintain-docs-system.mjs b/scripts/maintain-docs-system.mjs index e2ef493ca4..1cdb5ff7ef 100644 --- a/scripts/maintain-docs-system.mjs +++ b/scripts/maintain-docs-system.mjs @@ -227,7 +227,9 @@ export function classifyRepositoryPath(relativePath, options = {}) { /^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) || - /^tests\/(cme|roster|my-day|teaching|open-shifts|work|diary|workspace|calendar|handover|notes)(-|\.)/.test(lower) + // No bare `work-` prefix: Work tests span several systems (App experience, data + // platform, design system), so an unmatched one stays unplaced for explicit ownership. + /^tests\/(cme|roster|my-day|teaching|open-shifts|diary|workspace|calendar|handover|notes)(-|\.)/.test(lower) ) { return buildResult( "personal-practice", diff --git a/tests/maintain-docs-system.test.ts b/tests/maintain-docs-system.test.ts index 03c502ae21..6e682f41f1 100644 --- a/tests/maintain-docs-system.test.ts +++ b/tests/maintain-docs-system.test.ts @@ -185,6 +185,14 @@ describe("maintain-docs-system pipeline", () => { }); }); + it("leaves an unmatched work-* test to explicit ownership rather than auto-claiming it for personal practice", () => { + // Work tests span several systems, so the bare prefix cannot identify the owner. + expect(classifyRepositoryPath("tests/work-side-nav-scroll.test.ts").resolvedSystem).not.toBe("personal-practice"); + // Exact manifest rules still decide existing Work tests. + expect(classifyRepositoryPath("tests/work-side-nav.test.ts").resolvedSystem).toBe("app-experience"); + expect(classifyRepositoryPath("tests/work-calendar-entries.test.ts").resolvedSystem).toBe("personal-practice"); + }); + describe("placeUnplacedFiles", () => { it("places unplaced files into matching system manifests, deduplicating and sorting files[]", () => { const root = makeTempFixture(); From 8726bf6231b05357b0d05b0b0041771936233aa0 Mon Sep 17 00:00:00 2001 From: Grok Bot Date: Sat, 17 Oct 2026 21:37:13 +0800 Subject: [PATCH 11/11] fix(docs): let manifest globs own search-/document- tests; restore CodeRabbit decision attribution - maintain-docs-system: drop the search- and document- test prefixes, which the explicit app-experience tests/search-* and tests/document-* globs (and source-intake's tests/document-enrichment-*) always shadow; pin the real-manifest outcomes in tests - correct the work- comment: an unmatched Work test falls back to the generic delivery owner (pre-existing behaviour), and assert that explicitly - coderabbit decision: keep 'the owner, in chat' as the Source and cite the workflow separately as where the policy is implemented --- ...15-coderabbit-stays-but-does-not-block-merges.md | 3 ++- scripts/maintain-docs-system.mjs | 12 ++++++++---- tests/maintain-docs-system.test.ts | 13 +++++++++++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/decisions/2026-10-15-coderabbit-stays-but-does-not-block-merges.md b/docs/decisions/2026-10-15-coderabbit-stays-but-does-not-block-merges.md index a3b533741d..c0813b6df6 100644 --- a/docs/decisions/2026-10-15-coderabbit-stays-but-does-not-block-merges.md +++ b/docs/decisions/2026-10-15-coderabbit-stays-but-does-not-block-merges.md @@ -1,7 +1,8 @@ # Decision: Keep CodeRabbit, but its reviews must not block a merge - **Status:** decided 2026-10-15 -- **Source:** `docs/agents/pull-request-workflow.md`, find "never blocks merges or delays the merge queue" +- **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. diff --git a/scripts/maintain-docs-system.mjs b/scripts/maintain-docs-system.mjs index 1cdb5ff7ef..3a9816faaf 100644 --- a/scripts/maintain-docs-system.mjs +++ b/scripts/maintain-docs-system.mjs @@ -178,7 +178,8 @@ export function classifyRepositoryPath(relativePath, options = {}) { /^docs\/(rag|answer|search(?!-chrome)|query)/.test(lower) || (lower.startsWith("docs/") && /\b(rag|retrieval|grounding|rerank|citation|citations|query-classification)\b/.test(base)) || - /^tests\/(rag|answer|search(?!-chrome|-results-bar)|query-classification|retrieval|grounding|rerank|semantic-rerank|citation|citations|evidence|corpus-grounding|eval)(-|\.)/.test( + // 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, ) ) { @@ -205,7 +206,9 @@ export function classifyRepositoryPath(relativePath, options = {}) { lower.startsWith("src/app/sources/") || lower === "src/app/sources" || /^docs\/(source|ingest|document)/.test(lower) || - /^tests\/(ingest|ingestion|document|upload|reindex|chunk|chunking|extract|extracted|docling|ocr|pdf|xlsx|docx|table|indexing|enrichment|storage-cleanup|storage-upload)(-|\.)/.test( + // 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, ) ) { @@ -227,8 +230,9 @@ export function classifyRepositoryPath(relativePath, options = {}) { /^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) || - // No bare `work-` prefix: Work tests span several systems (App experience, data - // platform, design system), so an unmatched one stays unplaced for explicit ownership. + // 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( diff --git a/tests/maintain-docs-system.test.ts b/tests/maintain-docs-system.test.ts index 6e682f41f1..b230b9c7fb 100644 --- a/tests/maintain-docs-system.test.ts +++ b/tests/maintain-docs-system.test.ts @@ -185,14 +185,23 @@ describe("maintain-docs-system pipeline", () => { }); }); - it("leaves an unmatched work-* test to explicit ownership rather than auto-claiming it for personal practice", () => { + it("leaves an unmatched work-* test with the generic delivery owner rather than auto-claiming it for personal practice", () => { // Work tests span several systems, so the bare prefix cannot identify the owner. - expect(classifyRepositoryPath("tests/work-side-nav-scroll.test.ts").resolvedSystem).not.toBe("personal-practice"); + expect(classifyRepositoryPath("tests/work-side-nav-scroll.test.ts").resolvedSystem).toBe("delivery"); // Exact manifest rules still decide existing Work tests. expect(classifyRepositoryPath("tests/work-side-nav.test.ts").resolvedSystem).toBe("app-experience"); expect(classifyRepositoryPath("tests/work-calendar-entries.test.ts").resolvedSystem).toBe("personal-practice"); }); + it("lets explicit manifest globs win over the domain test prefixes for new tests", () => { + // app-experience owns tests/search-* and tests/document-* by glob; source-intake owns + // tests/document-enrichment-*. The classifier prefixes deliberately do not compete with them. + expect(classifyRepositoryPath("tests/search-new-widget.test.ts").resolvedSystem).toBe("app-experience"); + expect(classifyRepositoryPath("tests/document-new-viewer.test.ts").resolvedSystem).toBe("app-experience"); + expect(classifyRepositoryPath("tests/document-enrichment-new.test.ts").resolvedSystem).toBe("source-intake"); + expect(classifyRepositoryPath("tests/calculators-new-score.test.ts").resolvedSystem).toBe("clinical-content"); + }); + describe("placeUnplacedFiles", () => { it("places unplaced files into matching system manifests, deduplicating and sorting files[]", () => { const root = makeTempFixture();