Nightingale is a synthetic-data prototype for a clinic-scoped longitudinal care-note collaboration product. The repository is at Phase 9 / final release candidate: Gate A-C authentication, clinic-scoped RBAC, immutable revisions, audit metadata, optimistic concurrency, Glance/timeline/source navigation, bilingual UI chrome, safe one-click demo startup, mentions, internal assignments, and metadata-only near-real-time invalidation are implemented locally.
The product path is designed around a simple review workflow: make the next step visible, keep the
original record easy to verify, and preserve human review for every suggestion. The hosted Render
evaluation uses synthetic data, managed PostgreSQL 18, fixture AI, and a pre-recorded Voice example
with a prepared timestamped transcript. It is an evaluation prototype, not a clinical production
guarantee. Technical provider, redaction, performance, and deployment boundaries are documented
below and in the Technical Brief. Judge entry points are collected in JUDGE_ACCESS.md,
and the final recording artifact is kept outside GitHub and included only in the submission bundle.
The repository-root requirements.txt is the candidate brief,
not a pip requirements file; never run pip install -r requirements.txt.
All backend commands use the already verified Conda environment:
$pyExe = 'C:\Users\JI YANCHEN\Desktop\ai_trading_playground\ai_env\python.exe'
& $pyExe --version
& $pyExe -m pip checkThe prototype deliberately runs on Python 3.10.20 in that shared environment. This is a documented prototype limitation, not a production recommendation; production migration to Python 3.12+ is a follow-up. The shared environment is not upgraded or replaced during this sprint.
SQLite is used for local development/tests. The hosted Render evaluation uses PostgreSQL through
DATABASE_URL; local development can still use SQLite. Copy .env.example to a local .env, set
a random SESSION_SECRET of at least 32 characters, and set DEMO_SEED_PASSWORD only when
running the synthetic seed. .env is ignored by Git.
Install the lockfile-pinned dependencies and apply the real Alembic schema:
$pyExe = 'C:\Users\JI YANCHEN\Desktop\ai_trading_playground\ai_env\python.exe'
$uvExe = 'C:\Users\JI YANCHEN\.local\bin\uv.exe'
$env:UV_CACHE_DIR = Join-Path $PWD '.uv-cache'
& $uvExe pip install --python $pyExe --requirement backend\requirements.lock
Push-Location backend
& $pyExe -m alembic upgrade head
& $pyExe -m uvicorn app.main:app --reload --port 8000
Pop-LocationFor a local synthetic demo, use a local-only password and run the idempotent seed. The seed refuses to run unless the database is at the current Alembic head and prints opaque IDs/counts, not note text or credentials:
$pyExe = 'C:\Users\JI YANCHEN\Desktop\ai_trading_playground\ai_env\python.exe'
$env:DEMO_SEED_PASSWORD = 'set-a-local-only-password'
Push-Location backend
& $pyExe -m alembic upgrade head
& $pyExe -m app.scripts.seed_demo
Pop-Location
Remove-Item Env:DEMO_SEED_PASSWORDThe seed creates two synthetic clinics, five users, two synthetic patients, ten entries, three distinct system AI-scribed entry types, six source-linked highlights/materialized Glance rows, two source-anchored penicillin assertions with one protected conflict, a threaded internal comment fixture, a bounded wrong-dosage publication draft, and a derived archival summary with immutable source pointers. Re-running it preserves aggregate counts. Mentions and tasks are created through the clinic-scoped collaboration APIs so the seed remains deterministic and read-only by default.
Round 4 adds a local, synthetic, portal-only publication workflow. Accept on an internal AI
highlight never publishes to a patient. Staff can prepare/edit a draft; only a Clinician can
approve and then explicitly publish it. The bounded metformin dosage evidence check is
source/version anchored and fails closed on mismatch, ambiguity, or unsupported grammar.
Recall and correction are separate versioned transitions, while the Patient projection exposes
only current published content or safe notices. See
PATIENT_PUBLICATION_BOUNDARY.md, the
Round 4 design, and the
Round 4 evidence.
Round 5 adds no clinical feature. It reconciles the Round 1–4 slices, verifies fresh and legacy
SQLite migration paths through 0014_patient_publications, prepares the PostgreSQL 18 gate at
real-clinic-postgres.yml, and records the route/
privacy boundary. Real PostgreSQL execution was pending at the Round 5 checkpoint; Round 6 later
verified the prepared workflow against PostgreSQL 18. Offline SQL remains non-execution evidence.
See the
Round 5 integration audit,
demo runbook, and
iteration brief.
Round 6 pushed only codex/real-clinic-safety and ran the prepared PostgreSQL 18 workflow at the
exact code checkpoint 2af8073. The gate passed fresh/legacy migration checks, PostgreSQL
schema/FK assertions, idempotent synthetic seed, the backend regression suite, Ruff, mypy, and
pip check. One bounded repair corrected the mypy ignore code for the optional faster_whisper
import; no migrations, dependencies, or product behavior changed. The final evidence commit
eeff4cf passed exact-SHA run 33592639722, and real-clinic-rc2 points to it. The evidence is
in Round 6 external gate; any Render update is a separate
Round 7 action.
The current local iteration adds Alembic 0012_glance_impressions, a shared provider-free Glance
candidate builder, metadata-only exposure impressions, and a protected dual-source allergy
conflict review drawer. Staff can inspect both sources but cannot adjudicate; clinicians use a
versioned decision with database CAS; patients receive none of the conflict, assertion, or
impression data. Exposure records contain candidate/surface metadata only and are an observable
denominator for later evaluation; they do not claim IPS, counterfactual correction, or unbiased
self-learning. The local evidence is recorded in
round2_conflict_ui_exposure.md and
round2_warm_path.md. This iteration remains local-only:
it does not push, deploy, call DeepSeek, or change Voice.
The current local resilience slice adds Alembic 0013_ai_provider_resilience, a persistent
clinic/provider circuit with closed, open, and half_open states, and a bounded DeepSeek
adapter budget of 8 seconds per attempt, 12 seconds total, and 2 attempts. Provider failures are
never silently replaced by fixture output. Internal users can query the clinic-scoped provider
status; the AI panel exposes available/degraded/temporarily unavailable states while preserving
existing Glance, timeline, tasks, comments, and source navigation. The application logger accepts
only allowlisted metadata, unexpected exceptions return a generic response, and the explicit local
log audit command is:
Push-Location backend
& $pyExe -m app.scripts.audit_phi_logs path\to\local.log --known-name "Synthetic Patient"
Pop-LocationRound 3 remains local-only and synthetic. It does not provide a durable queue, automatic replay, third-party retention evidence, live provider calls, PostgreSQL production evidence, or clinical SLA.
POST /auth/login,GET /auth/me, andPOST /auth/logoutuse an HttpOnly signed cookie.GET /patientsandGET /patients/{patient_id}/timelineare clinic/link scoped; patient projections omit internal entries, comments, raw AI notes, conflicts, and revision history.GET /patients/{patient_id}/glancereturns at most six deterministic active highlights and excludes rejected/superseded items. It reads only thepatient_glance_itemsmaterialized projection; it does not call a provider.GET /highlights/{highlight_id}/sourceresolves the immutable entry version, exact quote, Python Unicode-codepoint offsets, and source reference.- Clinicians can create manual highlights and review suggestions; staff can read/comment but cannot accept/reject; admins are read-only; patients cannot access internal highlights.
GET/POST /entries/{entry_id}/commentssupports same-entry threaded replies andPATCH /comments/{comment_id}/resolutionsupports resolve/unresolve.- Existing Gate A routes provide role-owned edits, immutable version history, diff, revert-as-new-
version, and deterministic
409stale-write conflicts. POST /patients/{patient_id}/ai-processingaccepts the three AI-scribed entry types through a typed redacted payload. The deterministic fixture remains the default; an explicitly configured optional DeepSeek V4 Flash adapter uses only redacted synthetic text and never overwrites a human entry. Provider failures stay failures and do not silently fall back to fixture.GET /ai-processing/providerexposes only safe provider name/model/configured metadata to authorized staff/clinicians; it never returns a key, key-file path, or base URL.GET /patients/{patient_id}/ai-processing/provider-statusexposes clinic-scoped availability, circuit state, bounded retry-after, and whether new suggestions are available to internal users. It never contacts the provider or exposes keys, URLs, response bodies, or account data.GET /ai-processing/{job_id}exposes job metadata and safe error codes, not raw input, provider prompts, or provider responses.POST /highlights/{highlight_id}/feedbackrecords clinic-scoped staff/clinician feedback with an idempotency key. Feedback updates a bounded adaptive ranking contribution and the materialized Glance projection; it never mutates explicit risk or provenance.GET /patients/{patient_id}/contextreturns hot full-detail entries, warm metadata indexes, and derived archival periods.POST /patients/{patient_id}/context/refreshrebuilds only the derivative summaries for staff/clinicians; canonical entries and immutable versions are never deleted or rewritten.- Cold summaries carry a policy version, manifest hash, source entry/version pointers, and an explicit “Derived summary · not the original record” disclosure. Each source row also shows authorized entry type, occurred time, and immutable version. Open actions, explicit risk, active conflicts, unresolved discussion, pinned/accepted highlights, and clinician-confirmed care-plan entries remain protected from compression.
GET /patients/{patient_id}/mentionable-usersreturns only active staff/clinician collaborators in the current clinic. Comment creation accepts stablementioned_user_ids; it never guesses identities by scanning comment text.GET/POST /patients/{patient_id}/tasksandPATCH /tasks/{task_id}provide clinic-scoped assignments with source entry/comment pointers, assignee validation, status transitions, and deterministic stale-version409conflicts. Patient task access is denied server-side.GET /patients/{patient_id}/eventsis a persisted metadata-only SSE invalidation stream with cookie authentication, patient scope, heartbeat, reconnect throughLast-Event-ID, and no raw note/comment/title/quote payload. The browser refetches canonical APIs after an event.
The frontend uses real cookie login and /auth/me, a clinic-scoped patient list, a calm light
clinical workspace, Top Card, timeline, source click-to-focus/scroll, immutable Unicode
codepoint highlighting, comments, version history, diff/revert, conflict comparison, AI review
badges, role-aware controls, an internal AI Scribe Demo panel, a collapsed Why ranked?
explanation with pin/unpin feedback,
English/简体中文 application-chrome localization, a read-only bilingual Learning Guide, keyboard
mention autocomplete, contextual assignment/task drawers, fixed-viewport Desktop/Mobile demo
preview, and a reconnecting live-update indicator. Clinical
note content, comments, quotes, revisions and user-entered source data remain in their original
language; the UI never calls a translation API.
There is no UI-only role switch.
Double-click Start Nightingale Demo.cmd for English or 启动 Nightingale 中文演示.cmd for
Chinese UI chrome. The launcher discovers the existing local Python/pnpm/Node tools, runs
lockfile checks, alembic upgrade head, first-run synthetic seed, backend/frontend health checks,
and opens the browser only after both services are ready. It records only verified child PIDs and
logs under ignored artifacts/local-runtime/; Stop Nightingale Demo.cmd verifies the PID and
executable/health boundary before stopping them. Unknown port owners are never killed.
Manual setup commands remain supported. Configure DeepSeek.cmd stores only an external key-file
path in ignored .nightingale-local.json; Use Local Fixture.cmd restores the no-network default.
Clinical source text is deliberately not translated.
The optional DeepSeek adapter uses deepseek-v4-flash through the official
https://api.deepseek.com/chat/completions endpoint. It receives only validated redacted synthetic
text and returns schema-checked summary/action fields; local code computes immutable codepoint
offsets and sets risk/provenance/review state. A provider failure is recorded as a safe error and
never silently becomes fixture output. The bounded live smoke is recorded in
deepseek_live_smoke.md; it is not a model-quality
evaluation or production compliance claim.
The Phase 7.1/8 delivery set includes the editable and rendered Technical Brief, attribution audit,
demo script/shot list, UX timing protocol, deployment checklist, launcher smoke evidence, and
synthetic browser screenshots. Phase 9 adds a Docker/Render production-readiness path and a
bounded prerecorded Voice fixture. Render enables only VOICE_PROVIDER=fixture and keeps
LLM_PROVIDER=fixture; the Docker image still does not install Voice dependencies or model
weights.
The original final recording is a local submission artifact; it is not tracked or uploaded to
GitHub. Its content QA remains a separate human-review gate.
For judge entry points, use JUDGE_ACCESS.md. The final recording filename is
新标签页 - Google Chrome 2026-08-28 11-37-05.mp4; it is included only in the final submission ZIP,
not in the GitHub repository. The editable brief is docs/TECHNICAL_BRIEF.md,
and the rendered brief is deliverables/Nightingale_Technical_Brief.pdf.
The final candidate-brief audit is docs/FINAL_REQUIREMENTS_AUDIT.md.
The demo password is supplied separately in the submission email.
The Voice section is intentionally not continuous ambient capture. It plays two small, prerecorded synthetic WAV fixtures, displays prepared timestamped transcript segments, and labels confidence as unavailable. The achieved status is: “Bounded prerecorded synthetic audio with prepared transcript and segment provenance; no ASR inference, diarization, or microphone capture.”
The earlier Round 9 RC5 release reproduced and fixed the Uvicorn access-log formatter regression
with the real AccessFormatter. The Round 9 closure then repaired protected-item starvation,
passed the exact PostgreSQL 18 and deploy-candidate gates, and updated the existing Render
service. Main and Render now run 4f4fc84c3451152e63135bd7fdd7b851bb43a1ea; the deployment,
protected-first Staff canary, anonymous checks, logging observation, and 15/15 sustained watch are recorded in
round9_render_live.md. Auto-Deploy remains disabled for
controlled release, and no new Render resource was created.
The current Round 9 release record is intentionally partial: the authenticated hosted benchmark
is pending because no safe browser request/performance surface was available without extracting
cookies or tokens. The exact-commit closure did not repeat the Patient/Clinician/SSE canaries, so
real-clinic-live1 was not created. No production data cleanup was performed. See
round9_hosted_performance.md.
The closure evidence is consolidated in round9_closure.md.
Submission decision: SUBMISSION READY WITH DISCLOSED SUPPLEMENTARY BENCHMARK GAP. The hosted authenticated benchmark remains pending as a disclosed engineering limitation; it is not a requested deliverable and does not block final Demo Video preparation or submission.
The local iteration artifact is deliverables/iteration/Nightingale_Real_Clinic_Iteration_Demo.webm,
generated from disposable synthetic data with visible English captions and intentionally kept out
of GitHub. Its rehearsal/media QA is in round9_demo_qa.md. The
original user-supplied MP4 remains local and is not tracked or uploaded.
The current recording source of truth is REAL_CLINIC_DEMO_RECORDING_MASTER_ZH_EN.md.
It combines Chinese operator actions, English narration, cue times, and matching English subtitle
text. Use REAL_CLINIC_DEMO_STATE_PREP_ZH.md before
recording, then import REAL_CLINIC_DEMO_SUBTITLES_EN.srt.
Scenario mapping is in REAL_CLINIC_DEMO_REQUIREMENT_TRACEABILITY.md,
and post-recording review belongs in REAL_CLINIC_DEMO_VIDEO_QA.md.
The pre-shoot Staff observations are recorded in
real_clinic_final_demo_rehearsal.md.
The hosted authenticated benchmark remains a disclosed supplementary gap and is not a blocker for this recording phase. No product code, runtime, or requirements text is changed by the demo materials.
The adaptive ranking path uses a closed structured feature signature derived from entry type, item kind, source kind, action state, explicit risk, and a normalized topic category. It does not use embeddings, external LLM calls, patient identifiers, names, quotes, or raw free text.
final display priority = clamp(
base priority + recency + explicit risk + unresolved action
+ clinician confirmation + bounded adaptive feedback,
0, 100
)
Adaptive feedback is bounded to [-12, +12], is clinic-scoped and idempotent, and is kept
separate from medical risk, source provenance, and clinician truth. Glance reads remain provider-
free and consume only the materialized projection. The UI labels this as “Ranking priority, not a
medical risk score”.
Backend:
$pyExe = 'C:\Users\JI YANCHEN\Desktop\ai_trading_playground\ai_env\python.exe'
Push-Location backend
& $pyExe -m ruff check --no-cache app tests migrations
& $pyExe -m ruff format --check --no-cache app tests
& $pyExe -m mypy app tests
& $pyExe -m pytest
Pop-LocationAt the Round 9 closure checkpoint, the backend suite reports 194 passed. The global
pytest --cov=app measurement is 86.62%; the current CI and local commands enforce the
85% threshold. Standalone benchmark/seed/probe scripts remain covered by the same application
target, and no coverage setting was changed to conceal misses.
The repository contains the required real-application tests test_rbac_scope.py,
test_revision_history.py, test_highlight_provenance.py, and test_concurrent_edits.py, plus
test_redaction.py, test_ai_provider_boundary.py, test_ai_processing.py, and
test_materialized_glance.py, test_self_learning_importance.py, test_data_decay.py, and
test_voice.py, and test_uvicorn_access_logging.py. They use HTTPX AsyncClient with
ASGITransport; no old
TestClient/httpx warning is hidden. Migration tests use Alembic to create the database and
prove that seed does not call Base.metadata.create_all().
Frontend unit/build checks:
$pnpmCmd = 'C:\Users\JI YANCHEN\AppData\Roaming\npm\pnpm.cmd'
Push-Location frontend
& $pnpmCmd install --frozen-lockfile
& $pnpmCmd lint
& $pnpmCmd test
& $pnpmCmd type-check
& $pnpmCmd build
Pop-LocationReal browser checks:
Push-Location frontend
& $pnpmCmd e2e
& $pnpmCmd e2e:voice
Pop-Locationpnpm e2e creates a temporary Alembic-migrated SQLite database, seeds synthetic data, starts
real Uvicorn and Vite processes on clean local ports, and runs the core checks at 1440x900 and
390x844. pnpm e2e:voice runs four isolated Voice fixture checks and
pnpm e2e:publication runs two publication-gate checks at the same viewports. The Round 9 run
therefore reports 18 core, 4 Voice, and 2 publication browser checks. Scenario B
covers revisions, nested comments, keyboard mention selection, contextual assignment drawer
creation/completion, and a second browser receiving the metadata-only SSE invalidation. The
dedicated preview check verifies real internal 1440x900/390x844 iframe viewports, query
preservation, no recursive toolbar, and Escape close. The custom setup records only its own server
PIDs and teardown removes those processes, the temporary database, generated password, and
ignored artifacts/gate-b/ screenshots.
Gate C warm-path benchmark:
Push-Location backend
& $pyExe -m app.scripts.benchmark_warm_path
Pop-LocationThis uses a fresh migrated file-backed SQLite database, 26 synthetic patients, 208 benchmark
entries/highlights, real Uvicorn TCP HTTP, 50 warm-up requests, 1,000 measured requests, and
10-way concurrency. The 2026-08-28 release-candidate run reports P50 44.283 ms, P95
56.053 ms, P99 81.509 ms, max 89.495 ms, and zero errors. The current evidence is
gate_c_warm_path.md. It is a local approximation, not a
hosted PostgreSQL production benchmark.
- Only synthetic data is allowed. Do not add real patient data, credentials, API keys, access tokens, or identifying logs.
- The server is canonical for clinic and role authorization. Production requires secure cookies; credentialed browser writes are protected by the configured Origin allowlist.
- AI output is a suggestion. It cannot silently overwrite a human source or present an unsupported diagnosis as fact. Display priority, explicit risk, and clinician confirmation are separate fields.
- No external LLM key is committed or required. The optional DeepSeek path is explicitly selected, redaction-gated, and cost/network dependent; the fixture path remains deterministic by default. The Render synthetic evaluation uses managed PostgreSQL, HTTPS/TLS, and the bounded prerecorded Voice fixture; these are evaluation evidence, not clinical compliance evidence. The original final video is not uploaded to GitHub, and the test password is supplied separately in the submission email. The local Technical Brief PDF is delivery evidence, not hosted compliance evidence.
- Voice is prerecorded synthetic audio with a prepared transcript fixture. There is no microphone capture, local Whisper success claim, diarization, or production PHI audio path.
- The local redaction/provider boundary and materialized warm path/P95 are implemented and evidenced, but do not establish hosted production guarantees.