From b4e1a67db93ebd774cac852147c0a81edca76344 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Aug 2026 05:55:47 +0000 Subject: [PATCH 1/4] Finish the PsychSift rename across the repository's living surfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The app was renamed to PsychSift, but the rename stopped at the product code. The repo front page, the security policy, the container image labels and the living reference docs still advertised the retired name — including a worker runbook quoting a startup log line the worker has not emitted since the rename. Renames only surfaces that describe the system as it is now. Dated reports, plans, specs, ledgers and archives keep the old name: they record what was true when they were written, and rewriting history to match a later name makes the record less accurate, not more. `Clinical KB Database` and `Clinical KB Staging` stay throughout — those are the live Supabase projects' real names, pinned by AGENTS.md, not product names. Two codebase-index references that meant the database rather than the product are now explicit about which they mean. Extends the existing retired-name guard with a `userFacingProductSurfaces` list so these files cannot silently revert, and adds the Staging project to the regex's negative lookaheads. The guard-the-guard fixture moves from AGENTS.md, which is now clean, to a frozen quarterly archive that carries the old name by design. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01XHamg4hw5vg7EiNTjk1yu6 --- AGENTS.md | 2 +- CLAUDE.md | 2 +- Dockerfile | 6 ++-- LICENSE | 2 +- README.md | 6 ++-- SECURITY.md | 2 +- docs/README.md | 2 +- docs/clinical-badge-system-guide.md | 2 +- docs/clinical-governance.md | 2 +- docs/codebase-index.md | 8 +++--- docs/codex-prompt-playbook.md | 10 +++---- docs/deployment-architecture.md | 2 +- docs/design-system-contract.md | 2 +- docs/design-system.md | 2 +- docs/design-system/ADOPTION.md | 2 +- docs/design-system/COMPONENTS.md | 2 +- docs/design-system/DECISIONS.md | 2 +- docs/design-system/FIX-GUIDE.md | 2 +- docs/design-system/GATES.md | 2 +- docs/design-system/README.md | 2 +- docs/design-system/SPEC.md | 2 +- docs/design-system/TOKENS.md | 2 +- docs/observability-slos.md | 2 +- docs/performance.md | 2 +- docs/privacy-impact-assessment.md | 6 ++-- docs/production-readiness-checklist.md | 2 +- docs/productivity-workflows.md | 2 +- docs/pwa.md | 6 ++-- docs/ward-management-mode-map.md | 6 ++-- docs/worker-deploy-runbook.md | 2 +- mockups/README.md | 2 +- scripts/list-database-skills.mjs | 40 ++++++++++++++++++++++---- tests/database-skills.test.ts | 36 ++++++++++++++++++++--- 33 files changed, 115 insertions(+), 57 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index cc828c1904..03b80a3029 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -858,7 +858,7 @@ For Codex-specific productivity shortcuts and operating rules, see [`docs/agents ## Repository productivity skills -Automatically apply repo-local skills under `.agents/skills/` when their descriptions match the user's request. Run `npm run skills` for the validated catalog of 35 canonical skills. `npm run check:skills` verifies those skills, their compatibility aliases, and the Claude, Cursor, and Clinical KB plugin skill surfaces. The older long names remain compatibility aliases and must not be counted as unique skills. +Automatically apply repo-local skills under `.agents/skills/` when their descriptions match the user's request. Run `npm run skills` for the validated catalog of 35 canonical skills. `npm run check:skills` verifies those skills, their compatibility aliases, and the Claude, Cursor, and PsychSift plugin skill surfaces. The older long names remain compatibility aliases and must not be counted as unique skills. The foundational orchestration skills are: diff --git a/CLAUDE.md b/CLAUDE.md index 7194c3e4d8..a1f2a06a41 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,6 @@ @AGENTS.md -# Clinical KB — orientation for AI assistants +# PsychSift — orientation for AI assistants Private, local-first medical guideline RAG knowledge base for a psychiatrist in Perth, Australia. Clinical reference documents are uploaded to private Supabase Storage, indexed diff --git a/Dockerfile b/Dockerfile index 5db30acb3d..a78519ab98 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -# Clinical KB app tier (Next.js). See docs/deployment-architecture.md. +# PsychSift app tier (Next.js). See docs/deployment-architecture.md. # # The repo is engine-strict (Node 24.x / npm 11.x via .npmrc + preinstall # guard), so every stage pins the same Node 24 base image. The build stage @@ -96,8 +96,8 @@ COPY package.json next.config.ts ./ USER node EXPOSE 3000 LABEL org.opencontainers.image.source="https://github.com/BigSimmo/Database" -LABEL org.opencontainers.image.title="Clinical KB app tier" -LABEL org.opencontainers.image.description="Next.js 16 app tier for the Clinical KB medical guideline RAG knowledge base" +LABEL org.opencontainers.image.title="PsychSift app tier" +LABEL org.opencontainers.image.description="Next.js 16 app tier for the PsychSift medical guideline RAG knowledge base" LABEL org.opencontainers.image.licenses="UNLICENSED" STOPSIGNAL SIGTERM # /api/health is the app's own ops health route. diff --git a/LICENSE b/LICENSE index ee5e0ebc14..b226b24ede 100644 --- a/LICENSE +++ b/LICENSE @@ -76,7 +76,7 @@ This prohibition includes, without limitation: trade mark, confidentiality, or proprietary-rights notice. No patent, design, trade mark, trade-secret, or other non-copyright licence is -granted by this notice. Use of the names "BigSimmo", "Database", "Clinical KB", +granted by this notice. Use of the names "BigSimmo", "Database", "PsychSift", "Clinical KB", or any associated branding must not imply endorsement, affiliation, or origin. 4. GitHub, third-party licences, and mandatory legal rights diff --git a/README.md b/README.md index 57b9e2b307..94a82998c7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Clinical KB +# PsychSift Local-first medical guideline RAG knowledge base for a psychiatrist in Perth, Australia. The app uploads private clinical reference documents to Supabase @@ -100,7 +100,7 @@ For chat-driven work, use: npm run ensure ``` -This checks whether Clinical KB is already running, verifies the local server +This checks whether PsychSift is already running, verifies the local server belongs to this project, and starts the dev server in the background if needed. When you say `run` in this chat, Codex should use this command and return the printed URL. @@ -170,7 +170,7 @@ advisors, and docs lookup — not as a replacement for committed migrations. Defaults in `.cursor/mcp.json`: -- `project_ref=sjrfecxgysukkwxsowpy` — scoped to the live Clinical KB project +- `project_ref=sjrfecxgysukkwxsowpy` — scoped to the live `Clinical KB Database` Supabase project only - `read_only=true` — safer default for exploration and reviews diff --git a/SECURITY.md b/SECURITY.md index ae2316b131..f58ca37539 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,6 +1,6 @@ # Security Policy -Clinical KB (`psychiatry.tools`) is a private, single-maintainer clinical reference +PsychSift (`psychiatry.tools`) is a private, single-maintainer clinical reference application that handles private guideline documents and grounded answer generation. Security reports are taken seriously and handled privately. diff --git a/docs/README.md b/docs/README.md index 422f976ed0..1de9fdfd0e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# Clinical KB Documentation Index +# PsychSift Documentation Index Curated map of the load-bearing docs under `docs/` (not an exhaustive listing of every file). Categories distinguish **maintained** documents (keep these current when behavior diff --git a/docs/clinical-badge-system-guide.md b/docs/clinical-badge-system-guide.md index fa122985f7..63a6b5b602 100644 --- a/docs/clinical-badge-system-guide.md +++ b/docs/clinical-badge-system-guide.md @@ -1,6 +1,6 @@ # Clinical Badge System Guide -This guide defines the badge, chip, and compact label system for Clinical KB. Use it as context for future UI, medication, source, document, evidence, answer, and labelling tasks. +This guide defines the badge, chip, and compact label system for PsychSift. Use it as context for future UI, medication, source, document, evidence, answer, and labelling tasks. This document is governance only. It does not grant approval to apply badges across clinical content. Apply this system to a content area only when that area is explicitly approved for redesign or labelling work. diff --git a/docs/clinical-governance.md b/docs/clinical-governance.md index d21d53af93..044c7509b4 100644 --- a/docs/clinical-governance.md +++ b/docs/clinical-governance.md @@ -1,6 +1,6 @@ # Clinical Governance Workstream -Clinical KB is currently a source-backed clinical reference prototype. Before production clinical use, complete and record the following governance decisions. +PsychSift is currently a source-backed clinical reference prototype. Before production clinical use, complete and record the following governance decisions. ## Deployment Classification diff --git a/docs/codebase-index.md b/docs/codebase-index.md index a61549ff53..a9829195ec 100644 --- a/docs/codebase-index.md +++ b/docs/codebase-index.md @@ -1,4 +1,4 @@ -# Clinical KB — Codebase Index +# PsychSift — Codebase Index Structured map for AI agents and onboarding. For live routes, see `docs/site-map.md` (`npm run docs:update` / `sitemap:check`). For agent rules and verification gates, see `AGENTS.md`; for test execution and flake policy, see `docs/testing.md`. @@ -36,7 +36,7 @@ Smaller top-level directories that are easy to miss: | Path | Purpose | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `caring-contacts/` | Isolated Caring Contacts module migrations and local database-test runner. These migrations are deliberately separate from `supabase/migrations/` and must never target the Clinical KB project. | +| `caring-contacts/` | Isolated Caring Contacts module migrations and local database-test runner. These migrations are deliberately separate from `supabase/migrations/` and must never target the `Clinical KB Database` Supabase project. | | `data/` | Committed clinical **snapshot exports** loaded at runtime by `src/lib/` (differentials, forms, medications, services, specifiers). Regenerate via the matching `scripts/import-*-export.ts` / `build-*-index.mjs`; do not hand-edit. Distinct from `src/data/`, which holds hand-authored static content. | | `eval/` | Isolated evaluation labs, outside the product/runtime dependency graph. `eval/docling/` is the sandboxed, dispatch-only Docling extraction benchmark (own hashed Python lock + venvs, egress-blocked Docker run, synthetic fixtures + hostile corpus, aggregate-only reports; `docs/rag-improvement/README.md` §B3) | | `eslint-rules/` | Repo-specific lint rules enforced by `npm run lint` (button wiring, hardcoded hex, type/icon scale, z-index ladder) | @@ -211,7 +211,7 @@ relative imports within its directory, provides deny-by-default team-scoped perm privacy-safe audit records, and is exercised against both in-memory and local Postgres repositories. `src/lib/caring-contacts-server/` is the server-side seam for the demo session and optional separate database connection. It must fail closed in production and must never -connect to the Clinical KB Supabase project. The standalone `src/app/caring-contacts/` workspace +connect to the `Clinical KB Database` Supabase project. The standalone `src/app/caring-contacts/` workspace is noindex, visibly marked synthetic, and has a single inbound entry from the Tools catalogue. Inside the workspace, `src/components/caring-contacts/workspace/shell.tsx` owns the whole @@ -447,7 +447,7 @@ sequenceDiagram API-->>U: response (cached in rag_response_cache) ``` -### Clinical KB surface +### PsychSift surface - 15 app modes with unified search shell - Documents mode: browse indexed guidelines, search, scope, and inspect cited answers; document uploads remain in the administrator backend diff --git a/docs/codex-prompt-playbook.md b/docs/codex-prompt-playbook.md index d7f50ad388..d5972a75d7 100644 --- a/docs/codex-prompt-playbook.md +++ b/docs/codex-prompt-playbook.md @@ -1,6 +1,6 @@ # Codex Prompt Playbook -This playbook contains copy/paste prompts for common Clinical KB work. The +This playbook contains copy/paste prompts for common PsychSift work. The prompts are written for this repository, not for a generic Next.js project. Before using any prompt, keep these project defaults in mind: @@ -80,7 +80,7 @@ builds, commits, pushes, or cleanup unless I explicitly approve. Use this instead of asking for a guessed localhost URL. ```text -Run the Clinical KB app safely. +Run the PsychSift app safely. Follow AGENTS.md local-server safety. Execute npm run ensure, let it choose the project-specific URL, verify the server identity through the repo helper, and @@ -661,7 +661,7 @@ Do not modify files unless I explicitly ask for fixes after the review. ## 23. OpenAI Cookbook Review For This Repo Use this when you want a fresh pass over current OpenAI Cookbook patterns before -changing the Clinical KB RAG, answer, ingestion, eval, or prompt stack. +changing the PsychSift RAG, answer, ingestion, eval, or prompt stack. ```text Review the current OpenAI Cookbook and recommend what should be adopted in this @@ -800,7 +800,7 @@ Use this for image-heavy PDFs, tables, forms, diagrams, medication charts, or source pages where text-only retrieval may miss important evidence. ```text -Review multimodal/visual evidence support for this Clinical KB workflow. +Review multimodal/visual evidence support for this PsychSift workflow. Start read-only and offline. Inspect: - src/lib/visual-intelligence.ts @@ -830,7 +830,7 @@ Use this when prompt injection, off-topic questions, unsafe clinical confidence, or unsupported output could reach users. ```text -Review and harden Clinical KB RAG guardrails. +Review and harden PsychSift RAG guardrails. Focus on both input and output guardrails: - prompt injection and jailbreak attempts inside user queries or retrieved text diff --git a/docs/deployment-architecture.md b/docs/deployment-architecture.md index 6a6671ef46..bc590ebc67 100644 --- a/docs/deployment-architecture.md +++ b/docs/deployment-architecture.md @@ -1,6 +1,6 @@ # Deployment Architecture -Decision record for the production topology of Clinical KB. Written 2026-07-06, +Decision record for the production topology of PsychSift. Written 2026-07-06, revised 2026-07-12 when the app went live on Railway. Companion documents: `docs/observability-slos.md` (SLOs + eval canary) and `docs/audit/capacity-review.md` (load model, first bottleneck, soak test). diff --git a/docs/design-system-contract.md b/docs/design-system-contract.md index 9e8ddff716..75175c89b0 100644 --- a/docs/design-system-contract.md +++ b/docs/design-system-contract.md @@ -1,6 +1,6 @@ # Design System Contract & Standards -This document specifies the blocking design system token rules, touch/tap target standards, and enforcement mechanisms for the Clinical KB application. +This document specifies the blocking design system token rules, touch/tap target standards, and enforcement mechanisms for the PsychSift application. --- diff --git a/docs/design-system.md b/docs/design-system.md index 5b43376765..7a0d2f739e 100644 --- a/docs/design-system.md +++ b/docs/design-system.md @@ -1,4 +1,4 @@ -# Clinical KB Design System — the front door +# PsychSift Design System — the front door > **Superseded as spec (31 July 2026).** The system of record is now > [`docs/design-system/`](./design-system/README.md) — SPEC, TOKENS, COMPONENTS, DECISIONS, diff --git a/docs/design-system/ADOPTION.md b/docs/design-system/ADOPTION.md index 988e503243..6089a34754 100644 --- a/docs/design-system/ADOPTION.md +++ b/docs/design-system/ADOPTION.md @@ -1,4 +1,4 @@ -# Clinical KB design system — ADOPTION +# PsychSift design system — ADOPTION **The committed ownership and disposition contract for every production surface.** The source of truth is `adoption-contract.json`; the generated manifest and marked tables in this document diff --git a/docs/design-system/COMPONENTS.md b/docs/design-system/COMPONENTS.md index cf48d70887..1ad3cae5c5 100644 --- a/docs/design-system/COMPONENTS.md +++ b/docs/design-system/COMPONENTS.md @@ -1,4 +1,4 @@ -# Clinical KB design system — COMPONENTS +# PsychSift design system — COMPONENTS **The public component contracts, their local publication state, and the remaining specifications.** Prop shapes are normative contracts; token references are roles only — diff --git a/docs/design-system/DECISIONS.md b/docs/design-system/DECISIONS.md index dd8a28e5d7..c8a5c973c5 100644 --- a/docs/design-system/DECISIONS.md +++ b/docs/design-system/DECISIONS.md @@ -1,4 +1,4 @@ -# Clinical KB design system — DECISIONS +# PsychSift design system — DECISIONS **The six conflicts resolved — what was chosen, what was rejected, and why — plus the clinical Q&A that shaped the component specs, the assumptions register, and the blocked diff --git a/docs/design-system/FIX-GUIDE.md b/docs/design-system/FIX-GUIDE.md index 9b194b5e5f..5304584e22 100644 --- a/docs/design-system/FIX-GUIDE.md +++ b/docs/design-system/FIX-GUIDE.md @@ -1,4 +1,4 @@ -# Clinical KB design system — Hazard 1–2 fix guide +# PsychSift design system — Hazard 1–2 fix guide Single appendix for the closed Hazard 1–2 sweep. **Rules and roles stay in SPEC / TOKENS / GATES; this file only records dispositions.** A Documented row is not a licence to change diff --git a/docs/design-system/GATES.md b/docs/design-system/GATES.md index 7387ca9b74..f341d83dff 100644 --- a/docs/design-system/GATES.md +++ b/docs/design-system/GATES.md @@ -1,4 +1,4 @@ -# Clinical KB design system — GATES +# PsychSift design system — GATES **Every rule paired with the check that enforces it.** Labels: **implemented-blocking** (runs in `verify:cheap`/CI and fails the build) · **implemented-partial** (a real check diff --git a/docs/design-system/README.md b/docs/design-system/README.md index 701a879c38..75e93ba520 100644 --- a/docs/design-system/README.md +++ b/docs/design-system/README.md @@ -1,4 +1,4 @@ -# Clinical KB design system — document set +# PsychSift design system — document set The system of record for the v2 design system. **Rules and roles live here; values live only in the token files.** Source-of-truth ranking: `AGENTS.md` → `ckb-v2-tokens.css` → diff --git a/docs/design-system/SPEC.md b/docs/design-system/SPEC.md index 63c4747202..47d2aadd31 100644 --- a/docs/design-system/SPEC.md +++ b/docs/design-system/SPEC.md @@ -1,4 +1,4 @@ -# Clinical KB design system — SPEC +# PsychSift design system — SPEC **The complete design system: roles, rules, rationale. Never values.** Token values live in `src/app/ckb-v2-tokens.css` (branch copy) and `src/app/globals.css` (live layer) only — a value diff --git a/docs/design-system/TOKENS.md b/docs/design-system/TOKENS.md index 4ef3f43885..1f8e78deac 100644 --- a/docs/design-system/TOKENS.md +++ b/docs/design-system/TOKENS.md @@ -1,4 +1,4 @@ -# Clinical KB design system — TOKENS +# PsychSift design system — TOKENS **The reconciled token inventory (conflict C1 resolved): every role, its winning name, its owner, and what it replaces. Never values** — values live only in the owner file named per diff --git a/docs/observability-slos.md b/docs/observability-slos.md index 36df5f7b97..d261f209c9 100644 --- a/docs/observability-slos.md +++ b/docs/observability-slos.md @@ -1,6 +1,6 @@ # Observability & SLOs -Service-level objectives for the Clinical KB answer pipeline, the alert +Service-level objectives for the PsychSift answer pipeline, the alert thresholds attached to them, and the weekly production eval canary that turns the golden eval into a standing guard. Written 2026-07-06. diff --git a/docs/performance.md b/docs/performance.md index 20f714c4b8..9a89117a57 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -1,6 +1,6 @@ # Performance and Web Vitals Baselines -This document outlines performance benchmarks, layout stability strategies, and Core Web Vitals baselines for the Clinical KB application. +This document outlines performance benchmarks, layout stability strategies, and Core Web Vitals baselines for the PsychSift application. --- diff --git a/docs/privacy-impact-assessment.md b/docs/privacy-impact-assessment.md index 433af4b89f..2c886c3c95 100644 --- a/docs/privacy-impact-assessment.md +++ b/docs/privacy-impact-assessment.md @@ -3,7 +3,7 @@ **Current status authority:** [`docs/governance/privacy-readiness.v1.json`](governance/privacy-readiness.v1.json). This narrative explains the assessment; the versioned register separates code proof from provider configuration, legal approval, and clinical acceptance. Pending external items in that register are not completed by technical controls described here. **Status:** Draft for governance approval · **Date:** 2026-07-06 · **Revised:** 2026-08-23 -**Scope:** Clinical data flows through the Clinical KB app (Next.js on Railway Singapore + Supabase Sydney + OpenAI), the live Supabase project `Clinical KB Database` (`sjrfecxgysukkwxsowpy`), and the WA private-clinical deployment context. +**Scope:** Clinical data flows through the PsychSift app (Next.js on Railway Singapore + Supabase Sydney + OpenAI), the live Supabase project `Clinical KB Database` (`sjrfecxgysukkwxsowpy`), and the WA private-clinical deployment context. **Author:** Automated code-level assessment (multi-agent audit of `src/app/api/**`, `src/lib/*`, `supabase/schema.sql`, `supabase/migrations/**`), cross-checked against the live database. **Repository last verified:** `1f193d7b633e9b45602bd39056a957811e62b521` on 2026-08-23. @@ -72,7 +72,7 @@ material. | Clinical reference corpus (documents, chunks, embeddings, images, tables) | Supabase (Sydney) + storage buckets | Low–Medium | Published guidelines are not PHI; **uploaded** docs _could_ contain PHI. | | Free-text clinical queries | Processed by Railway (Singapore); hashed into Supabase logs (Sydney); sent to OpenAI (US) for retrieval embedding and, when selected, answer synthesis | **High (potential PHI)** | The primary incidental-PHI vector; embedding egress can occur even when the final answer is source-only. | | Generated answers | `rag_queries.answer` (not persisted unless `RAG_PERSIST_ANSWER_TEXT`); short-lived `rag_response_cache.payload` | **High (derived from PHI query + corpus)** | Durable answer log dropped at rest by default (PIA-3); expired cache rows have a bounded hourly purge when `pg_cron` is available. | -| Safety-plan working content | React memory in the current browser tab; user-directed clipboard, print, or PDF output | **High (sensitive health information)** | No patient-identifier field; not sent to the application service or stored by Clinical KB. Exported copies leave this boundary. | +| Safety-plan working content | React memory in the current browser tab; user-directed clipboard, print, or PDF output | **High (sensitive health information)** | No patient-identifier field; not sent to the application service or stored by PsychSift. Exported copies leave this boundary. | | User identity | Supabase Auth (`auth.users`), `owner_id` foreign keys | Medium (PII) | Email + SSO identity; managed by Supabase Auth. | | Audit trail | `audit_logs` | Medium | Append-only, service-role-only, retained indefinitely by design. | | Operational telemetry | `rag_retrieval_logs`, ingestion job tables | Low–Medium | Redacted query text; per-owner. | @@ -140,7 +140,7 @@ OpenAI as the only cross-border flow. The `/safety-plan` route has a separate local-only flow: form inputs update React state in the current browser tab, with no API request or browser-storage write. Clearing the plan, unmounting the component, or closing the tab discards that working state. Copy, print, and save-as-PDF are explicit user-directed -exports; the exported copy is outside Clinical KB and must be handled under the organisation's approved +exports; the exported copy is outside PsychSift and must be handled under the organisation's approved clinical-record process. The tool provides no patient name, date-of-birth, or record-number field and warns against putting patient identifiers into free text; any patient identifier must be added after export if local policy permits it. Support-contact names and phone details are accepted as sensitive diff --git a/docs/production-readiness-checklist.md b/docs/production-readiness-checklist.md index 45a3740824..3c18393690 100644 --- a/docs/production-readiness-checklist.md +++ b/docs/production-readiness-checklist.md @@ -1,4 +1,4 @@ -# Clinical KB Production Readiness Checklist (Executable Today) +# PsychSift Production Readiness Checklist (Executable Today) **Status: reusable release-candidate checklist, not an outstanding-task ledger.** Live/provider-gated action detail is indexed in [`operator-backlog.md`](operator-backlog.md); canonical task status is diff --git a/docs/productivity-workflows.md b/docs/productivity-workflows.md index 5ed05f82ab..9d49338463 100644 --- a/docs/productivity-workflows.md +++ b/docs/productivity-workflows.md @@ -1,6 +1,6 @@ # Productivity workflows -The repository exposes a validated catalog of 35 canonical Database skills. Run `npm run skills` to list them by category. `npm run check:skills` validates the 35 canonical skills, 8 compatibility aliases, and every Claude, Cursor, and Clinical KB plugin `SKILL.md` for metadata, local links, npm commands, frozen-ledger discipline, provider approval boundaries, and destructive-action safeguards. +The repository exposes a validated catalog of 35 canonical Database skills. Run `npm run skills` to list them by category. `npm run check:skills` validates the 35 canonical skills, 8 compatibility aliases, and every Claude, Cursor, and PsychSift plugin `SKILL.md` for metadata, local links, npm commands, frozen-ledger discipline, provider approval boundaries, and destructive-action safeguards. The repository exposes seven offline-first workflow planners. Each planner inspects the current change through `scripts/ci-change-scope.mjs`, prints a minimal local verification sequence, and separates provider-backed commands into an explicit approval section. diff --git a/docs/pwa.md b/docs/pwa.md index b5188936c6..5c023bb5d3 100644 --- a/docs/pwa.md +++ b/docs/pwa.md @@ -1,6 +1,6 @@ # Progressive Web App architecture -Clinical KB is an installable, production-first PWA with a deliberately limited offline surface. The service worker +PsychSift is an installable, production-first PWA with a deliberately limited offline surface. The service worker improves launch, static-asset reuse, update handling, and failure messaging without turning private clinical data into durable browser storage. @@ -55,7 +55,7 @@ install/Add to Home Screen flow. The install card is not shown in standalone mode. It stays non-blocking and lower-right on wide screens; on phones it becomes a compact sheet positioned clear of the current composer owner (above a bottom dock or below an in-flow home composer) and the safe area. The benefit list is deliberately limited to quick access, app-like launch, and the -familiar Clinical KB workspace. It does not imply offline clinical access. +familiar PsychSift workspace. It does not imply offline clinical access. Choosing **Not now**, using **Dismiss**, or dismissing the browser prompt suppresses the custom prompt for 30 days using `clinical-kb-pwa-install-dismissed-at` in localStorage. `appinstalled` clears that value. Storage failures are treated as non-fatal progressive-enhancement failures. @@ -333,7 +333,7 @@ These omissions are deliberate and must not be added as generic PWA enhancements | Push notifications | Deferred. It requires a permission and subscription UX, backend key/subscription lifecycle, revocation, and a clinical privacy policy for lock-screen content. No safe notification payload or product need is currently defined. | | Background Sync / Periodic Background Sync | Deferred. Queuing or replaying clinical queries, uploads, answers, or mutations risks sensitive local persistence, duplicate writes, stale auth, and actions occurring after the user's context changed. Browser support is also not a correctness guarantee. | | Web Share Target / inbound sharing | Deferred. Accepting text, URLs, or documents from another app needs an explicit consent, validation, auth, provenance, malware/file-safety, and retention flow. The manifest intentionally has no `share_target`. | -| File handlers | Deferred. Associating Clinical KB with clinical document types could import sensitive files without the existing upload review and validation context. The manifest intentionally has no `file_handlers`. | +| File handlers | Deferred. Associating PsychSift with clinical document types could import sensitive files without the existing upload review and validation context. The manifest intentionally has no `file_handlers`. | | Offline clinical data, search, or answers | Prohibited by the current privacy model. Cached clinical guidance can become stale, lose revocation/auth guarantees, separate answers from source provenance, and expose private content to durable same-origin storage. Only the generic offline shell and public application assets are allowed. | Any proposal to enable one of these capabilities needs a product decision, threat model, privacy review, data lifecycle, diff --git a/docs/ward-management-mode-map.md b/docs/ward-management-mode-map.md index 3e1bb3f77a..2c7eed38af 100644 --- a/docs/ward-management-mode-map.md +++ b/docs/ward-management-mode-map.md @@ -15,7 +15,7 @@ diagram and explainable shortlist in one view — and absorbs the working-surfac used to carry; the table below is corrected to drop the Constellation row. The eight remaining mode links (Command, Network, Priority queue, Capacity, Movements, Exceptions, Transport, Governance) moved out of the horizontal mode strip and into the left `ClinicalRail`, per the -owner's direction that Ward Flow is its own application inside the Clinical KB shell and free to +owner's direction that Ward Flow is its own application inside the PsychSift shell and free to use that rail for its own navigation. See "Navigation" below. **Status:** Synthetic product wireframe. The routes below model a WA mental-health patient-flow coordination layer; they do not claim to reproduce an internal WA Health system or current allocation policy. @@ -49,10 +49,10 @@ The public WA sources used to ground the wireframes establish five important con | Transport | `/mockups/ward-flow/transport` | Is the legal/document/booking chain ready for safe transfer? | Transport readiness board and metro/country pathway cues | ED / Flow coordinator | | Governance | `/mockups/ward-flow/governance` | Why did the system recommend this, who confirmed it, and what is synthetic? | AI assurance, audit trail, data boundary and source register | Authorised reviewers | -**Navigation:** the left `ClinicalRail` carries both the global Clinical KB application switcher +**Navigation:** the left `ClinicalRail` carries both the global PsychSift application switcher and, below it, Ward Flow's own eight mode links (icon-only, each with its own accessible name) — there is no separate horizontal mode strip. This follows from Ward Flow being its own application -inside the Clinical KB shell, free to use that rail as its own local navigation, and it also gives +inside the PsychSift shell, free to use that rail as its own local navigation, and it also gives the coordinator screen back the vertical space the horizontal strip used to take. The rail stays visible and reachable down to 320px; on a short viewport the mode-link section scrolls independently of the pinned app-switcher icons above it and the pinned favourites/settings/avatar diff --git a/docs/worker-deploy-runbook.md b/docs/worker-deploy-runbook.md index 968e92ad40..b8130590d6 100644 --- a/docs/worker-deploy-runbook.md +++ b/docs/worker-deploy-runbook.md @@ -524,7 +524,7 @@ The second Gate B caveat is already load-bearing above: docling's eager-mode lat ## 4. Verify -1. **Startup.** Logs show `Clinical KB worker started. worker=`. If a +1. **Startup.** Logs show `PsychSift worker started. worker=`. If a `PDF/OCR prerequisite warning` appears, the Python/Tesseract layer did not build correctly — rebuild the image (do not leave it running; OCR fallback will be silently unavailable). diff --git a/mockups/README.md b/mockups/README.md index a3f63e13b5..5e4e58678f 100644 --- a/mockups/README.md +++ b/mockups/README.md @@ -164,7 +164,7 @@ Mockups use the Clinical White / Sky Graphite role tokens (`--command`, `--clini ## Global search shell -Runnable mockups under `src/app/mockups/*` inherit the shared Clinical KB header and bottom search composer from `src/app/mockups/layout.tsx`. +Runnable mockups under `src/app/mockups/*` inherit the shared PsychSift header and bottom search composer from `src/app/mockups/layout.tsx`. - Put the mockup content between the global header and bottom composer; do not copy the header or composer into new pages. - Favourites mockups and Tools mockups that provide their own primary search surface keep the shared app header but hide the bottom composer. diff --git a/scripts/list-database-skills.mjs b/scripts/list-database-skills.mjs index 86243e434b..c40c1005ec 100644 --- a/scripts/list-database-skills.mjs +++ b/scripts/list-database-skills.mjs @@ -369,10 +369,34 @@ export const userFacingPluginMetadata = [ "plugins/clinical-kb/README.md", ]; -/** The product's retired name. `Clinical KB Database` is the live Supabase - * project and is excluded by the negative lookahead — it is the database's - * real name, pinned by AGENTS.md, not a product name. */ -const RETIRED_PRODUCT_NAME = /Clinical KB(?! Database)/g; +/** The product's retired name. `Clinical KB Database` and `Clinical KB + * Staging` are the live Supabase projects and are excluded by the negative + * lookaheads — those are the databases' real names, pinned by AGENTS.md, not + * product names. */ +const RETIRED_PRODUCT_NAME = /Clinical KB(?! Database)(?! Staging)/g; + +/** Repository surfaces outside the plugin whose *user-facing* text names the + * product: the repo front page, the security policy, the container image + * labels, and the living reference docs a person reads to learn what this is. + * Dated reports, plans, specs, ledgers and archives are deliberately NOT + * covered — they record what was true when they were written, and rewriting + * history to match a later name makes the record less accurate, not more. + * `Clinical KB Database` and `Clinical KB Staging` stay: those are the live + * Supabase projects' real names, pinned by AGENTS.md. */ +export const userFacingProductSurfaces = [ + "README.md", + "SECURITY.md", + "Dockerfile", + "mockups/README.md", + "docs/README.md", + "docs/codebase-index.md", + "docs/pwa.md", + "docs/privacy-impact-assessment.md", + "docs/clinical-governance.md", + "docs/deployment-architecture.md", + "docs/production-readiness-checklist.md", + "docs/design-system/README.md", +]; export function validatePluginProductName(files = userFacingPluginMetadata) { const errors = []; @@ -399,7 +423,13 @@ function run(argv = process.argv.slice(2)) { const validation = validateSkillCatalog(catalog); const repositoryValidation = validateRepositorySkillPolicies(); const productName = validatePluginProductName(); - const errors = [...validation.errors, ...repositoryValidation.errors, ...productName.errors]; + const productSurfaces = validatePluginProductName(userFacingProductSurfaces); + const errors = [ + ...validation.errors, + ...repositoryValidation.errors, + ...productName.errors, + ...productSurfaces.errors, + ]; if (errors.length) { console.error(errors.map((error) => `- ${error}`).join("\n")); process.exitCode = 1; diff --git a/tests/database-skills.test.ts b/tests/database-skills.test.ts index 4078f2c7aa..a1d7056228 100644 --- a/tests/database-skills.test.ts +++ b/tests/database-skills.test.ts @@ -6,6 +6,7 @@ import { describe, expect, it } from "vitest"; import { validatePluginProductName, userFacingPluginMetadata, + userFacingProductSurfaces, discoverSkillDefinitions, discoverRepositorySkillFiles, loadSkillCatalog, @@ -162,10 +163,11 @@ describe("the plugin's user-facing product name", () => { }); it("still fails when a surface reverts to the retired name", () => { - // Guards the guard: a check that cannot fail is not a check. Uses a file - // that genuinely still carries the string — AGENTS.md documents the rename - // and quotes the old name — so nothing has to be written to disk. - const { errors } = validatePluginProductName(["AGENTS.md"]); + // Guards the guard: a check that cannot fail is not a check. Uses a frozen + // quarterly archive, which genuinely still carries the string and always + // will — rewriting a historical record to match a later name is exactly + // what the surface list refuses to do — so nothing is written to disk. + const { errors } = validatePluginProductName(["docs/archive/branch-review-ledger-2026-q3.md"]); expect(errors).toHaveLength(1); expect(errors[0]).toContain("retired product name"); }); @@ -177,3 +179,29 @@ describe("the plugin's user-facing product name", () => { } }); }); + +describe("the repository's user-facing product name", () => { + // The app was renamed to PsychSift but the repo front page, the security + // policy, the container image labels and the living reference docs kept the + // retired name — including a worker runbook quoting a startup log line the + // worker has not emitted since the rename. Only living surfaces are covered: + // dated reports, plans and ledgers record what was true when written. + it("is clean across every repository surface a person reads", () => { + expect(validatePluginProductName(userFacingProductSurfaces).errors).toEqual([]); + }); + + it("keeps the live Supabase project names, which are not the product name", () => { + // `Clinical KB Database` and `Clinical KB Staging` are pinned by AGENTS.md. + // A guard that stripped them would rename a real database out of the docs. + const index = fs.readFileSync(path.resolve(import.meta.dirname, "..", "docs/codebase-index.md"), "utf8"); + expect(index).toContain("Clinical KB Database"); + expect(validatePluginProductName(["docs/codebase-index.md"]).errors).toEqual([]); + }); + + it("names only files that exist", () => { + expect(userFacingProductSurfaces.length).toBeGreaterThan(0); + for (const file of userFacingProductSurfaces) { + expect(fs.existsSync(path.join(path.resolve(import.meta.dirname, ".."), file)), file).toBe(true); + } + }); +}); From 0ac2621f88cf882594eec225bc686cf21d5ff6a9 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Aug 2026 06:16:18 +0000 Subject: [PATCH 2/4] Guard both container images and every renamed living surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex review on #2461 found the guard list covered the app Dockerfile while Dockerfile.worker still shipped the retired name in both published OCI labels, and that the list omitted most of the surfaces this rename had already touched — so they could regress silently. Both parts were correct. The root cause was a truncated sweep: the original repository-wide search was piped through `head -30`, which cut off Dockerfile.worker, and the resulting partial list was treated as complete. Renames the three remaining occurrences in Dockerfile.worker, plus three more living surfaces the same truncation hid: CONTEXT.md, .design-sync/NOTES.md and .design-sync/conventions.md. Expands userFacingProductSurfaces from a 12-file sample to all 34 living surfaces this rename touches, so the guard's coverage matches its stated purpose. LICENSE stays out deliberately — its protected-names clause keeps the former name alongside the current one. Adds a test that enumerates Dockerfile* from disk and asserts each is guarded, so a second published image cannot again be renamed without its guard entry. Verified it fails without the fix. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01XHamg4hw5vg7EiNTjk1yu6 --- .design-sync/NOTES.md | 2 +- .design-sync/conventions.md | 2 +- CONTEXT.md | 2 +- Dockerfile.worker | 6 ++-- scripts/list-database-skills.mjs | 50 +++++++++++++++++++++++++------- tests/database-skills.test.ts | 15 ++++++++++ 6 files changed, 61 insertions(+), 16 deletions(-) diff --git a/.design-sync/NOTES.md b/.design-sync/NOTES.md index 71cbd74bed..c688378b73 100644 --- a/.design-sync/NOTES.md +++ b/.design-sync/NOTES.md @@ -1,4 +1,4 @@ -# design-sync notes — Clinical KB +# design-sync notes — PsychSift **Day-to-day:** run `node scripts/design-sync.mjs` from the repo root. That installs the gitignored `.ds-sync` toolchain and compiles CSS into `.design-sync/.cache/compiled.css`. diff --git a/.design-sync/conventions.md b/.design-sync/conventions.md index c52cf4f61d..007fa34e7f 100644 --- a/.design-sync/conventions.md +++ b/.design-sync/conventions.md @@ -1,4 +1,4 @@ -# Clinical KB — build conventions +# PsychSift — build conventions > The system of record is `docs/design-system/` (SPEC · TOKENS · COMPONENTS · DECISIONS · > GATES). This file is the designer-facing build idiom; where it disagrees with that set, diff --git a/CONTEXT.md b/CONTEXT.md index 3af7ed2156..41d22d1287 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -33,7 +33,7 @@ Structured content from the selected mode's repository-owned catalogue, carrying _Avoid_: Model knowledge, database truth **Indexed Evidence**: -Retrieved excerpts from authorised documents already indexed by Clinical KB. +Retrieved excerpts from authorised documents already indexed by PsychSift. _Avoid_: Uploaded truth, internal authority **External Authority Evidence**: diff --git a/Dockerfile.worker b/Dockerfile.worker index 6bed2d5d32..52f0644a60 100644 --- a/Dockerfile.worker +++ b/Dockerfile.worker @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -# Clinical KB ingestion worker (Node pipeline + Python OCR stack). +# PsychSift ingestion worker (Node pipeline + Python OCR stack). # See docs/deployment-architecture.md for why the worker ships as a # container instead of completing the edge-agent migration. # @@ -109,8 +109,8 @@ USER node # before the image is promoted. It never calls Supabase/OpenAI or claims jobs. RUN node dist/worker/validate-runtime.mjs LABEL org.opencontainers.image.source="https://github.com/BigSimmo/Database" -LABEL org.opencontainers.image.title="Clinical KB ingestion worker" -LABEL org.opencontainers.image.description="Node + Python OCR ingestion worker for the Clinical KB medical guideline RAG knowledge base" +LABEL org.opencontainers.image.title="PsychSift ingestion worker" +LABEL org.opencontainers.image.description="Node + Python OCR ingestion worker for the PsychSift medical guideline RAG knowledge base" LABEL org.opencontainers.image.licenses="UNLICENSED" STOPSIGNAL SIGTERM # Long-poll worker; WORKER_* env vars control claim batch size, concurrency, diff --git a/scripts/list-database-skills.mjs b/scripts/list-database-skills.mjs index c40c1005ec..606d6e2265 100644 --- a/scripts/list-database-skills.mjs +++ b/scripts/list-database-skills.mjs @@ -376,26 +376,56 @@ export const userFacingPluginMetadata = [ const RETIRED_PRODUCT_NAME = /Clinical KB(?! Database)(?! Staging)/g; /** Repository surfaces outside the plugin whose *user-facing* text names the - * product: the repo front page, the security policy, the container image - * labels, and the living reference docs a person reads to learn what this is. + * product: the repo front page, the security policy, BOTH container images' + * published OCI labels, and the living reference docs a person reads to learn + * what this is. Every living surface this rename touched is listed — a partial + * list is what let the app `Dockerfile` be renamed while `Dockerfile.worker` + * kept shipping the retired name in `org.opencontainers.image.title`. + * * Dated reports, plans, specs, ledgers and archives are deliberately NOT * covered — they record what was true when they were written, and rewriting * history to match a later name makes the record less accurate, not more. - * `Clinical KB Database` and `Clinical KB Staging` stay: those are the live - * Supabase projects' real names, pinned by AGENTS.md. */ + * `LICENSE` is also excluded on purpose: its protected-names clause keeps the + * former name alongside the current one, because the former name still needs + * the same no-endorsement protection. + * + * `Clinical KB Database` and `Clinical KB Staging` stay wherever they appear: + * those are the live Supabase projects' real names, pinned by AGENTS.md. */ export const userFacingProductSurfaces = [ + ".design-sync/NOTES.md", + ".design-sync/conventions.md", + "AGENTS.md", + "CLAUDE.md", + "CONTEXT.md", + "Dockerfile", + "Dockerfile.worker", "README.md", "SECURITY.md", - "Dockerfile", - "mockups/README.md", "docs/README.md", - "docs/codebase-index.md", - "docs/pwa.md", - "docs/privacy-impact-assessment.md", + "docs/clinical-badge-system-guide.md", "docs/clinical-governance.md", + "docs/codebase-index.md", + "docs/codex-prompt-playbook.md", "docs/deployment-architecture.md", - "docs/production-readiness-checklist.md", + "docs/design-system-contract.md", + "docs/design-system.md", + "docs/design-system/ADOPTION.md", + "docs/design-system/COMPONENTS.md", + "docs/design-system/DECISIONS.md", + "docs/design-system/FIX-GUIDE.md", + "docs/design-system/GATES.md", "docs/design-system/README.md", + "docs/design-system/SPEC.md", + "docs/design-system/TOKENS.md", + "docs/observability-slos.md", + "docs/performance.md", + "docs/privacy-impact-assessment.md", + "docs/production-readiness-checklist.md", + "docs/productivity-workflows.md", + "docs/pwa.md", + "docs/ward-management-mode-map.md", + "docs/worker-deploy-runbook.md", + "mockups/README.md", ]; export function validatePluginProductName(files = userFacingPluginMetadata) { diff --git a/tests/database-skills.test.ts b/tests/database-skills.test.ts index a1d7056228..751ca8a140 100644 --- a/tests/database-skills.test.ts +++ b/tests/database-skills.test.ts @@ -204,4 +204,19 @@ describe("the repository's user-facing product name", () => { expect(fs.existsSync(path.join(path.resolve(import.meta.dirname, ".."), file)), file).toBe(true); } }); + + it("guards every container image, because both publish the name in OCI labels", () => { + // The miss this test exists for: the app `Dockerfile` was renamed and + // guarded while `Dockerfile.worker` kept shipping the retired name in + // `org.opencontainers.image.title` and `.description`. A guard list that + // covers one of two published images reads as complete and is not, so + // enumerate the images from disk rather than trusting the list. + const root = path.resolve(import.meta.dirname, ".."); + const images = fs.readdirSync(root).filter((entry) => /^Dockerfile(\..+)?$/.test(entry)); + expect(images).toContain("Dockerfile"); + expect(images).toContain("Dockerfile.worker"); + for (const image of images) { + expect(userFacingProductSurfaces, `${image} publishes OCI labels and must be guarded`).toContain(image); + } + }); }); From 489fd8648bf01daa6bc40bea8f28b08578561175 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Mon, 31 Aug 2026 02:57:04 +0800 Subject: [PATCH 3/4] test(caring-contacts): pin contact adjustment clock --- .../caring-contacts-contact-time-adjustment.dom.test.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/caring-contacts-contact-time-adjustment.dom.test.tsx b/tests/caring-contacts-contact-time-adjustment.dom.test.tsx index e644be5eed..b0a399021c 100644 --- a/tests/caring-contacts-contact-time-adjustment.dom.test.tsx +++ b/tests/caring-contacts-contact-time-adjustment.dom.test.tsx @@ -23,7 +23,7 @@ import { act, cleanup, render, screen, waitFor } from "@testing-library/react"; import { PLAN_ASSURANCE_VALUES } from "@/lib/caring-contacts/assurances"; import userEvent from "@testing-library/user-event"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; /** * The router, replaced so `refresh()` is observable. @@ -263,6 +263,13 @@ function openOverlayId(): string | null { return document.querySelector('[data-testid="workspace-overlay-content"]')?.getAttribute("data-overlay-id") ?? null; } +beforeAll(() => { + vi.useFakeTimers({ shouldAdvanceTime: true }); + vi.setSystemTime(new Date(NOW)); +}); + +afterAll(() => vi.useRealTimers()); + beforeEach(() => { actingRole = "coordinator"; requested = []; From 44bcc6fd8ac481854bf3bb835793384b2cd44852 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Mon, 31 Aug 2026 03:04:52 +0800 Subject: [PATCH 4/4] test: keep baseline repair out of rename PR --- ...tacts-contact-time-adjustment.dom.test.tsx | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/tests/caring-contacts-contact-time-adjustment.dom.test.tsx b/tests/caring-contacts-contact-time-adjustment.dom.test.tsx index b0a399021c..ecd2209015 100644 --- a/tests/caring-contacts-contact-time-adjustment.dom.test.tsx +++ b/tests/caring-contacts-contact-time-adjustment.dom.test.tsx @@ -20,10 +20,10 @@ // HTTP boundary: `route.ts` imports `server-only` and `next/headers`, and it has its own suite in // `tests/caring-contacts-contact-route.test.ts`, which asserts the same refusals against the real // handler. -import { act, cleanup, render, screen, waitFor } from "@testing-library/react"; +import { act, cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react"; import { PLAN_ASSURANCE_VALUES } from "@/lib/caring-contacts/assurances"; import userEvent from "@testing-library/user-event"; -import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; /** * The router, replaced so `refresh()` is observable. @@ -263,13 +263,6 @@ function openOverlayId(): string | null { return document.querySelector('[data-testid="workspace-overlay-content"]')?.getAttribute("data-overlay-id") ?? null; } -beforeAll(() => { - vi.useFakeTimers({ shouldAdvanceTime: true }); - vi.setSystemTime(new Date(NOW)); -}); - -afterAll(() => vi.useRealTimers()); - beforeEach(() => { actingRole = "coordinator"; requested = []; @@ -335,8 +328,7 @@ describe("moving one contact within its day", () => { await waitFor(() => expect(outcomeText()).toContain("11:30 AWST")); // The second move, with no server render in between. - await userEvent.clear(timeField()); - await userEvent.type(timeField(), "15:45"); + fireEvent.change(timeField(), { target: { value: "15:45" } }); await openOverlay(); await userEvent.click(overlayAction()); await waitFor(() => expect(outcomeText()).not.toBe("")); @@ -381,8 +373,7 @@ describe("moving one contact within its day", () => { expect(toAwstParts((await contactUnderTest(store)).planned.sendAt)).toMatchObject({ hour: 11, minute: 30 }); const afterFirst = await contactUnderTest(store); - await userEvent.clear(timeField()); - await userEvent.type(timeField(), "15:45"); + fireEvent.change(timeField(), { target: { value: "15:45" } }); await openOverlay(); const beforeSecond = requested.length; await userEvent.click(overlayAction()); @@ -704,8 +695,8 @@ describe("a time this service may not send at", () => { act(() => window.history.back()); await waitFor(() => expect(openOverlayId()).toBeNull()); - await userEvent.clear(timeField()); - await userEvent.type(timeField(), "18:00"); + // A time control emits one completed browser change; typing partial values makes jsdom sanitise it to "". + fireEvent.change(timeField(), { target: { value: "18:00" } }); await openOverlay(); expect(openOverlayId()).toBe("outside-window-warning"); });