tranth3truong commited on
Commit
cc678b9
·
0 Parent(s):

Deploy public Scribe-only CarePath Space

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .dockerignore +33 -0
  2. .env.ckey.example +35 -0
  3. .env.example +75 -0
  4. .env.local.example +31 -0
  5. .gitattributes +2 -0
  6. .github/workflows/ci.yml +147 -0
  7. .github/workflows/keepalive.yml +17 -0
  8. .gitignore +40 -0
  9. AGENTS.md +335 -0
  10. CLAUDE.md +6 -0
  11. Dockerfile +53 -0
  12. README.hf-space.md +21 -0
  13. README.md +21 -0
  14. UI-FIX-PLAN.md +154 -0
  15. data/medical_lexicon.json +215 -0
  16. docs/ARCHITECTURE.md +40 -0
  17. docs/CONTEXT_RULES.md +19 -0
  18. docs/FEATURE_INTAKE.md +51 -0
  19. docs/GLOSSARY.md +144 -0
  20. docs/HARNESS.md +65 -0
  21. docs/HARNESS_AUDIT.md +38 -0
  22. docs/HARNESS_BACKLOG.md +62 -0
  23. docs/HARNESS_COMPONENTS.md +167 -0
  24. docs/HARNESS_MATURITY.md +316 -0
  25. docs/IMPROVEMENT_PROTOCOL.md +57 -0
  26. docs/README.md +40 -0
  27. docs/TEST_MATRIX.md +17 -0
  28. docs/TOOL_REGISTRY.md +195 -0
  29. docs/TRACE_SPEC.md +204 -0
  30. docs/decisions/0001-harness-first-development.md +48 -0
  31. docs/decisions/0002-post-spec-product-lifecycle.md +54 -0
  32. docs/decisions/0003-generic-spec-intake-harness.md +58 -0
  33. docs/decisions/0004-sqlite-durable-layer.md +75 -0
  34. docs/decisions/0005-prebuilt-rust-harness-cli.md +91 -0
  35. docs/decisions/0006-phase-4-benchmark-triage.md +54 -0
  36. docs/decisions/0007-improvement-proposal-rules.md +60 -0
  37. docs/decisions/0008-carepath-harness-adoption.md +44 -0
  38. docs/decisions/0009-restructure-target-layout.md +56 -0
  39. docs/decisions/0010-shared-normalization-contract.md +31 -0
  40. docs/decisions/0011-canonical-medical-term-source.md +30 -0
  41. docs/decisions/0012-interpreter-runtime-hardening.md +29 -0
  42. docs/decisions/0013-gec-training-data-governance.md +30 -0
  43. docs/decisions/0014-gec-safety-weighted-regression-gate.md +31 -0
  44. docs/decisions/0015-soap-note-measurement-gate.md +31 -0
  45. docs/decisions/0016-scribe-training-ownership.md +35 -0
  46. docs/decisions/README.md +28 -0
  47. docs/deploy.md +150 -0
  48. docs/history/DEMO-SITE-PLAN.md +146 -0
  49. docs/history/JUDGE.md +99 -0
  50. docs/history/MERGE-PLAN.md +279 -0
.dockerignore ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .agents/
2
+ .claude/
3
+ .codex/
4
+ .git/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ .mypy_cache/
8
+ .venv/
9
+ .venv_labeling/
10
+ __pycache__/
11
+ *.py[cod]
12
+ *.egg-info/
13
+ .env
14
+ .env.*
15
+ **/node_modules
16
+ **/dist
17
+ **/coverage
18
+ **/playwright-report
19
+ **/test-results
20
+ **/*.db
21
+ artifacts/
22
+ data/labeling/
23
+ models/
24
+ tmp/
25
+ *.wav
26
+ *.mp3
27
+ *.m4a
28
+ *.aac
29
+ *.flac
30
+ *.ogg
31
+ *.oga
32
+ *.opus
33
+ *.webm
.env.ckey.example ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath CKey runtime
2
+ APP_ENV=local
3
+ ASR_PROVIDER=gipformer
4
+ ALLOW_MOCK_ASR=false
5
+
6
+ # CKey uses the OpenAI-compatible chat/completions route.
7
+ # Get the key from the CKey AI API Console and keep .env out of source control.
8
+ LLM_PROVIDER=ckey
9
+ LLM_BASE_URL=https://api.xah.io/v1
10
+ LLM_MODEL=gpt-5.4
11
+ LLM_API_KEY=sk-YOUR_API_KEY
12
+ LLM_TIMEOUT_SECONDS=120
13
+ # Demo safety net: if CKey fails/times out, serve the deterministic offline
14
+ # generator instead of returning an error. Set to false to fail hard.
15
+ LLM_FALLBACK_OFFLINE=true
16
+
17
+ # Retrieval
18
+ MEDICAL_LEXICON_PATH=data/medical_lexicon.json
19
+ RETRIEVAL_TOP_K=5
20
+
21
+ # Gipformer ASR
22
+ GIPFORMER_QUANTIZE=int8
23
+ GIPFORMER_NUM_THREADS=4
24
+ GIPFORMER_DECODING_METHOD=modified_beam_search
25
+ GIPFORMER_CHUNK_SECONDS=20
26
+
27
+ # Abuse guard
28
+ TEAM_CODE=
29
+ SOAP_RATE_LIMIT_PER_IP_HOUR=3
30
+ SOAP_RATE_LIMIT_PER_IP_DAY=10
31
+ SOAP_RATE_LIMIT_GLOBAL_DAY=100
32
+
33
+ # --- Interpreter module (mock until its cloud track lands) ---
34
+ PROVIDER_MODE=mock
35
+ DATABASE_URL=sqlite:///./carepath.db
.env.example ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath unified runtime — one FastAPI service, two products.
2
+ # Defaults below are the keyless demo profile: the whole app must boot with no
3
+ # API keys (mock interpreter providers, mock ASR + offline LLM for the scriber).
4
+ # Ready-made profiles: .env.local.example (keyless demo), .env.ckey.example
5
+ # (real Gipformer ASR + CKey LLM).
6
+
7
+ # --- Scriber (scribe/carepath, routes /api/v1/*) ---
8
+ APP_ENV=local
9
+ ASR_PROVIDER=gipformer
10
+ GIPFORMER_QUANTIZE=int8
11
+ GIPFORMER_NUM_THREADS=4
12
+ GIPFORMER_DECODING_METHOD=modified_beam_search
13
+ GIPFORMER_CHUNK_SECONDS=20
14
+ # Long-audio segmentation: overlap (default) | vad | fixed.
15
+ # overlap = overlapping windows merged with seam de-duplication (no word loss
16
+ # at chunk boundaries; no extra model).
17
+ # vad = split on silence; requires GIPFORMER_VAD_MODEL (repo_id:filename or
18
+ # a local silero_vad.onnx path). Falls back to overlap if unavailable.
19
+ # fixed = legacy non-overlapping 20s windows.
20
+ GIPFORMER_SEGMENTATION=overlap
21
+ GIPFORMER_OVERLAP_SECONDS=2
22
+ GIPFORMER_MAX_SEGMENT_SECONDS=20
23
+ GIPFORMER_VAD_MODEL=
24
+
25
+ # Set LLM_PROVIDER=offline for a deterministic no-key fallback.
26
+ # Set LLM_PROVIDER=ckey for CKey OpenAI-compatible chat completions.
27
+ LLM_PROVIDER=offline
28
+ LLM_BASE_URL=https://api.openai.com/v1
29
+ LLM_MODEL=gpt-4.1-mini
30
+ LLM_API_KEY=
31
+ LLM_TIMEOUT_SECONDS=60
32
+ # If a network LLM provider fails, fall back to the offline generator so a
33
+ # request never errors out (recommended for live demos).
34
+ LLM_FALLBACK_OFFLINE=true
35
+
36
+ # Retrieval
37
+ MEDICAL_LEXICON_PATH=data/medical_lexicon.json
38
+ RETRIEVAL_TOP_K=5
39
+ # Backend: lexical (default) | semantic | hybrid. semantic/hybrid use the
40
+ # Vietnamese bi-encoder and need the optional sentence-transformers + pyvi deps.
41
+ RETRIEVAL_BACKEND=lexical
42
+ SEMANTIC_MODEL_NAME=bkai-foundation-models/vietnamese-bi-encoder
43
+
44
+ # Safety/demo
45
+ ALLOW_MOCK_ASR=false
46
+ TEAM_CODE=
47
+ SOAP_RATE_LIMIT_PER_IP_HOUR=3
48
+ SOAP_RATE_LIMIT_PER_IP_DAY=10
49
+ SOAP_RATE_LIMIT_GLOBAL_DAY=100
50
+ # Cross-origin frontends for both APIs. Clear this value for same-origin-only
51
+ # production; list every Vite development origin when developing against either API.
52
+ CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
53
+
54
+ # Public Vercel site used by the Interpreter's “Tất cả chức năng” link when
55
+ # its frontend is built into the Space image. Set as a Docker build arg.
56
+ VITE_PUBLIC_SITE_URL=https://carepath-omega.vercel.app
57
+
58
+ # --- Interpreter (interpreter/app, routes /api/* + /ws/*) ---
59
+ # PROVIDER_MODE=mock runs deterministic providers with zero keys (the demo
60
+ # profile). PROVIDER_MODE=cloud is a later track: it needs the two API keys
61
+ # below and a non-default ADMIN_TOKEN (startup refuses "change-me").
62
+ PROVIDER_MODE=mock
63
+ ANTHROPIC_API_KEY=
64
+ OPENAI_API_KEY=
65
+ ADMIN_TOKEN=change-me
66
+ CONFIDENCE_THRESHOLD=0.7
67
+ RETENTION_DAYS=30
68
+ MAX_TURN_AUDIO_BYTES=10485760
69
+ # sqlite is fine for the demo (ephemeral on HF Spaces); point at Postgres etc.
70
+ # for anything that must survive a container restart.
71
+ DATABASE_URL=sqlite:///./carepath.db
72
+ OPENAI_TRANSCRIBE_MODEL=gpt-4o-transcribe
73
+ CLAUDE_MT_MODEL=claude-sonnet-5
74
+ CLAUDE_REVIEWER_MODEL=claude-sonnet-5
75
+ PROVIDER_TIMEOUT_SECONDS=30
.env.local.example ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath local smoke/demo runtime
2
+ APP_ENV=local
3
+ ASR_PROVIDER=mock
4
+ ALLOW_MOCK_ASR=true
5
+
6
+ # Offline correction/SOAP fallback for local API contract testing.
7
+ LLM_PROVIDER=offline
8
+ LLM_BASE_URL=https://api.openai.com/v1
9
+ LLM_MODEL=gpt-4.1-mini
10
+ LLM_API_KEY=
11
+ LLM_TIMEOUT_SECONDS=60
12
+
13
+ # Retrieval
14
+ MEDICAL_LEXICON_PATH=data/medical_lexicon.json
15
+ RETRIEVAL_TOP_K=5
16
+
17
+ # Gipformer settings are ignored while ASR_PROVIDER=mock.
18
+ GIPFORMER_QUANTIZE=int8
19
+ GIPFORMER_NUM_THREADS=4
20
+ GIPFORMER_DECODING_METHOD=modified_beam_search
21
+ GIPFORMER_CHUNK_SECONDS=20
22
+
23
+ # Abuse guard
24
+ TEAM_CODE=
25
+ SOAP_RATE_LIMIT_PER_IP_HOUR=3
26
+ SOAP_RATE_LIMIT_PER_IP_DAY=10
27
+ SOAP_RATE_LIMIT_GLOBAL_DAY=100
28
+
29
+ # --- Interpreter module (mock providers, zero keys) ---
30
+ PROVIDER_MODE=mock
31
+ DATABASE_URL=sqlite:///./carepath.db
.gitattributes ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Playwright snapshots are byte-compared; never convert their line endings.
2
+ site/tests/**/*-snapshots/** -text
.github/workflows/ci.yml ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ unified-api:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-python@v5
13
+ with:
14
+ python-version: "3.12"
15
+ - name: Install shared and API packages
16
+ run: python -m pip install -e ".[dev]" -e "./shared" -e "./interpreter[dev]"
17
+ - name: Scriber and combined-app tests
18
+ run: pytest
19
+ - name: Shared normalization characterization
20
+ run: python -m pytest shared/tests
21
+ - name: Regenerate term artifacts without drift
22
+ run: python scripts/build_term_artifacts.py && git diff --exit-code -- data/medical_lexicon.json interpreter/app/glossary/data/seed_glossary.csv
23
+ - name: Enforce serving/training import boundary
24
+ run: if rg -l 'from gec|import gec' scribe/carepath/; then exit 1; fi
25
+ - name: Scriber smoke test (mock ASR + offline LLM)
26
+ run: python scripts/smoke_backend.py
27
+
28
+ training-governance:
29
+ runs-on: ubuntu-latest
30
+ steps:
31
+ - uses: actions/checkout@v4
32
+ - uses: actions/setup-python@v5
33
+ with:
34
+ python-version: "3.12"
35
+ - name: Install CPU-only training proof dependencies
36
+ run: python -m pip install -e ".[dev]" -e "./shared"
37
+ - name: Test training governance and export smoke
38
+ run: python -m pytest scribe/training/tests
39
+ - name: Verify the committed frozen baseline report
40
+ run: python scribe/training/scripts/baseline_report.py
41
+
42
+ interpreter:
43
+ runs-on: ubuntu-latest
44
+ steps:
45
+ - uses: actions/checkout@v4
46
+ - uses: actions/setup-python@v5
47
+ with:
48
+ python-version: "3.12"
49
+ - name: Install shared and interpreter
50
+ run: python -m pip install -e "./shared" -e "./interpreter[dev]"
51
+ - name: Lint interpreter
52
+ working-directory: interpreter
53
+ run: ruff check .
54
+ - name: Test interpreter
55
+ working-directory: interpreter
56
+ run: pytest
57
+ - name: Eval regression
58
+ run: python interpreter/eval/run_eval.py --set interpreter/eval/fixtures/eval_starter.tsv --providers mock
59
+
60
+ frontend:
61
+ runs-on: ubuntu-latest
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+ - uses: actions/setup-node@v4
65
+ with:
66
+ node-version: "22"
67
+ cache: npm
68
+ cache-dependency-path: interpreter/frontend/package-lock.json
69
+ - name: Install frontend
70
+ working-directory: interpreter/frontend
71
+ run: npm ci
72
+ - name: Lint frontend
73
+ working-directory: interpreter/frontend
74
+ run: npm run lint
75
+ - name: Test frontend
76
+ working-directory: interpreter/frontend
77
+ run: npm test
78
+ - name: Build frontend
79
+ working-directory: interpreter/frontend
80
+ run: npm run build
81
+
82
+ e2e:
83
+ runs-on: ubuntu-latest
84
+ needs: [interpreter, frontend]
85
+ env:
86
+ PROVIDER_MODE: mock
87
+ steps:
88
+ - uses: actions/checkout@v4
89
+ - uses: actions/setup-python@v5
90
+ with:
91
+ python-version: "3.12"
92
+ - uses: actions/setup-node@v4
93
+ with:
94
+ node-version: "22"
95
+ cache: npm
96
+ cache-dependency-path: interpreter/frontend/package-lock.json
97
+ - name: Install shared and interpreter
98
+ run: python -m pip install -e "./shared" -e "./interpreter[dev]"
99
+ - name: Install frontend
100
+ working-directory: interpreter/frontend
101
+ run: npm ci
102
+ - name: Install Playwright browser
103
+ working-directory: interpreter/frontend
104
+ run: npx playwright install --with-deps chromium
105
+ - name: Run Playwright e2e
106
+ working-directory: interpreter/frontend
107
+ run: npx playwright test
108
+
109
+ site:
110
+ runs-on: ubuntu-latest
111
+ steps:
112
+ - uses: actions/checkout@v4
113
+ - uses: actions/setup-node@v4
114
+ with:
115
+ node-version: "22"
116
+ cache: npm
117
+ cache-dependency-path: scribe/frontend/package-lock.json
118
+ - name: Install demo site
119
+ working-directory: scribe/frontend
120
+ run: npm ci
121
+ - name: Lint demo site
122
+ working-directory: scribe/frontend
123
+ run: npm run lint
124
+ - name: Test demo site
125
+ working-directory: scribe/frontend
126
+ run: npm test
127
+ - name: Test Vercel environment validation
128
+ working-directory: scribe/frontend
129
+ run: npm run test:deploy-env
130
+ - name: Build demo site
131
+ working-directory: scribe/frontend
132
+ run: npm run build
133
+ - name: Install Playwright browser
134
+ working-directory: scribe/frontend
135
+ run: npx playwright install --with-deps chromium
136
+ - name: Run demo site e2e
137
+ working-directory: scribe/frontend
138
+ run: npm run e2e
139
+ - name: Rebuild production demo site
140
+ working-directory: scribe/frontend
141
+ run: npm run build
142
+ - name: Audit demo site
143
+ working-directory: scribe/frontend
144
+ run: npm audit
145
+ - name: Run Lighthouse gates
146
+ working-directory: scribe/frontend
147
+ run: npm run lighthouse
.github/workflows/keepalive.yml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Keep HF Space Awake
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 */12 * * *"
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ ping:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Ping health endpoint
13
+ env:
14
+ SPACE_URL: ${{ vars.SPACE_URL }}
15
+ run: |
16
+ test -n "$SPACE_URL"
17
+ curl -fsS "${SPACE_URL%/}/api/v1/health"
.gitignore ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .env
2
+ .venv/
3
+ __pycache__/
4
+ *.py[cod]
5
+ *.egg-info/
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ .mypy_cache/
9
+ artifacts/
10
+ models/
11
+ tmp/
12
+ *.wav
13
+ *.mp3
14
+ *.m4a
15
+ *.aac
16
+ *.flac
17
+ *.ogg
18
+ *.oga
19
+ *.opus
20
+ *.webm
21
+
22
+ node_modules/
23
+ dist/
24
+ coverage/
25
+ *.tsbuildinfo
26
+ playwright-report/
27
+ test-results/
28
+ eval/reports/
29
+ interpreter/eval/reports/
30
+
31
+ *.db
32
+ *.sqlite
33
+ *.sqlite3
34
+
35
+ # Harness durable layer
36
+ harness.db
37
+ harness.db-wal
38
+ harness.db-shm
39
+ scripts/bin/harness-cli
40
+ scripts/bin/harness-cli.exe
AGENTS.md ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Agent instructions — CarePath unified
2
+
3
+ CarePath is one unified medical AI product with two clearly separated user-facing modules:
4
+
5
+ 1. **Ghi chép bệnh án AI**
6
+ Internal/technical term: AI Scribe / scriber
7
+ Backend: `scribe/carepath`, `/api/v1/*`
8
+ Purpose: listen to a consultation and help generate structured clinical notes.
9
+
10
+ 2. **Phiên dịch khám bệnh trực tiếp**
11
+ Internal/technical term: Medical Interpreter / interpreter
12
+ Backend: `interpreter/app`, `/api/*` + `/ws/*`
13
+ Purpose: live two-way interpretation between Vietnamese doctors and English-speaking patients.
14
+
15
+ The app is served by one FastAPI process plus two Vite frontends:
16
+
17
+ * `scribe/frontend/` at `/`
18
+ * `interpreter/frontend/` at `/phien-dich-y-khoa/` (`/console/` is a legacy redirect)
19
+
20
+ ## Interpreter status
21
+
22
+ After restructure Phase 7, the Interpreter is on hold. Accept only bug fixes,
23
+ safety fixes, and required operational maintenance there; new product work is
24
+ focused on the Scribe training track unless the owner explicitly reopens it.
25
+
26
+ `docs/history/PLAN.md` and `docs/history/DEMO-SITE-PLAN.md` are historical build
27
+ plans for the interpreter and demo site. `docs/history/MERGE-PLAN.md` is the
28
+ executed unification plan, M.0–M.8 done, and `docs/history/JUDGE.md` is its
29
+ review protocol.
30
+ `docs/research.md` holds the interpreter safety background.
31
+
32
+ ## Product UX contract
33
+
34
+ CarePath must be Vietnamese-first.
35
+
36
+ The target users may include Vietnamese doctors who are not comfortable with English medical software terms. Therefore, the UI must explain workflows by user intent, not by English product names.
37
+
38
+ ### Primary user-facing labels
39
+
40
+ Use these as primary UI labels:
41
+
42
+ * `Ghi chép bệnh án AI`
43
+ * `Phiên dịch khám bệnh trực tiếp`
44
+
45
+ Use these as primary CTAs:
46
+
47
+ * `Bắt đầu ghi chép`
48
+ * `Bắt đầu phiên dịch`
49
+
50
+ Use this homepage framing:
51
+
52
+ ```text
53
+ Bạn muốn hỗ trợ việc gì hôm nay?
54
+ ```
55
+
56
+ ### Secondary/internal labels
57
+
58
+ The following English terms may appear only as secondary helper text, developer labels, comments, docs, or internal route/component names:
59
+
60
+ * Scribe
61
+ * AI Scribe
62
+ * Interpreter
63
+ * Medical Interpreter
64
+ * Console
65
+ * Transcript
66
+ * Encounter
67
+ * Session
68
+
69
+ Do not use `Scribe` or `Interpreter` as primary labels on user-facing screens.
70
+
71
+ ### Required distinction between the two modules
72
+
73
+ The landing page must make it obvious that these are two different workflows:
74
+
75
+ #### Ghi chép bệnh án AI
76
+
77
+ Explain as:
78
+
79
+ ```text
80
+ AI nghe buổi khám và tạo ghi chú y khoa có cấu trúc.
81
+ ```
82
+
83
+ Use when:
84
+
85
+ ```text
86
+ Phù hợp khi bác sĩ muốn giảm thời gian nhập liệu sau khám.
87
+ ```
88
+
89
+ Clarify that the doctor must review the output before use.
90
+
91
+ #### Phiên dịch khám bệnh trực tiếp
92
+
93
+ Explain as:
94
+
95
+ ```text
96
+ Dịch hai chiều giữa bác sĩ tiếng Việt và bệnh nhân tiếng Anh trong lúc khám.
97
+ ```
98
+
99
+ Use when:
100
+
101
+ ```text
102
+ Phù hợp khi bác sĩ và bệnh nhân không cùng ngôn ngữ.
103
+ ```
104
+
105
+ Clarify that the system translates only and must not provide medical advice.
106
+
107
+ ### Every user-facing screen must answer
108
+
109
+ 1. Tôi đang dùng chức năng nào?
110
+ 2. Chức năng này giúp việc gì?
111
+ 3. Tôi cần bấm gì tiếp theo?
112
+ 4. Có rủi ro hoặc giới hạn nào bác sĩ cần biết không?
113
+
114
+ ### Vietnamese copy rules
115
+
116
+ * Vietnamese text must be clear, short, and professional.
117
+ * Preserve Vietnamese diacritics.
118
+ * Keep text NFC-normalized.
119
+ * Avoid unnecessary English.
120
+ * Avoid startup/marketing buzzwords on clinical workflow screens.
121
+ * Prefer concrete action language over abstract product names.
122
+
123
+ Good:
124
+
125
+ ```text
126
+ Ghi chép bệnh án AI
127
+ Phiên dịch khám bệnh trực tiếp
128
+ Bắt đầu ghi chép
129
+ Bắt đầu phiên dịch
130
+ Bác sĩ nói tiếng Việt, bệnh nhân nghe tiếng Anh
131
+ ```
132
+
133
+ Avoid as primary UI:
134
+
135
+ ```text
136
+ Scribe
137
+ Interpreter
138
+ Session
139
+ Encounter
140
+ Transcript
141
+ Start session
142
+ Launch interpreter
143
+ ```
144
+
145
+ ## Non-negotiable safety invariants
146
+
147
+ This file is the current safety contract. `docs/history/PLAN.md §2` preserves
148
+ the original MVP source for historical context.
149
+
150
+ 1. Translate-only: never generate medical advice, diagnoses, or drug recommendations.
151
+ 2. High/critical-risk turns are blocked from patient display and TTS until doctor confirms.
152
+ 3. Low-confidence output is always visibly flagged, never silently delivered.
153
+ 4. Raw audio is never persisted. Use memory-only processing. No audio columns, no temp files.
154
+ 5. No mic capture before recorded consent.
155
+ 6. On any pipeline or reviewer failure, fail closed: keep the turn blocked, show the doctor raw source and translation, offer escalation. Never fail open to the patient.
156
+
157
+ ## Implementation workflow for agents
158
+
159
+ For UX or product-flow changes, do not implement immediately.
160
+
161
+ First produce or update a plan in `docs/ux-redesign-carepath.md` with:
162
+
163
+ 1. Current UX problem
164
+ 2. Proposed flow
165
+ 3. Affected routes/pages/components
166
+ 4. Vietnamese-first copy
167
+ 5. Implementation stories
168
+ 6. Dependencies between stories
169
+ 7. Acceptance criteria
170
+ 8. Validation commands
171
+ 9. Risks and fallback behavior
172
+
173
+ Then implement one story at a time.
174
+
175
+ ### Recommended story order for UX redesign
176
+
177
+ 1. Update Vietnamese-first product naming and copy.
178
+ 2. Redesign the landing page into two clear workflow cards.
179
+ 3. Add or clarify separate entry routes for the two modules.
180
+ 4. Add pre-start onboarding/explanation screens.
181
+ 5. Improve empty/loading/error states in Vietnamese.
182
+ 6. Run QA for mobile, accessibility, safety copy, and route regressions.
183
+
184
+ Do not combine homepage redesign, routing changes, and audio/backend logic changes in one large patch.
185
+
186
+ ### Agent behavior
187
+
188
+ * Keep changes small and focused.
189
+ * Preserve existing working functionality.
190
+ * Do not rewrite backend, audio, risk, or websocket logic unless the current story explicitly requires it.
191
+ * Do not introduce new dependencies without documenting why.
192
+ * Prefer existing components and styling patterns.
193
+ * When changing user-facing Vietnamese text, check diacritics and consistency.
194
+ * When changing risk-engine behavior, update fixtures and evals.
195
+ * When changing product copy only, avoid touching medical logic.
196
+
197
+ ## Commands
198
+
199
+ ### Combined service
200
+
201
+ ```bash
202
+ uvicorn carepath.main:app --app-dir scribe --reload
203
+ ```
204
+
205
+ Requires:
206
+
207
+ ```bash
208
+ pip install -e ".[dev]" -e "./shared" -e "./interpreter[dev]"
209
+ ```
210
+
211
+ ### Scriber and combined tests
212
+
213
+ ```bash
214
+ pytest
215
+ python scripts/smoke_backend.py
216
+ python scripts/build_term_artifacts.py --check
217
+ ```
218
+
219
+ ### Interpreter backend alone
220
+
221
+ ```bash
222
+ cd interpreter && uvicorn app.main:app --reload
223
+ pytest
224
+ ```
225
+
226
+ ### Console
227
+
228
+ ```bash
229
+ cd interpreter/frontend && npm run dev
230
+ npm test
231
+ npx playwright test
232
+ ```
233
+
234
+ ### Demo site
235
+
236
+ ```bash
237
+ cd scribe/frontend && npm run dev
238
+ npm test
239
+ npm run build
240
+ npm run e2e
241
+ ```
242
+
243
+ `npm run build` is also the diacritics gate.
244
+
245
+ ### Full mock-mode run
246
+
247
+ Set this in `.env`:
248
+
249
+ ```bash
250
+ PROVIDER_MODE=mock
251
+ ```
252
+
253
+ Mock mode must work with no API keys.
254
+
255
+ ### Eval regression
256
+
257
+ ```bash
258
+ python interpreter/eval/run_eval.py --set interpreter/eval/fixtures/eval_starter.tsv --providers mock
259
+ ```
260
+
261
+ ## Conventions
262
+
263
+ * Python 3.12.
264
+ * Python code must be ruff-formatted and type-hinted.
265
+ * Use pure functions for normalization and risk rules.
266
+ * TypeScript must be strict.
267
+ * Components should be small.
268
+ * Keep state minimal: context/zustand is allowed, Redux is not.
269
+ * `shared/carepath_shared/terms/medical_terms.json` is the canonical medical
270
+ term source. Regenerate `data/medical_lexicon.json` and
271
+ `interpreter/app/glossary/data/seed_glossary.csv` with
272
+ `python scripts/build_term_artifacts.py`; do not hand-edit generated artifacts.
273
+ * Risk lexicons under `interpreter/app/risk/lexicons/` remain separate
274
+ interpreter safety data. Clinicians edit data, not code.
275
+ * Every risk-engine behavior change updates `interpreter/eval/fixtures/risk_cases.jsonl`.
276
+ * The fixture run is the test.
277
+ * Zero misses on critical fixtures is a hard gate.
278
+ * Secrets only via env.
279
+ * `.env` is gitignored.
280
+ * `.env.example` must stay current.
281
+ * No new dependencies without noting why in the PR.
282
+ * Vietnamese text is data, not decoration: always NFC-normalized, diacritics preserved.
283
+ * Tests must include diacritic-stripped variants where matching allows it.
284
+
285
+ ## Acceptance criteria for UX clarity changes
286
+
287
+ A UX clarity change is not done un less all of the following are true:
288
+
289
+ 1. A Vietnamese doctor can understand the two workflows without knowing the words `Scribe` or `Interpreter`.
290
+ 2. The landing page clearly separates:
291
+
292
+ * `Ghi chép bệnh án AI`
293
+ * `Phiên dịch khám bệnh trực tiếp`
294
+ 3. Each workflow has a distinct CTA.
295
+ 4. Each workflow explains when to use it.
296
+ 5. English terms appear only as secondary helper text, not primary labels.
297
+ 6. Mobile layout remains clear.
298
+ 7. Existing core functionality still works.
299
+ 8. Safety invariants remain unchanged.
300
+ 9. Build and relevant tests pass.
301
+
302
+ <!-- HARNESS:START -->
303
+ ## Harness workflow
304
+
305
+ This repository uses Repository Harness for durable task intake, proof, and
306
+ decision records. This block adds to the CarePath instructions above; it does
307
+ not replace them.
308
+
309
+ Priority, highest first:
310
+
311
+ 1. The current user request and the safety and product rules in this file.
312
+ 2. Current product contracts in `docs/product/`.
313
+ 3. Selected story packets in `docs/stories/` and accepted decisions in
314
+ `docs/decisions/`.
315
+ 4. Executable tests and the Harness proof matrix.
316
+ 5. `docs/history/` as context only.
317
+
318
+ Before any task, read `README.md`, `docs/HARNESS.md`, and
319
+ `docs/FEATURE_INTAKE.md`; then run
320
+ `.\scripts\bin\harness-cli.exe query matrix` on Windows. Classify and record
321
+ the task as `tiny`, `normal`, or `high-risk` before changing code.
322
+
323
+ - Tiny work records an intake and runs the relevant quick proof.
324
+ - Normal work also updates one story packet and its proof record.
325
+ - High-risk work uses `docs/templates/high-risk-story/`, records a decision
326
+ when it changes architecture, data, safety, APIs, or validation, and waits
327
+ for human direction if its scope is ambiguous.
328
+ - A UX or product-flow task still must first update
329
+ `docs/ux-redesign-carepath.md`, then follow the Harness lane requirements.
330
+ - Before a step that could use an external tool, query the available provider:
331
+ `.\scripts\bin\harness-cli.exe query tools --capability <capability> --status present`.
332
+ A missing provider is a clean skip, never a reason to invent a dependency.
333
+ - Finish normal and high-risk work with a Harness trace that records the real
334
+ validation outcome and any friction. Do not claim proof that was not run.
335
+ <!-- HARNESS:END -->
CLAUDE.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # CarePath
2
+
3
+ @AGENTS.md
4
+ @docs/FEATURE_INTAKE.md
5
+
6
+ Use the Harness workflow in `AGENTS.md` before changing this repository.
Dockerfile ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # --- Stage 1: build the static frontends (demo site + interpreter console) ---
2
+ FROM node:22-slim AS frontends
3
+
4
+ WORKDIR /build
5
+
6
+ COPY scribe/frontend/package.json scribe/frontend/package-lock.json scribe/frontend/
7
+ RUN cd scribe/frontend && npm ci
8
+ COPY scribe/frontend scribe/frontend
9
+ # site build also runs the Vietnamese diacritics gate.
10
+ RUN cd scribe/frontend && npm run build
11
+
12
+ COPY interpreter/frontend/package.json interpreter/frontend/package-lock.json interpreter/frontend/
13
+ RUN cd interpreter/frontend && npm ci
14
+ COPY interpreter/frontend interpreter/frontend
15
+ # Production build uses base /phien-dich-y-khoa/ (see interpreter/frontend/vite.config.ts).
16
+ ARG VITE_PUBLIC_SITE_URL
17
+ ENV VITE_PUBLIC_SITE_URL=${VITE_PUBLIC_SITE_URL}
18
+ RUN cd interpreter/frontend && npm run build
19
+
20
+ # --- Stage 2: Python runtime serving both APIs and the built frontends ---
21
+ FROM python:3.12-slim
22
+
23
+ ENV PYTHONDONTWRITEBYTECODE=1 \
24
+ PYTHONUNBUFFERED=1 \
25
+ PIP_NO_CACHE_DIR=1 \
26
+ HF_HOME=/opt/hf-cache
27
+
28
+ WORKDIR /app
29
+
30
+ RUN apt-get update \
31
+ && apt-get install -y --no-install-recommends ca-certificates libgomp1 libsndfile1 \
32
+ && rm -rf /var/lib/apt/lists/*
33
+
34
+ COPY pyproject.toml README.md ./
35
+ COPY shared ./shared
36
+ COPY scribe/carepath ./scribe/carepath
37
+ COPY interpreter ./interpreter
38
+ RUN python -m pip install --upgrade pip \
39
+ && python -m pip install . ./shared ./interpreter
40
+
41
+ ARG GIPFORMER_QUANTIZE=int8
42
+ ENV GIPFORMER_QUANTIZE=${GIPFORMER_QUANTIZE}
43
+ RUN python -c "from carepath.services.asr import GipformerASR; from huggingface_hub import hf_hub_download; files = GipformerASR.onnx_files['${GIPFORMER_QUANTIZE}']; [hf_hub_download(repo_id=GipformerASR.repo_id, filename=name) for name in (*files.values(), 'tokens.txt')]"
44
+
45
+ COPY data ./data
46
+ COPY --from=frontends /build/scribe/frontend/dist ./scribe/frontend/dist
47
+ COPY --from=frontends /build/interpreter/frontend/dist ./interpreter/frontend/dist
48
+ ENV SITE_DIST_DIR=/app/scribe/frontend/dist \
49
+ CONSOLE_DIST_DIR=/app/interpreter/frontend/dist
50
+
51
+ EXPOSE 7860
52
+
53
+ CMD ["uvicorn", "carepath.main:app", "--app-dir", "scribe", "--host", "0.0.0.0", "--port", "7860"]
README.hf-space.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: CarePath
3
+ sdk: docker
4
+ app_port: 7860
5
+ ---
6
+
7
+ # CarePath Space
8
+
9
+ This Space runs the unified CarePath product from the root `Dockerfile`, which
10
+ builds `scribe/frontend/` and `interpreter/frontend/`:
11
+ demo site at `/`, Scribe tool at `/ghi-chep-lam-sang/`, scriber API at
12
+ `/api/v1/*`, and Interpreter API at `/api/*` + `/ws/*`. Interpreter browser
13
+ paths are disabled for public users while that module remains in development.
14
+
15
+ Required Space secrets (scriber; the interpreter runs keyless in mock mode):
16
+
17
+ - `LLM_PROVIDER=ckey`
18
+ - `LLM_API_KEY=<your CKey key>`
19
+ - `LLM_MODEL=gpt-5.4`
20
+ - `TEAM_CODE=<shared internal bypass code>`
21
+ - `APP_ENV=prod`
README.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: CarePath
3
+ sdk: docker
4
+ app_port: 7860
5
+ ---
6
+
7
+ # CarePath Space
8
+
9
+ This Space runs the unified CarePath product from the root `Dockerfile`, which
10
+ builds `scribe/frontend/` and `interpreter/frontend/`:
11
+ demo site at `/`, Scribe tool at `/ghi-chep-lam-sang/`, scriber API at
12
+ `/api/v1/*`, and Interpreter API at `/api/*` + `/ws/*`. Interpreter browser
13
+ paths are disabled for public users while that module remains in development.
14
+
15
+ Required Space secrets (scriber; the interpreter runs keyless in mock mode):
16
+
17
+ - `LLM_PROVIDER=ckey`
18
+ - `LLM_API_KEY=<your CKey key>`
19
+ - `LLM_MODEL=gpt-5.4`
20
+ - `TEAM_CODE=<shared internal bypass code>`
21
+ - `APP_ENV=prod`
UI-FIX-PLAN.md ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # UI Fix Plan — carepath-omega.vercel.app (scribe/frontend/)
2
+
3
+ Plan authored by Fable 5 after reviewing the live deploy and source. Executor: Opus 4.8.
4
+ Scope: the Vite/React app in `scribe/frontend/` only. Do the fixes in order. Keep diffs minimal — no redesigns, no new dependencies.
5
+
6
+ ## How findings were verified (and how you re-verify)
7
+
8
+ The live site was screenshotted and probed with the repo's own Playwright
9
+ (`scribe/frontend/node_modules/playwright-core`, headless Chromium) at 1440/1100/900/800/390px widths.
10
+ Re-run any probe the same way, e.g.:
11
+
12
+ ```js
13
+ // node, from scribe/frontend/: require('playwright-core'), launch chromium,
14
+ // newPage({ viewport }), goto https://carepath-omega.vercel.app/ (or local `npm run preview`)
15
+ ```
16
+
17
+ Verify locally against `npm run dev`/`preview` in `scribe/frontend/` — do not deploy to verify.
18
+
19
+ ## Do NOT chase these (verified non-issues)
20
+
21
+ Full-page/element screenshots of this site produce artifacts because of the sticky nav and
22
+ GSAP scroll animations. Already confirmed fine:
23
+
24
+ - Hero "Audio → SOAP" strip overhanging its card (`.hero__route--scribe { right: -3% }`) is an
25
+ intentional accent. `document.scrollWidth - clientWidth === 0` at all tested widths — no
26
+ horizontal overflow anywhere.
27
+ - Grey band across the bottom of the safety bento in screenshots = GSAP scrub timeline
28
+ (`scribe/frontend/src/landing/useLandingMotion.ts:45-68`) caught mid-state. Renders correctly live.
29
+ - Scribe chapter body text is complete in source (`scribe/frontend/src/content/strings.ts:340`); the
30
+ "truncation" seen in captures was the sticky nav bar overlaying a line during scroll-stitching.
31
+ - Marquee is 48px tall and animates correctly; "clipped text" in captures is the same stitching
32
+ artifact.
33
+
34
+ ---
35
+
36
+ ## P0-1: Lead contact path is dead on production
37
+
38
+ **Symptom:** Footer "Liên hệ chương trình thí điểm" renders `href="mailto:"` (no recipient).
39
+ Submitting the pilot lead form opens a recipient-less mail draft and then shows the success-ish
40
+ "mail opened" status. The site's only conversion path silently goes nowhere.
41
+
42
+ **Root cause:** Neither `VITE_LEAD_ENDPOINT` nor `VITE_LEAD_EMAIL` is set in the Vercel project.
43
+ `submitLead()` falls through to `buildLeadMailto(payload, email = "")`
44
+ (`scribe/frontend/src/leads.ts:88-130`). The deploy gate `scribe/frontend/scripts/validate-deploy-env.mjs` only
45
+ validates `VITE_API_BASE` + `VITE_CONSOLE_URL`, so the build passed anyway
46
+ (`scribe/frontend/vercel.json` runs `npm run validate:deploy && npm run build`).
47
+
48
+ **Fix (all three parts):**
49
+ 1. `scribe/frontend/scripts/validate-deploy-env.mjs`: require at least one lead channel — error if both
50
+ `VITE_LEAD_ENDPOINT` and `VITE_LEAD_EMAIL` are empty. Extend
51
+ `scribe/frontend/scripts/validate-deploy-env.test.mjs` accordingly (`npm run test:deploy-env`).
52
+ 2. UI guard, belt-and-suspenders:
53
+ - `scribe/frontend/src/leads.ts` / `scribe/frontend/src/LeadForm.tsx`: if no endpoint and no email, `submitLead`
54
+ must not open `mailto:` and the form must show the existing error status (`labels.failed`
55
+ path) instead of "mail opened". Never report success for a no-op.
56
+ - `scribe/frontend/src/LandingPage.tsx:476-478`: don't render the footer mailto link when
57
+ `VITE_LEAD_EMAIL` is empty (render the text non-linked, or drop it).
58
+ - Existing tests mock `leadEmail`/`endpoint` props (`scribe/frontend/src/LeadForm.test.tsx`,
59
+ `scribe/frontend/src/leads.test.ts`) — add the empty-config case.
60
+ 3. Tell the user to set `VITE_LEAD_EMAIL` (and optionally `VITE_LEAD_ENDPOINT`) in the Vercel
61
+ project settings — the value is a business decision; do not invent one. The code fix must be
62
+ correct with or without it.
63
+
64
+ **Accept when:** with no lead env vars, footer shows no dead link and form submit shows an error,
65
+ not success; `npm run test` and `npm run test:deploy-env` pass; with `VITE_LEAD_EMAIL` set the
66
+ mailto contains the recipient.
67
+
68
+ ## P0-2: Mobile nav menu opens off-screen — links unusable on phones
69
+
70
+ **Symptom:** At 390×844, opening the hamburger shows a white panel whose link labels are
71
+ invisible. Measured panel box: `x = -108, width = 304` — a third of it (including all left-padded
72
+ label text) is past the left viewport edge. At 900px the panel floats detached mid-nav
73
+ (`x = 225`) under the centered button.
74
+
75
+ **Root cause:** `scribe/frontend/src/styles.css:2267-2277` — `.site-nav__menu > div` is
76
+ `position: absolute; right: 0` anchored to `.site-nav__menu` (`position: relative`, line 2248),
77
+ i.e. to the 2.6rem hamburger itself, which sits mid-nav between the brand and the VI/EN toggle.
78
+ The 19rem-wide panel extends leftward from there.
79
+
80
+ **Fix:** Anchor the panel to the nav bar, not the button. `.site-nav` is `position: sticky`
81
+ (styles.css:129-141) and therefore already a containing block for absolute descendants — the
82
+ smallest fix is to drop `position: relative` from `.site-nav__menu` (line 2248) and give the
83
+ panel a right offset matching the nav padding (`right: max(1.5rem, calc((100vw - var(--container)) / 2))`
84
+ at ≥761px; `1rem`-ish at ≤760px — mirror the nav's own padding values). Keep
85
+ `width: min(19rem, calc(100vw - 2rem))`.
86
+
87
+ **Accept when:** at 320, 390, 760, and 900px widths the open panel's bounding box is fully inside
88
+ the viewport, flush near the right edge below the bar, and every link label is visible.
89
+
90
+ ## P0-3: Menu never closes after navigating
91
+
92
+ **Symptom:** Tap hamburger → tap "An toàn" → page scrolls to the section but the `<details>`
93
+ panel stays open, covering the content just navigated to. Verified: `.site-nav__menu[open]`
94
+ still present after link click.
95
+
96
+ **Root cause:** Native `<details>` doesn't close on child anchor clicks
97
+ (`scribe/frontend/src/LandingPage.tsx:60-63`).
98
+
99
+ **Fix:** In `LandingPage.tsx`, close the details when a menu link is clicked (e.g. `onClick` on
100
+ the wrapping div or each link that clears the `open` attribute via a ref). Keep it a few lines —
101
+ no state library, no outside-click handler unless it's free.
102
+
103
+ **Accept when:** tapping any menu link scrolls to the section AND the panel is closed.
104
+
105
+ ## P1-1: Evidence section headline wraps 2 words × 6 lines on desktop
106
+
107
+ **Symptom:** At 1440px, "Xem cách mỗi sản phẩm giữ điểm cần duyệt ở đúng chỗ." renders 64px in a
108
+ 379px-wide column → 6 cramped lines. Measured: `{w: 379, fs: 64px, lines: 6}`; still 4 lines at
109
+ 1100px. Inside the carousel the slide `h3` (up to 2.6rem in a ~270px column,
110
+ `.evidence-slide` col `minmax(13rem, 0.65fr)`, styles.css:2062-2094) wraps ~5 lines the same way.
111
+
112
+ **Root cause:** `.evidence` grid gives the intro `minmax(16rem, 0.55fr)` of a 74rem container
113
+ minus up to 8rem gap (styles.css:2049-2056), while `.section-intro h2` uses the global
114
+ `clamp(2rem, 4.5vw, 4rem)` scale (styles.css:1615-1618) sized for full-width intros.
115
+
116
+ **Fix:** Scoped override, not a layout rework — e.g.
117
+ `.evidence .section-intro h2 { font-size: clamp(1.8rem, 2.2vw, 2.5rem); }` and similarly cap
118
+ `.evidence-slide__copy h3` (~`clamp(1.4rem, 1.8vw, 1.9rem)`). Alternatively rebalance the column
119
+ (`0.55fr → 0.75fr`) plus a smaller cap — pick whichever reads best live, but the acceptance bar
120
+ is below. Don't touch other sections' headings.
121
+
122
+ **Accept when:** at 1280–1600px the evidence h2 wraps ≤3 lines with ≥3 words per line, and each
123
+ slide h3 wraps ≤3 lines; ≤1023px layouts (already fine) unchanged.
124
+
125
+ ## P2 (do only after P0/P1; each is a 1–2 line change)
126
+
127
+ - **Sticky nav dissolves into the page while scrolling.** `--nav-bg` ≈ page beige at 0.92 alpha
128
+ with only a hairline border (styles.css:129-141), so the floating VI/EN pill + hamburger appear
129
+ to sit directly on content text mid-scroll (most visible on mobile). Add a subtle
130
+ `box-shadow` (or slightly stronger bottom border) to `.site-nav` so the bar reads as a surface.
131
+ - **Marquee labels are 11.84px** (`.marquee__track span`, `font-size: 0.74rem`,
132
+ styles.css:780-791) — uppercase microtext below the 12px floor; bump to `0.78rem`.
133
+ - **Demo controls wrap ragged on mobile:** in `.demo__controls`
134
+ (`scribe/frontend/src/demo/DemoPlayer.tsx:251`, styles for it in styles.css) "Phát lại" wraps to an orphan
135
+ row at 390px. Make the wrap intentional (consistent gap; buttons full-width or evenly split at
136
+ ≤760px — match `.product-chapter__actions`' existing pattern at styles.css:2429-2433).
137
+
138
+ ## Verification (run all from `scribe/frontend/`)
139
+
140
+ 1. `npm run lint`, `npm run test`, `npm run test:deploy-env` — all green.
141
+ 2. `npm run build` — green WITH lead env vars; FAILS with a clear message when both lead vars are
142
+ missing (new validator rule). `npm run dev` for visual checks.
143
+ 3. Playwright probe (as above) against local dev at 390 / 760 / 900 / 1440px:
144
+ menu panel fully in-viewport, closes on navigate; evidence h2 line counts within budget;
145
+ `scrollWidth === clientWidth` (no new horizontal overflow at any width).
146
+ 4. Both languages (VI default, EN toggle) and `#/scribe` route still render — `App.test.tsx`,
147
+ `LandingPage.test.tsx`, `ScribeTool.test.tsx` cover regressions.
148
+ 5. The build's `check-diacritics.mjs` runs inside `npm run build` — any copy you touch must keep
149
+ Vietnamese diacritics intact.
150
+
151
+ ## Out of scope
152
+
153
+ Backend/`scribe/carepath`, the HF-space console (external `VITE_CONSOLE_URL` target), `interpreter/frontend/`
154
+ (separate app), content rewrites, redesigns, new sections, dependencies.
data/medical_lexicon.json ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "terms": [
3
+ {
4
+ "term": "SpO2",
5
+ "category": "vital_sign",
6
+ "vietnamese": "độ bão hòa oxy",
7
+ "aliases": ["spo2", "saturation", "oxy máu"]
8
+ },
9
+ {
10
+ "term": "ECG",
11
+ "category": "test",
12
+ "vietnamese": "điện tâm đồ",
13
+ "aliases": ["ekg", "electrocardiogram"]
14
+ },
15
+ {
16
+ "term": "HbA1c",
17
+ "category": "biomarker",
18
+ "vietnamese": "đường huyết trung bình",
19
+ "aliases": ["hba1c", "a1c"]
20
+ },
21
+ {
22
+ "term": "glucose",
23
+ "category": "biomarker",
24
+ "vietnamese": "đường huyết",
25
+ "aliases": ["blood sugar", "đường máu"]
26
+ },
27
+ {
28
+ "term": "insulin",
29
+ "category": "medication",
30
+ "vietnamese": "insulin",
31
+ "aliases": ["in-su-lin"]
32
+ },
33
+ {
34
+ "term": "metformin",
35
+ "category": "medication",
36
+ "vietnamese": "metformin",
37
+ "aliases": ["met for min", "mét-pho-min"]
38
+ },
39
+ {
40
+ "term": "hypertension",
41
+ "category": "condition",
42
+ "vietnamese": "tăng huyết áp",
43
+ "aliases": ["cao huyết áp", "high blood pressure"]
44
+ },
45
+ {
46
+ "term": "diabetes mellitus",
47
+ "category": "condition",
48
+ "vietnamese": "đái tháo đường",
49
+ "aliases": ["tiểu đường", "diabetes"]
50
+ },
51
+ {
52
+ "term": "COPD",
53
+ "category": "condition",
54
+ "vietnamese": "bệnh phổi tắc nghẽn mạn tính",
55
+ "aliases": ["copd", "bệnh phổi tắc nghẽn"]
56
+ },
57
+ {
58
+ "term": "asthma",
59
+ "category": "condition",
60
+ "vietnamese": "hen phế quản",
61
+ "aliases": ["hen suyễn"]
62
+ },
63
+ {
64
+ "term": "BMI",
65
+ "category": "biometric",
66
+ "vietnamese": "chỉ số khối cơ thể",
67
+ "aliases": ["body mass index"]
68
+ },
69
+ {
70
+ "term": "creatinine",
71
+ "category": "biomarker",
72
+ "vietnamese": "creatinin",
73
+ "aliases": ["creatinin"]
74
+ },
75
+ {
76
+ "term": "eGFR",
77
+ "category": "biomarker",
78
+ "vietnamese": "mức lọc cầu thận ước tính",
79
+ "aliases": ["egfr", "gfr"]
80
+ },
81
+ {
82
+ "term": "CRP",
83
+ "category": "biomarker",
84
+ "vietnamese": "protein phản ứng C",
85
+ "aliases": ["c reactive protein"]
86
+ },
87
+ {
88
+ "term": "WBC",
89
+ "category": "biomarker",
90
+ "vietnamese": "bạch cầu",
91
+ "aliases": ["white blood cell", "leukocyte"]
92
+ },
93
+ {
94
+ "term": "hemoglobin",
95
+ "category": "biomarker",
96
+ "vietnamese": "huyết sắc tố",
97
+ "aliases": ["hb"]
98
+ },
99
+ {
100
+ "term": "platelet",
101
+ "category": "biomarker",
102
+ "vietnamese": "tiểu cầu",
103
+ "aliases": ["plt"]
104
+ },
105
+ {
106
+ "term": "sodium",
107
+ "category": "biomarker",
108
+ "vietnamese": "natri",
109
+ "aliases": ["na", "na+"]
110
+ },
111
+ {
112
+ "term": "potassium",
113
+ "category": "biomarker",
114
+ "vietnamese": "kali",
115
+ "aliases": ["k", "k+"]
116
+ },
117
+ {
118
+ "term": "ALT",
119
+ "category": "biomarker",
120
+ "vietnamese": "men gan ALT",
121
+ "aliases": ["sgpt"]
122
+ },
123
+ {
124
+ "term": "AST",
125
+ "category": "biomarker",
126
+ "vietnamese": "men gan AST",
127
+ "aliases": ["sgot"]
128
+ },
129
+ {
130
+ "term": "ultrasound",
131
+ "category": "test",
132
+ "vietnamese": "siêu âm",
133
+ "aliases": ["sonography"]
134
+ },
135
+ {
136
+ "term": "X-ray",
137
+ "category": "test",
138
+ "vietnamese": "x-quang",
139
+ "aliases": ["xray", "x quang"]
140
+ },
141
+ {
142
+ "term": "CT",
143
+ "category": "test",
144
+ "vietnamese": "chụp cắt lớp vi tính",
145
+ "aliases": ["ct scan", "computed tomography"]
146
+ },
147
+ {
148
+ "term": "MRI",
149
+ "category": "test",
150
+ "vietnamese": "chụp cộng hưởng từ",
151
+ "aliases": ["magnetic resonance imaging"]
152
+ },
153
+ {
154
+ "term": "pneumonia",
155
+ "category": "condition",
156
+ "vietnamese": "viêm phổi",
157
+ "aliases": ["lung infection"]
158
+ },
159
+ {
160
+ "term": "tachycardia",
161
+ "category": "finding",
162
+ "vietnamese": "nhịp tim nhanh",
163
+ "aliases": ["tim nhanh"]
164
+ },
165
+ {
166
+ "term": "bradycardia",
167
+ "category": "finding",
168
+ "vietnamese": "nhịp tim chậm",
169
+ "aliases": ["tim chậm"]
170
+ },
171
+ {
172
+ "term": "systolic",
173
+ "category": "vital_sign",
174
+ "vietnamese": "huyết áp tâm thu",
175
+ "aliases": ["tâm thu"]
176
+ },
177
+ {
178
+ "term": "diastolic",
179
+ "category": "vital_sign",
180
+ "vietnamese": "huyết áp tâm trương",
181
+ "aliases": ["tâm trương"]
182
+ },
183
+ {
184
+ "term": "testosterone",
185
+ "category": "hormone",
186
+ "vietnamese": "testosterone",
187
+ "aliases": ["testosteron"]
188
+ },
189
+ {
190
+ "term": "dihydrotestosterone",
191
+ "category": "hormone",
192
+ "vietnamese": "dihydrotestosterone",
193
+ "aliases": ["dht"]
194
+ },
195
+ {
196
+ "term": "Bartholin",
197
+ "category": "anatomy",
198
+ "vietnamese": "tuyến Bartholin",
199
+ "aliases": ["bartholins"]
200
+ },
201
+ {
202
+ "term": "methionine",
203
+ "category": "biochemistry",
204
+ "vietnamese": "methionin",
205
+ "aliases": ["methionin"]
206
+ },
207
+ {
208
+ "term": "glutathione",
209
+ "category": "biochemistry",
210
+ "vietnamese": "glutathion",
211
+ "aliases": ["glutathion"]
212
+ }
213
+ ]
214
+ }
215
+
docs/ARCHITECTURE.md ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath Architecture
2
+
3
+ CarePath is one FastAPI deployment with two separately named clinical workflows.
4
+ The combined entrypoint is `scribe/carepath/main.py`; it owns the Scribe API,
5
+ imports the Interpreter routers from `interpreter/app`, and mounts both built Vite
6
+ frontends after API routes.
7
+
8
+ ## Product Boundaries
9
+
10
+ | Workflow | Backend boundary | Browser surface |
11
+ | --- | --- | --- |
12
+ | Ghi chép bệnh án AI | `scribe/carepath`, `/api/v1/*` | `scribe/frontend/` at `/`, including `/ghi-chep-lam-sang/` |
13
+ | Phiên dịch khám bệnh trực tiếp | `interpreter/app`, `/api/*` and `/ws/*` | `interpreter/frontend/` at `/phien-dich-y-khoa/` |
14
+
15
+ `/console/` redirects to the canonical interpreter path for compatibility. The
16
+ two API namespaces intentionally do not overlap.
17
+
18
+ `scribe/training/` is exclusively the Scribe's offline DARAG/GEC training and quality
19
+ track. It does not train or serve the Interpreter. `interpreter/eval/` is a
20
+ separate deterministic translation-safety harness that stays with the
21
+ Interpreter.
22
+
23
+ ## Boundaries That Must Stay Explicit
24
+
25
+ - Scribe output is a clinician-reviewed draft; it does not replace clinical
26
+ judgment.
27
+ - Interpreter output is translation only. High or critical risk stays blocked
28
+ from patient display and TTS until clinician confirmation.
29
+ - Interpreter audio is memory-only: no raw-audio persistence, no microphone
30
+ capture before consent, and failures fail closed.
31
+ - Risk lexicons and glossary seeds are editable JSON/CSV data, not code.
32
+ - Providers, environment variables, HTTP/WebSocket payloads, uploaded files,
33
+ and database rows are trust boundaries and must be parsed before use.
34
+
35
+ ## Delivery and Proof
36
+
37
+ The shared process serves built static assets in production; Vite dev servers
38
+ remain the development path. Existing Python, eval, frontend, browser, build,
39
+ and Lighthouse commands are the validation ladder. Do not add a second service,
40
+ state framework, or test runner unless a selected story proves the need.
docs/CONTEXT_RULES.md ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath Context Rules
2
+
3
+ Read enough to preserve the selected contract, not the entire repository.
4
+
5
+ | Lane | Required context before implementation |
6
+ | --- | --- |
7
+ | Tiny | `AGENTS.md`, `docs/FEATURE_INTAKE.md`, matrix query, and exact files to change |
8
+ | Normal | Tiny context plus relevant product contract, story, validation command, and architecture when a boundary changes |
9
+ | High-risk | Normal context plus relevant decisions, high-risk template, safety/eval fixtures, and every affected module boundary |
10
+
11
+ Always read the current task's validation evidence before recording its trace.
12
+ For product or UX work, read the appropriate `docs/product/` contract; for UX
13
+ flows also read `docs/ux-redesign-carepath.md`. For risk, consent, TTS, audio,
14
+ or provider work, read `AGENTS.md` safety invariants and the affected tests and
15
+ fixtures before editing.
16
+
17
+ Stop reading unrelated history once the lane, contract, affected files, and
18
+ proof path are clear. Search targeted paths with `rg` rather than loading broad
19
+ archives.
docs/FEATURE_INTAKE.md ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath Feature Intake
2
+
3
+ Every implementation request is classified before code changes. Record the
4
+ classification with `.\scripts\bin\harness-cli.exe intake`.
5
+
6
+ ## Input Types
7
+
8
+ | Type | Use when | Typical artifact |
9
+ | --- | --- | --- |
10
+ | Change request | Bounded behavior, bug, copy, or UX refinement | Direct patch or story |
11
+ | New initiative | A new product area spanning multiple stories | Initiative note and stories |
12
+ | Maintenance request | Dependency, performance, delivery, or operational work | Story or decision |
13
+ | Harness improvement | Process, proof, template, or instruction work | Harness docs and trace |
14
+
15
+ ## Lanes
16
+
17
+ ### Tiny
18
+
19
+ Use for narrow docs, copy, or isolated maintenance with no safety, API, data,
20
+ or multi-module impact. Record intake, patch directly, and run the relevant
21
+ quick proof. A UX or product-flow change still updates
22
+ `docs/ux-redesign-carepath.md` first.
23
+
24
+ ### Normal
25
+
26
+ Use for a bounded change to one product surface or shared implementation. Create
27
+ or update one story packet, define the validation, update proof flags, and
28
+ record a standard trace.
29
+
30
+ ### High-Risk
31
+
32
+ Use `docs/templates/high-risk-story/` and record a durable decision when the
33
+ work changes safety behavior, architecture, data ownership, public API shape,
34
+ or validation policy. Ask the user before implementing when the direction is
35
+ ambiguous.
36
+
37
+ ## CarePath Hard Gates
38
+
39
+ The following are always high-risk:
40
+
41
+ - Consent, microphone capture, raw-audio handling, retention, or privacy.
42
+ - Interpreter risk classification, confidence display, patient display, TTS,
43
+ escalation, or fail-closed behavior.
44
+ - Medical advice boundaries, provider behavior, credentials, or external
45
+ clinical data.
46
+ - Public API or WebSocket contract changes, database migrations, or changes
47
+ that span the Scribe and Interpreter modules.
48
+ - Removing or weakening existing safety or validation requirements.
49
+
50
+ Use the existing test and eval fixtures whenever a risk-engine rule changes;
51
+ zero misses on critical fixtures remains a hard gate.
docs/GLOSSARY.md ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Glossary
2
+
3
+ ## Agent
4
+
5
+ An AI coding collaborator operating inside the repository.
6
+
7
+ ## Harness
8
+
9
+ The repo-level operating system that tells humans and agents how to turn intent
10
+ into safe product changes.
11
+
12
+ ## Product Contract
13
+
14
+ The current expected behavior of the product. Product docs plus executable tests
15
+ become the living contract once implementation exists.
16
+
17
+ ## Story Packet
18
+
19
+ A story-sized work file or folder that describes the product contract, affected
20
+ docs, design notes, and validation expectations for a feature.
21
+
22
+ ## Feature Intake
23
+
24
+ The classification step that turns a prompt into tiny, normal, or high-risk
25
+ work before implementation begins.
26
+
27
+ ## Component Taxonomy
28
+
29
+ A map from Harness files and capabilities to the responsibilities they serve,
30
+ used to evaluate coverage, attribute failures, and identify missing harness
31
+ capabilities.
32
+
33
+ ## Maturity Level
34
+
35
+ A verifiable stage in Harness capability, from H0 bare environment through H5
36
+ self-improving harness. Each level has required files, criteria, and benchmark
37
+ indicators.
38
+
39
+ ## Trace Quality Tier
40
+
41
+ The expected depth of a task trace: minimal for tiny work, standard for normal
42
+ work, and detailed for high-risk work.
43
+
44
+ ## Verification Gate
45
+
46
+ An advisory Harness check that runs or inspects mechanical proof before a task
47
+ is closed. In Phase 4, `story verify <id>` executes a story's `verify_command`,
48
+ `story verify-all` runs all configured story proof commands, and
49
+ `trace --story <id>` warns when that story's verification has not passed.
50
+
51
+ ## Tool Registry
52
+
53
+ The compiled and registered tool manifest exposed by
54
+ `scripts/bin/harness-cli query tools`. It lets agents discover available
55
+ commands, arguments, responsibilities, and custom project tools.
56
+
57
+ ## Intervention
58
+
59
+ A durable record of human, reviewer, CI, or agent feedback that corrected,
60
+ overrode, escalated, or approved work. Interventions are stored separately from
61
+ traces and feed improvement proposals.
62
+
63
+ ## Context Score
64
+
65
+ The advisory result from `scripts/bin/harness-cli score-context <trace-id>`.
66
+ It compares a trace's recorded `files_read` against compiled context rules and
67
+ retrieval triggers.
68
+
69
+ ## Entropy Score
70
+
71
+ The drift score printed by `scripts/bin/harness-cli audit`. Lower is better.
72
+ It counts stale or incomplete durable records such as orphaned stories,
73
+ unverified proof commands, missing backlog outcomes, and broken registered
74
+ tools.
75
+
76
+ ## Improvement Proposal
77
+
78
+ A structured recommendation generated by `scripts/bin/harness-cli propose` from
79
+ repeated friction, intervention patterns, and audit findings. Proposals are
80
+ advisory unless committed to the backlog with `--commit`.
81
+
82
+ ## Context Phase
83
+
84
+ A phase of an agent task that changes what context should be read, such as
85
+ intake, planning, implementation, validation, or trace recording.
86
+
87
+ ## Retrieval Trigger
88
+
89
+ A condition that tells an agent to fetch additional context, such as touching a
90
+ database schema, changing a public contract, or discovering missing validation.
91
+
92
+ ## Harness Delta
93
+
94
+ A documentation, template, validation, backlog, or decision update that makes
95
+ future agent work safer or easier.
96
+
97
+ ## Backlog Outcome Loop
98
+
99
+ The feedback workflow for Harness improvements: record predicted impact when a
100
+ backlog item is created, then record actual measured outcome when the item is
101
+ closed so future agents can compare expectation with result.
102
+
103
+ ## Durable Layer
104
+
105
+ The SQLite database and CLI (`scripts/bin/harness-cli`) that stores operational records
106
+ (intakes, stories, decisions, backlog items, traces) as structured, queryable
107
+ data. Policy docs describe how to work; the durable layer stores what happened.
108
+
109
+ ## Product Delta
110
+
111
+ A product-facing change such as code, tests, API shape, data model, or product
112
+ documentation.
113
+
114
+ ## Trace
115
+
116
+ A structured record of what an agent did during a task: actions taken, files
117
+ read, files changed, decisions made, errors encountered, outcome, and any
118
+ harness friction discovered.
119
+
120
+ ## Tool Registry
121
+
122
+ The compiled and user-registered tool manifest exposed by
123
+ `scripts/bin/harness-cli query tools` and documented in `docs/TOOL_REGISTRY.md`.
124
+
125
+ ## Intervention
126
+
127
+ A durable record of a human, reviewer, CI, or agent correction, override,
128
+ escalation, or approval that is separate from the normal task trace.
129
+
130
+ ## Context Score
131
+
132
+ The advisory result from `scripts/bin/harness-cli score-context <trace-id>`,
133
+ which compares a trace's recorded reads against compiled context rules.
134
+
135
+ ## Entropy Score
136
+
137
+ The drift score from `scripts/bin/harness-cli audit`. Lower scores mean fewer
138
+ orphaned, stale, unverified, outcome-missing, or broken-tool records.
139
+
140
+ ## Improvement Proposal
141
+
142
+ A structured proposal generated by `scripts/bin/harness-cli propose` from
143
+ repeated friction, interventions, and audit drift. Proposals can be committed as
144
+ backlog items with `--commit`.
docs/HARNESS.md ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath Harness
2
+
3
+ CarePath uses Repository Harness to turn a request into safe, reviewable work.
4
+ The application is what clinicians use; the Harness is the durable operating
5
+ layer for humans and coding agents.
6
+
7
+ ## Sources of Truth
8
+
9
+ Apply sources in this order:
10
+
11
+ 1. Current user instruction and the safety, Vietnamese-first, and UX rules in
12
+ `AGENTS.md`.
13
+ 2. The current contracts in `docs/product/`.
14
+ 3. The selected story packet in `docs/stories/` and accepted decisions in
15
+ `docs/decisions/`.
16
+ 4. Executable tests and the proof matrix.
17
+ 5. `docs/history/` and research as background, unless a current contract
18
+ explicitly incorporates them.
19
+
20
+ No Harness document may weaken a CarePath safety invariant. If sources conflict,
21
+ pause and ask the user rather than choosing a less-safe interpretation.
22
+
23
+ ## Durable Layer
24
+
25
+ `scripts/bin/harness-cli.exe` manages the local, ignored `harness.db` using the
26
+ versioned migrations in `scripts/schema/`. Initialize it once per clone:
27
+
28
+ ```powershell
29
+ .\scripts\bin\harness-cli.exe init
30
+ ```
31
+
32
+ The database records intake classifications, story proof, decisions, traces,
33
+ and Harness friction. Markdown remains the reviewable product record; the
34
+ database records what happened locally.
35
+
36
+ ## Task Loop
37
+
38
+ 1. Read `AGENTS.md`, this file, `docs/FEATURE_INTAKE.md`, and the current
39
+ matrix.
40
+ 2. Classify and record the request with `harness-cli.exe intake`.
41
+ 3. Read only the affected product contract, stories, decisions, and code.
42
+ 4. Define the proof before implementation.
43
+ 5. Implement only the selected lane.
44
+ 6. Update the product contract, story, and matrix when the change affects them.
45
+ 7. Run the applicable existing checks and record their actual result.
46
+ 8. Record a trace. Capture repeated missing context or proof as Harness
47
+ friction or a backlog item.
48
+
49
+ For UX or product-flow work, `AGENTS.md` additionally requires an updated
50
+ `docs/ux-redesign-carepath.md` before implementation. That requirement applies
51
+ even when intake classifies the edit as tiny.
52
+
53
+ ## Tool Registry
54
+
55
+ The registry is optional. Before relying on an external tool, query it by
56
+ capability. If no present provider is registered, skip that optional step and
57
+ record the limitation only when it affects proof. Do not add a dependency or
58
+ tool registration merely to satisfy the Harness.
59
+
60
+ ## Done
61
+
62
+ A task is done when its requested change is complete, relevant contracts and
63
+ proof records are current, the applicable checks have real results, and the
64
+ trace says what happened. A failed unrelated existing check is recorded as
65
+ failed proof; repairing it requires separate scope.
docs/HARNESS_AUDIT.md ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Harness Audit
2
+
3
+ `scripts/bin/harness-cli audit` detects drift in durable Harness state and
4
+ prints an entropy score. Lower is better.
5
+
6
+ ## Checks
7
+
8
+ | Category | Meaning | Weight |
9
+ | --- | --- | --- |
10
+ | Orphaned stories | Planned or in-progress stories with no linked trace. | 10 |
11
+ | Unverified stories | Active or implemented stories with `verify_command` but no recorded verification result. Retired stories are historical records and are not counted. | 5 |
12
+ | Unverified decisions | Decisions with `verify_command` but no recorded verification result. | 5 |
13
+ | Open backlog without outcomes | Implemented backlog items with predicted impact but no actual outcome. | 2 |
14
+ | Stale stories | Unimplemented stories whose latest linked trace is more than 30 days old. | 3 |
15
+ | Broken tools | Registered tools whose command is not found on disk or `PATH`. | 8 |
16
+
17
+ ## Score
18
+
19
+ ```text
20
+ score = orphaned_stories * 10
21
+ + unverified_stories * 5
22
+ + unverified_decisions * 5
23
+ + backlog_without_outcomes * 2
24
+ + stale_stories * 3
25
+ + broken_tools * 8
26
+ ```
27
+
28
+ The score is capped at 100.
29
+
30
+ | Range | Interpretation |
31
+ | --- | --- |
32
+ | 0 | Perfect: records are traced, verified, and healthy. |
33
+ | 1-25 | Healthy: minor housekeeping remains. |
34
+ | 26-50 | Attention needed: drift is accumulating. |
35
+ | 51-100 | Action required: stale state undermines Harness value. |
36
+
37
+ Audit findings feed `scripts/bin/harness-cli propose`, which can turn repeated
38
+ drift into proposed backlog items.
docs/HARNESS_BACKLOG.md ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Harness Backlog
2
+
3
+ Use this file when an agent discovers a missing harness capability but should
4
+ not change the operating model immediately.
5
+
6
+ ## Template
7
+
8
+ ```md
9
+ ## Missing Harness Capability
10
+
11
+ ### Title
12
+
13
+ Short name.
14
+
15
+ ### Discovered While
16
+
17
+ Task or story that exposed the gap.
18
+
19
+ ### Current Pain
20
+
21
+ What was hard, repeated, ambiguous, or unsafe?
22
+
23
+ ### Suggested Improvement
24
+
25
+ What should be added or changed?
26
+
27
+ ### Risk
28
+
29
+ Tiny, normal, or high-risk.
30
+
31
+ CLI value: `--risk tiny`, `--risk normal`, or `--risk high-risk`.
32
+
33
+ ### Status
34
+
35
+ proposed | accepted | implemented | rejected
36
+ ```
37
+
38
+ ## Items
39
+
40
+ ## Future Interpreter Risk-Lexicon Consolidation
41
+
42
+ ### Discovered While
43
+
44
+ CP-RES-006 term-store consolidation.
45
+
46
+ ### Current Pain
47
+
48
+ The Interpreter safety lexicons are also clinician-editable data, but they
49
+ govern deterministic risk classification rather than medical-term retrieval.
50
+
51
+ ### Suggested Improvement
52
+
53
+ Evaluate a separate, clinician-approved consolidation only with a safety-fixture
54
+ and evaluation policy change. Do not merge them into the general term source.
55
+
56
+ ### Risk
57
+
58
+ high-risk.
59
+
60
+ ### Status
61
+
62
+ proposed
docs/HARNESS_COMPONENTS.md ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Harness Components
2
+
3
+ This taxonomy maps the current `repository-harness` repository to two
4
+ component frameworks used by Phase 2 and updated by Phase 3 active
5
+ observability work:
6
+
7
+ - Runtime Substrate responsibilities: the 11 responsibility areas the harness
8
+ should cover.
9
+ - NexAU decomposition: the seven implementation surfaces that influence agent
10
+ behavior.
11
+
12
+ Status values:
13
+
14
+ - **Covered**: the repository has an explicit file, command, or record for this
15
+ responsibility.
16
+ - **Partial**: the repository has some support, but the support is incomplete,
17
+ manual, or not yet measured.
18
+ - **Missing**: no meaningful support exists yet.
19
+
20
+ ## Responsibility Map
21
+
22
+ | # | Responsibility | Status | Harness Files | Evidence | Gap |
23
+ | --- | --- | --- | --- | --- | --- |
24
+ | 1 | Task specification | Covered | `AGENTS.md`, `docs/FEATURE_INTAKE.md`, `docs/templates/story.md`, `docs/templates/spec-intake.md`, `docs/templates/high-risk-story/*`, `docs/stories/*`, `intake` table, `story` table | Requests are classified by type and lane before implementation; normal and high-risk work have templates and durable story rows. | Keep story packets synchronized with future product docs. |
25
+ | 2 | Context selection | Covered | `AGENTS.md`, `docs/CONTEXT_RULES.md`, `docs/ARCHITECTURE.md`, `docs/decisions/*`, `docs/product/README.md`, `scripts/bin/harness-cli score-context` | Phase 2 adds phase-by-lane context rules and retrieval triggers; Phase 5 adds context scoring against recorded trace reads. | Future automation could enforce context selection instead of only measuring it. |
26
+ | 3 | Tool access | Covered | `scripts/bin/harness-cli`, `docs/TOOL_REGISTRY.md`, `tool` table, `crates/harness-cli/*`, `scripts/install-harness.sh`, `scripts/build-harness-cli-release.sh` | The Harness CLI exposes operational commands and a machine-readable tool manifest through `query tools`; external tools can be registered and removed. | Permission profiles and usage analytics remain future work. |
27
+ | 4 | Project memory | Covered | `docs/HARNESS.md`, `docs/decisions/*`, `docs/GLOSSARY.md`, `docs/HARNESS_BACKLOG.md`, `docs/stories/*`, `harness.db`, `decision`, `backlog`, and `trace` tables | Decisions, backlog, stories, and traces preserve durable knowledge across tasks. | Future work should add staleness checks and summarize old traces. |
28
+ | 5 | Task state | Covered | `scripts/bin/harness-cli query matrix`, `docs/TEST_MATRIX.md`, `intake` table, `story` table, `trace` table | Durable records track intake, story status, proof columns, and task traces. | Add lifecycle checks so in-progress stories cannot be forgotten. |
29
+ | 6 | Observability | Partial | `docs/TRACE_SPEC.md`, `trace` table, `scripts/bin/harness-cli trace`, `scripts/bin/harness-cli score-trace`, `scripts/bin/harness-cli query traces`, `scripts/bin/harness-cli query friction`, `docs/HARNESS_MATURITY.md` | Traces are auto-scored when recorded, can be rescored by command, and can be reviewed with friction context. | No dashboard or benchmark ingestion exists in this repo. |
30
+ | 7 | Failure attribution | Partial | `docs/HARNESS_COMPONENTS.md`, `docs/TRACE_SPEC.md`, `trace.errors`, `trace.harness_friction`, `docs/HARNESS_BACKLOG.md`, `backlog` table, `scripts/bin/harness-cli query friction` | Failures can be tied to files, components, friction, backlog proposals, and linked intake lane/type context. | No automated attribution from benchmark failures to harness components exists yet. |
31
+ | 8 | Verification | Covered | `docs/TEST_MATRIX.md`, `scripts/bin/harness-cli query matrix`, `scripts/bin/harness-cli story verify`, `scripts/bin/harness-cli story verify-all`, `scripts/bin/harness-cli trace`, `scripts/bin/harness-cli score-trace`, `story.verify_command`, `story.last_verified_result`, `.github/workflows/harness-cli-release.yml`, `docs/templates/validation-report.md` | Stories can store and run mechanical proof commands individually or in batch, traces warn when linked story verification has not passed, trace quality can be checked mechanically, and release workflow verifies Rust CLI releases. | Benchmark ingestion remains future work. |
32
+ | 9 | Permissions | Partial | `AGENTS.md`, `docs/HARNESS.md`, `docs/FEATURE_INTAKE.md`, `docs/ARCHITECTURE.md`, installer conflict handling in `scripts/install-harness.sh` | Policy describes when agents may update docs and when to ask before architecture or workflow changes. | Permissions are instruction-level only; no enforced policy layer or command allowlist exists. |
33
+ | 10 | Entropy auditing | Covered | `docs/HARNESS_BACKLOG.md`, `docs/HARNESS_AUDIT.md`, `docs/IMPROVEMENT_PROTOCOL.md`, `backlog` table, `trace.harness_friction`, `scripts/bin/harness-cli audit`, `scripts/bin/harness-cli propose`, `docs/HARNESS_MATURITY.md` | Growth rule captures friction, audit detects drift and entropy score, backlog items compare predicted impact to actual outcome, and proposal generation can create reviewable backlog items. | Automated repair remains future work. |
34
+ | 11 | Intervention recording | Covered | `intervention` table, `scripts/bin/harness-cli intervention add`, `scripts/bin/harness-cli query interventions`, `trace` table, `docs/decisions/*`, `docs/stories/*`, `docs/HARNESS.md` | Human, reviewer, CI, and agent interventions are separate durable records and can be filtered by trace, story, or type. | Capture is still manual and advisory. |
35
+
36
+ ## NexAU Cross-Reference
37
+
38
+ | Component | Harness Equivalent | Status | Notes |
39
+ | --- | --- | --- | --- |
40
+ | System prompts | `AGENTS.md` plus Harness policy docs | Covered | `AGENTS.md` is the stable shim; `docs/HARNESS.md`, `docs/FEATURE_INTAKE.md`, and `docs/CONTEXT_RULES.md` carry evolving operating instructions. |
41
+ | Tool descriptions | `docs/TOOL_REGISTRY.md`, `scripts/README.md`, `docs/HARNESS.md`, `docs/TRACE_SPEC.md`, CLI help from `crates/harness-cli/src/interface.rs`, `scripts/bin/harness-cli query tools` | Covered | Commands are documented in a standalone registry and exposed as compiled plus registered tool manifest entries. |
42
+ | Tool implementations | `scripts/bin/harness-cli`, `crates/harness-cli/*`, `scripts/schema/001-init.sql`, `scripts/schema/002-story-verify.sql` | Covered | The Rust CLI is the primary durable-layer implementation and stable repo-local entrypoint. |
43
+ | Middleware | installer safety logic, feature intake workflow | Partial | The installer and intake process mediate work, but there is no runtime middleware enforcing policies. |
44
+ | Skills | `docs/templates/*`, `docs/FEATURE_INTAKE.md`, `docs/CONTEXT_RULES.md`, `docs/TRACE_SPEC.md` | Partial | Reusable procedures exist as markdown, not executable or installable agent skills. |
45
+ | Sub-agents | None in this repository | Missing | No delegated specialist agents or sub-agent protocols exist. |
46
+ | Long-term memory | `harness.db`, `docs/decisions/*`, `docs/stories/*`, `docs/HARNESS_BACKLOG.md`, `docs/GLOSSARY.md` | Covered | Durable records and markdown decisions preserve task history and project vocabulary. |
47
+
48
+ ## File Inventory
49
+
50
+ Every tracked project file plus the Phase 2 input file is mapped to at least
51
+ one Runtime Substrate responsibility.
52
+
53
+ | File | Primary Responsibility | Secondary Responsibilities |
54
+ | --- | --- | --- |
55
+ | `.gitignore` | Tool access | Task state |
56
+ | `AGENTS.md` | Context selection | Task specification, permissions |
57
+ | `README.md` | Task specification | Project memory |
58
+ | `CONTRIBUTING.md` | Intervention recording | Project memory |
59
+ | `Cargo.toml` | Tool access | Verification |
60
+ | `Cargo.lock` | Tool access | Verification |
61
+ | `PHASE2.md` | Task specification | Observability, context selection |
62
+ | `PHASE3.md` | Task specification | Observability, verification, entropy auditing |
63
+ | `PHASE4.md` | Task specification | Verification, observability, task state |
64
+ | `PHASE5.md` | Task specification | Verification, entropy auditing, intervention recording |
65
+ | `crates/harness-cli/Cargo.toml` | Tool access | Verification |
66
+ | `crates/harness-cli/src/main.rs` | Tool access | Tool implementation |
67
+ | `crates/harness-cli/src/domain.rs` | Tool access | Task state, verification |
68
+ | `crates/harness-cli/src/application.rs` | Tool access | Task state |
69
+ | `crates/harness-cli/src/infrastructure.rs` | Tool access | Project memory, task state, observability |
70
+ | `crates/harness-cli/src/interface.rs` | Tool access | Context selection, verification |
71
+ | `docs/ARCHITECTURE.md` | Permissions | Context selection, task specification |
72
+ | `docs/FEATURE_INTAKE.md` | Task specification | Permissions, context selection |
73
+ | `docs/GLOSSARY.md` | Project memory | Context selection |
74
+ | `docs/HARNESS.md` | Task specification | Project memory, task state, permissions |
75
+ | `docs/HARNESS_BACKLOG.md` | Entropy auditing | Project memory, failure attribution |
76
+ | `docs/HARNESS_COMPONENTS.md` | Failure attribution | Observability, entropy auditing |
77
+ | `docs/HARNESS_MATURITY.md` | Entropy auditing | Observability, verification |
78
+ | `docs/HARNESS_AUDIT.md` | Entropy auditing | Verification, task state |
79
+ | `docs/IMPROVEMENT_PROTOCOL.md` | Entropy auditing | Failure attribution, permissions |
80
+ | `docs/CONTEXT_RULES.md` | Context selection | Permissions, task specification |
81
+ | `docs/TRACE_SPEC.md` | Observability | Failure attribution, intervention recording |
82
+ | `docs/TOOL_REGISTRY.md` | Tool access | Context selection, verification |
83
+ | `docs/README.md` | Project memory | Context selection |
84
+ | `docs/TEST_MATRIX.md` | Verification | Task state |
85
+ | `docs/decisions/0001-harness-first-development.md` | Project memory | Permissions |
86
+ | `docs/decisions/0002-post-spec-product-lifecycle.md` | Project memory | Task specification |
87
+ | `docs/decisions/0003-generic-spec-intake-harness.md` | Project memory | Task specification |
88
+ | `docs/decisions/0004-sqlite-durable-layer.md` | Project memory | Observability, task state |
89
+ | `docs/decisions/0005-prebuilt-rust-harness-cli.md` | Project memory | Tool access |
90
+ | `docs/decisions/0006-phase-4-benchmark-triage.md` | Project memory | Verification |
91
+ | `docs/decisions/0007-improvement-proposal-rules.md` | Project memory | Entropy auditing, permissions |
92
+ | `docs/decisions/README.md` | Project memory | Context selection |
93
+ | `docs/demo/README.md` | Task specification | Project memory |
94
+ | `docs/product/README.md` | Task specification | Project memory |
95
+ | `docs/review-fixes-1d30bf62-to-main.md` | Intervention recording | Failure attribution, verification |
96
+ | `docs/stories/README.md` | Task specification | Project memory |
97
+ | `docs/stories/US-001-install-harness.md` | Task specification | Verification, intervention recording |
98
+ | `docs/stories/US-008-trace-quality-scoring.md` | Task specification | Observability, verification |
99
+ | `docs/stories/US-009-enriched-friction-query.md` | Task specification | Failure attribution, observability |
100
+ | `docs/stories/US-011-backlog-outcome-workflow.md` | Task specification | Entropy auditing, project memory |
101
+ | `docs/stories/US-012-story-verify-command-field.md` | Task specification | Verification |
102
+ | `docs/stories/US-015-story-verify-command.md` | Task specification | Verification |
103
+ | `docs/stories/US-016-auto-trace-scoring-on-write.md` | Task specification | Observability, verification |
104
+ | `docs/stories/US-017-pre-close-verification-gate.md` | Task specification | Verification, permissions |
105
+ | `docs/stories/US-018-phase4-cli-ux-hardening.md` | Task specification | Tool access, verification |
106
+ | `docs/stories/US-019-machine-readable-tool-registry.md` | Task specification | Tool access |
107
+ | `docs/stories/US-020-batch-story-verification.md` | Task specification | Verification |
108
+ | `docs/stories/US-021-intervention-recording-schema.md` | Task specification | Intervention recording |
109
+ | `docs/stories/US-022-context-rule-measurement.md` | Task specification | Context selection |
110
+ | `docs/stories/US-023-drift-detection-entropy-score.md` | Task specification | Entropy auditing |
111
+ | `docs/stories/US-024-improvement-proposal-pipeline.md` | Task specification | Entropy auditing, permissions |
112
+ | `docs/stories/backlog.md` | Task specification | Project memory |
113
+ | `docs/stories/epics/README.md` | Task specification | Project memory |
114
+ | `docs/stories/epics/E01-durable-layer/US-002-rust-harness-cli/overview.md` | Task specification | Project memory |
115
+ | `docs/stories/epics/E01-durable-layer/US-002-rust-harness-cli/design.md` | Task specification | Tool access, permissions |
116
+ | `docs/stories/epics/E01-durable-layer/US-002-rust-harness-cli/execplan.md` | Task specification | Verification, task state |
117
+ | `docs/stories/epics/E01-durable-layer/US-002-rust-harness-cli/validation.md` | Verification | Intervention recording |
118
+ | `docs/stories/epics/E02-phase-2-observability-taxonomy/phase-2-progress.md` | Task state | Intervention recording |
119
+ | `docs/stories/epics/E03-phase-5-evolution-infrastructure/phase-5-progress.md` | Task state | Verification, entropy auditing |
120
+ | `docs/templates/decision.md` | Project memory | Task specification |
121
+ | `docs/templates/spec-intake.md` | Task specification | Context selection |
122
+ | `docs/templates/story.md` | Task specification | Verification |
123
+ | `docs/templates/validation-report.md` | Verification | Intervention recording |
124
+ | `docs/templates/high-risk-story/overview.md` | Task specification | Context selection |
125
+ | `docs/templates/high-risk-story/design.md` | Task specification | Permissions |
126
+ | `docs/templates/high-risk-story/execplan.md` | Task state | Verification |
127
+ | `docs/templates/high-risk-story/validation.md` | Verification | Failure attribution |
128
+ | `scripts/README.md` | Tool access | Context selection |
129
+ | `scripts/bin/harness-cli` | Tool access | Task state, observability |
130
+ | `scripts/bin/harness-cli` | Tool access | Task state, observability |
131
+ | `scripts/install-harness.sh` | Tool access | Permissions |
132
+ | `scripts/build-harness-cli-release.sh` | Verification | Tool access |
133
+ | `scripts/schema/001-init.sql` | Task state | Observability, project memory |
134
+ | `scripts/schema/002-story-verify.sql` | Verification | Task state, project memory |
135
+ | `scripts/schema/003-tool-registry.sql` | Tool access | Project memory |
136
+ | `scripts/schema/004-intervention.sql` | Intervention recording | Failure attribution |
137
+ | `.github/ISSUE_TEMPLATE/agent-failure-case.md` | Failure attribution | Entropy auditing |
138
+ | `.github/ISSUE_TEMPLATE/pattern-request.md` | Entropy auditing | Intervention recording |
139
+ | `.github/ISSUE_TEMPLATE/real-world-example.md` | Project memory | Intervention recording |
140
+ | `.github/workflows/harness-cli-release.yml` | Verification | Tool access |
141
+
142
+ ## Coverage Summary
143
+
144
+ - Covered: 8/11 responsibilities.
145
+ - Partial: 3/11 responsibilities.
146
+ - Missing: 0/11 responsibilities.
147
+
148
+ Covered responsibilities:
149
+
150
+ - Task specification.
151
+ - Context selection.
152
+ - Tool access.
153
+ - Project memory.
154
+ - Task state.
155
+ - Verification.
156
+ - Entropy auditing.
157
+ - Intervention recording.
158
+ Partial responsibilities:
159
+
160
+ - Observability.
161
+ - Failure attribution.
162
+ - Permissions.
163
+
164
+ Phase 5 converts tool access, entropy auditing, and intervention recording into
165
+ covered responsibilities with a registry, drift audit, proposal loop, and
166
+ intervention schema. Later phases should focus on benchmark ingestion,
167
+ component-level attribution, permission enforcement, and tool usage analytics.
docs/HARNESS_MATURITY.md ADDED
@@ -0,0 +1,316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Harness Maturity Ladder
2
+
3
+ This ladder defines how `repository-harness` should progress from static
4
+ agent instructions to measurable harness improvement.
5
+
6
+ The levels are intentionally verifiable. A level is achieved only when its
7
+ criteria can be inspected in repository files, durable Harness records, or
8
+ benchmark output.
9
+
10
+ ## Levels
11
+
12
+ ### H0 - Bare Environment
13
+
14
+ The model operates with no repository harness. It receives a prompt and may
15
+ produce a patch, but the repo does not tell it how to classify, validate, or
16
+ record work.
17
+
18
+ Criteria:
19
+
20
+ - No `AGENTS.md` Harness block exists.
21
+ - No feature intake policy exists.
22
+ - No story, decision, validation, or trace artifact exists.
23
+
24
+ Required files:
25
+
26
+ - None.
27
+
28
+ Benchmark indicators:
29
+
30
+ - Functional score is the only meaningful metric.
31
+ - Harness compliance: 0%.
32
+ - Trace quality: 0/3.
33
+
34
+ Current status:
35
+
36
+ - Passed. This repository is beyond H0.
37
+
38
+ Activated responsibilities:
39
+
40
+ - None.
41
+
42
+ ### H1 - Scaffolding And Policy
43
+
44
+ The repository contains static operating instructions, templates, risk lanes,
45
+ and source-of-truth rules. Agents can follow a documented workflow, but durable
46
+ state may still be manual or incomplete.
47
+
48
+ Criteria:
49
+
50
+ - `AGENTS.md` points agents to the Harness operating docs.
51
+ - `docs/HARNESS.md`, `docs/FEATURE_INTAKE.md`, and `docs/ARCHITECTURE.md`
52
+ exist.
53
+ - Story, decision, and validation templates exist under `docs/templates/`.
54
+ - `docs/TEST_MATRIX.md` defines proof columns and status meanings.
55
+
56
+ Required files:
57
+
58
+ - `AGENTS.md`
59
+ - `docs/HARNESS.md`
60
+ - `docs/FEATURE_INTAKE.md`
61
+ - `docs/ARCHITECTURE.md`
62
+ - `docs/TEST_MATRIX.md`
63
+ - `docs/templates/story.md`
64
+ - `docs/templates/decision.md`
65
+ - `docs/templates/validation-report.md`
66
+
67
+ Benchmark indicators:
68
+
69
+ - Harness compliance: 20-40%.
70
+ - Lane accuracy improves when agents read the intake policy.
71
+ - Trace quality remains low unless traces are separately requested.
72
+
73
+ Current status:
74
+
75
+ - Achieved. H1 files exist and are used by current Harness instructions.
76
+
77
+ Activated responsibilities:
78
+
79
+ - Task specification.
80
+ - Permissions.
81
+ - Project memory.
82
+ - Verification.
83
+
84
+ ### H2 - Durable State And Observability
85
+
86
+ The repository has structured operational records and explicit observation
87
+ rules. Agents can record what happened, connect work to stories, and write
88
+ traces with predictable depth.
89
+
90
+ Criteria:
91
+
92
+ - `scripts/bin/harness-cli` can record intake, story, decision, backlog, and trace
93
+ data in `harness.db`.
94
+ - `scripts/schema/001-init.sql` defines durable tables for intake, story,
95
+ decision, backlog, and trace records.
96
+ - `docs/HARNESS_COMPONENTS.md` maps files and responsibilities.
97
+ - `docs/HARNESS_MATURITY.md` defines H0-H5 with measurable criteria.
98
+ - `docs/TRACE_SPEC.md` defines trace fields, quality tiers, and friction
99
+ capture.
100
+ - `docs/CONTEXT_RULES.md` defines phase-by-lane context rules.
101
+ - `AGENTS.md` and `docs/HARNESS.md` reference the Phase 2 operating docs.
102
+
103
+ Required files:
104
+
105
+ - `scripts/bin/harness-cli`
106
+ - `scripts/schema/001-init.sql`
107
+ - `docs/HARNESS_COMPONENTS.md`
108
+ - `docs/HARNESS_MATURITY.md`
109
+ - `docs/TRACE_SPEC.md`
110
+ - `docs/CONTEXT_RULES.md`
111
+
112
+ Benchmark indicators:
113
+
114
+ - Harness compliance: 75-90%.
115
+ - Trace quality: at least 2.0/3 on normal-lane tasks.
116
+ - Lane accuracy: 6/6 on the current benchmark suite.
117
+ - Friction captured: at least 4/6 benchmark tasks when friction exists.
118
+
119
+ Current status:
120
+
121
+ - Achieved. Durable state exists, and the Phase 2 docs define the
122
+ observability and context specification. Phase 3 active scoring builds on
123
+ this layer.
124
+
125
+ Activated responsibilities:
126
+
127
+ - Task state.
128
+ - Observability.
129
+ - Failure attribution.
130
+ - Context selection.
131
+ - Entropy auditing.
132
+
133
+ ### H3 - Active Observability And Evolution
134
+
135
+ The harness can evaluate its own operational data and turn repeated failures
136
+ into prioritized improvements.
137
+
138
+ Criteria:
139
+
140
+ - Trace quality can be scored by a repeatable command or benchmark step.
141
+ - Harness friction can be grouped by component from `docs/HARNESS_COMPONENTS.md`.
142
+ - Backlog items include predicted impact and actual outcome after completion.
143
+ - Benchmark comparison output identifies which harness responsibility moved or
144
+ regressed.
145
+
146
+ Required files:
147
+
148
+ - H2 files.
149
+ - A benchmark protocol or report that references maturity levels.
150
+ - A documented trace quality scoring method.
151
+ - A documented friction-to-backlog review loop.
152
+
153
+ Benchmark indicators:
154
+
155
+ - Harness compliance: 85-95%.
156
+ - Trace quality: 2.3-2.7/3.
157
+ - Friction captured and classified by component for most failed or awkward
158
+ tasks.
159
+ - Regressions include an attributed harness component.
160
+
161
+ Current status:
162
+
163
+ - Partially achieved by Phase 3. `scripts/bin/harness-cli score-trace` scores trace
164
+ quality against tier rules, `query friction` includes linked intake context,
165
+ the `trace` command now prints that score at write time, and the backlog
166
+ outcome loop documents predicted impact versus actual outcome. Full H3 still
167
+ requires benchmark comparison output that attributes moved or regressed
168
+ responsibilities.
169
+
170
+ Activated responsibilities:
171
+
172
+ - Observability.
173
+ - Failure attribution.
174
+ - Entropy auditing.
175
+ - Intervention recording.
176
+
177
+ ### H4 - Automated Verification
178
+
179
+ The harness can run or orchestrate proof checks consistently and can reject or
180
+ flag incomplete work before the final response.
181
+
182
+ Criteria:
183
+
184
+ - A documented verification command or protocol runs the expected checks for a
185
+ selected story and lane.
186
+ - Stories can store and execute a `verify_command`.
187
+ - Trace recording warns when a linked story has a verification command that has
188
+ not passed.
189
+ - Missing validation evidence is surfaced before a task is marked implemented.
190
+
191
+ Required files:
192
+
193
+ - H3 files.
194
+ - A verification protocol or command reference.
195
+ - Validation report examples tied to story proof columns.
196
+ - Story verification command documentation.
197
+
198
+ Benchmark indicators:
199
+
200
+ - Functional score remains stable.
201
+ - Harness compliance: at least 90%.
202
+ - Fewer false "done" claims in benchmark review.
203
+ - Missing proof is detected before merge or final response.
204
+
205
+ Current status:
206
+
207
+ - Achieved by Phase 5. `scripts/bin/harness-cli story verify <id>` runs
208
+ story-level proof commands, records pass/fail state, `trace --story` warns
209
+ before close when verification has not passed, and
210
+ `scripts/bin/harness-cli story verify-all` runs all configured story proof
211
+ commands in one pass. Proof-column automation remains a future enhancement,
212
+ but H4's required automated verification gate is now present.
213
+
214
+ Activated responsibilities:
215
+
216
+ - Verification.
217
+ - Task state.
218
+ - Permissions.
219
+ - Intervention recording.
220
+
221
+ ### H5 - Self-Improving Harness
222
+
223
+ The harness can use traces, benchmark results, and backlog outcomes to propose
224
+ or apply safe improvements to itself.
225
+
226
+ Criteria:
227
+
228
+ - Repeated friction patterns are summarized into proposed harness changes.
229
+ - Proposed changes include predicted impact, risk, validation plan, and rollback
230
+ criteria.
231
+ - Completed changes compare predicted impact with actual benchmark or trace
232
+ outcomes.
233
+ - High-risk harness changes pause for human confirmation before changing source
234
+ hierarchy, architecture direction, or validation requirements.
235
+
236
+ Required files:
237
+
238
+ - H4 files.
239
+ - Self-improvement protocol.
240
+ - Historical improvement reports.
241
+ - Backlog outcome reviews.
242
+
243
+ Benchmark indicators:
244
+
245
+ - Harness compliance remains at least 90% across repeated benchmark runs.
246
+ - Trace quality remains at least 2.5/3.
247
+ - Improvements show measurable positive deltas or are explicitly reverted.
248
+ - Scope creep and validation weakening are caught by policy.
249
+
250
+ Current status:
251
+
252
+ - Partially achieved by Phase 5. `scripts/bin/harness-cli audit` detects
253
+ durable-state drift, `scripts/bin/harness-cli propose` generates structured
254
+ improvement proposals from friction, interventions, and audit results, and
255
+ `docs/IMPROVEMENT_PROTOCOL.md` defines the review loop. H5 is not fully
256
+ achieved until repeated benchmark outcomes prove proposed improvements create
257
+ measurable positive deltas or are explicitly reverted.
258
+
259
+ Activated responsibilities:
260
+
261
+ - Entropy auditing.
262
+ - Failure attribution.
263
+ - Intervention recording.
264
+ - Permissions.
265
+
266
+ ## Current Assessment
267
+
268
+ | Level | Status | Evidence |
269
+ | --- | --- | --- |
270
+ | H0 | Passed | Harness docs, templates, and durable records exist. |
271
+ | H1 | Achieved | `AGENTS.md`, `docs/HARNESS.md`, `docs/FEATURE_INTAKE.md`, `docs/ARCHITECTURE.md`, `docs/templates/*`, and `docs/TEST_MATRIX.md` exist. |
272
+ | H2 | Achieved | `scripts/bin/harness-cli`, `scripts/schema/001-init.sql`, durable story records, `docs/HARNESS_COMPONENTS.md`, `docs/HARNESS_MATURITY.md`, `docs/TRACE_SPEC.md`, and `docs/CONTEXT_RULES.md` define the Phase 2 surface. |
273
+ | H3 | Partial | Phase 3 adds `scripts/bin/harness-cli score-trace`, enriched friction context, and the backlog outcome loop; Phase 4 auto-scores traces on write. Component-level benchmark attribution remains open. |
274
+ | H4 | Achieved | Phase 4 adds story-level `verify_command`, `story verify`, and trace-time verification warnings. Phase 5 adds `story verify-all` for batch story proof. |
275
+ | H5 | Partial | Phase 5 adds `audit`, `score-context`, `intervention add/query`, `propose`, `docs/HARNESS_AUDIT.md`, and `docs/IMPROVEMENT_PROTOCOL.md`; repeated benchmark outcome proof remains open. |
276
+
277
+ ## Responsibility Activation
278
+
279
+ | Responsibility | H0 | H1 | H2 | H3 | H4 | H5 |
280
+ | --- | --- | --- | --- | --- | --- | --- |
281
+ | Task specification | Missing | Covered | Covered | Covered | Covered | Covered |
282
+ | Context selection | Missing | Partial | Covered | Covered | Covered | Covered |
283
+ | Tool access | Missing | Partial | Partial | Partial | Covered | Covered |
284
+ | Project memory | Missing | Covered | Covered | Covered | Covered | Covered |
285
+ | Task state | Missing | Partial | Covered | Covered | Covered | Covered |
286
+ | Observability | Missing | Missing | Partial | Covered | Covered | Covered |
287
+ | Failure attribution | Missing | Missing | Partial | Covered | Covered | Covered |
288
+ | Verification | Missing | Partial | Partial | Partial | Covered | Covered |
289
+ | Permissions | Missing | Partial | Partial | Partial | Covered | Covered |
290
+ | Entropy auditing | Missing | Missing | Partial | Covered | Covered | Covered |
291
+ | Intervention recording | Missing | Partial | Partial | Covered | Covered | Covered |
292
+
293
+ ## Phase 3 Interpretation
294
+
295
+ Phase 3 starts the H2 to H3 transition. It claims active trace scoring and a
296
+ documented improvement feedback loop, but it does not claim full H3 because
297
+ benchmark comparison and component-level regression attribution are explicitly
298
+ outside this repository's Phase 3 scope.
299
+
300
+ ## Phase 4 Interpretation
301
+
302
+ Phase 4 starts the H3 to H4 transition. It gives stories the same mechanical
303
+ verification pattern that decisions already had, records story verification
304
+ results in the durable layer, auto-scores traces when they are written, and
305
+ warns before close when a linked story's verification has not passed. It does
306
+ not claim full H4 because benchmark execution, batch verification, and automatic
307
+ proof-column updates remain separate work.
308
+
309
+ ## Phase 5 Interpretation
310
+
311
+ Phase 5 completes H4 by adding batch story verification and starts H5 by adding
312
+ tool discovery, intervention records, context scoring, drift audit, and
313
+ deterministic proposal generation. The repository may claim H5 partial only
314
+ when those commands and docs are present and validated; it must not claim full
315
+ H5 until benchmark runs or trace outcomes prove the proposal loop improves the
316
+ harness over time.
docs/IMPROVEMENT_PROTOCOL.md ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Improvement Protocol
2
+
3
+ Phase 5 starts the self-improvement loop:
4
+
5
+ ```text
6
+ friction + interventions + audit findings
7
+ -> harness-cli propose
8
+ -> proposed backlog item
9
+ -> human review
10
+ -> implementation with predicted impact
11
+ -> close with actual outcome
12
+ ```
13
+
14
+ ## Generate Proposals
15
+
16
+ ```bash
17
+ scripts/bin/harness-cli propose
18
+ ```
19
+
20
+ The command is rule-based. It looks for:
21
+
22
+ - repeated trace friction,
23
+ - repeated intervention patterns,
24
+ - non-zero audit categories.
25
+
26
+ Each proposal includes title, component, evidence, predicted impact, risk,
27
+ suggested action, validation plan, and confidence.
28
+
29
+ ## Commit Proposals
30
+
31
+ ```bash
32
+ scripts/bin/harness-cli propose --commit
33
+ ```
34
+
35
+ Committed proposals become `proposed` backlog items. Humans review them with:
36
+
37
+ ```bash
38
+ scripts/bin/harness-cli query backlog --open
39
+ ```
40
+
41
+ ## Review Rules
42
+
43
+ - Tiny proposals may be implemented directly when they only clarify docs.
44
+ - Normal proposals need a story packet or clear backlog acceptance.
45
+ - High-risk proposals need a durable decision record before changing source
46
+ hierarchy, architecture direction, validation requirements, or risk policy.
47
+ - Completed proposal work must close the backlog item with actual outcome
48
+ evidence.
49
+
50
+ ## Validation
51
+
52
+ After implementation, compare the predicted impact with:
53
+
54
+ - `scripts/bin/harness-cli audit`,
55
+ - `scripts/bin/harness-cli query friction`,
56
+ - `scripts/bin/harness-cli query interventions`,
57
+ - benchmark trace quality and harness compliance when benchmark proof applies.
docs/README.md ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath Documentation
2
+
3
+ Start every task with `AGENTS.md`. This index directs agents to the smallest
4
+ relevant context rather than every document in the repository.
5
+
6
+ ## Current Product and Work
7
+
8
+ - `product/` — accepted contracts for CarePath, Ghi chép bệnh án AI, and Phiên
9
+ dịch khám bệnh trực tiếp.
10
+ - `ux-redesign-carepath.md` — current Vietnamese-first UX implementation
11
+ backlog; required before UX or product-flow implementation.
12
+ - `onboarding-ux-fix-tasks.md` — current visual onboarding execution backlog.
13
+ - `../UI-FIX-PLAN.md` — current public-site issue plan.
14
+ - `deploy.md` — Hugging Face Space deployment instructions.
15
+
16
+ ## Harness: Read for Daily Work
17
+
18
+ - `HARNESS.md` — source hierarchy, task loop, and done definition.
19
+ - `FEATURE_INTAKE.md` — lane selection and CarePath hard gates.
20
+ - `ARCHITECTURE.md` — module and delivery boundaries.
21
+ - `CONTEXT_RULES.md` — minimum context by lane.
22
+ - `TEST_MATRIX.md` — behavior-to-proof baseline.
23
+ - `TRACE_SPEC.md` — durable completion evidence.
24
+ - `stories/`, `decisions/`, and `templates/` — selected work, settled
25
+ tradeoffs, and new-work starters.
26
+
27
+ ## Harness: Read Only When Triggered
28
+
29
+ - `TOOL_REGISTRY.md` — registering or using optional external tools.
30
+ - `HARNESS_AUDIT.md`, `HARNESS_COMPONENTS.md`, and `HARNESS_MATURITY.md` —
31
+ audit, observability, maturity, or benchmark work.
32
+ - `HARNESS_BACKLOG.md` and `IMPROVEMENT_PROTOCOL.md` — repeated Harness
33
+ friction or process improvements.
34
+ - `GLOSSARY.md` — extending shared Harness terminology.
35
+
36
+ ## Evidence and History
37
+
38
+ - `qa-evidence/` — versioned visual QA proof and its retention index.
39
+ - `history/` — preserved MVP, demo-site, unification, and review documents.
40
+ These are context only; do not reopen completed tickets as current work.
docs/TEST_MATRIX.md ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath Test Matrix
2
+
3
+ This matrix maps the current CarePath baseline to proof. Status changes only
4
+ after the named evidence is actually run and recorded.
5
+
6
+ | Story | Contract | Unit | Integration | E2E | Platform | Status | Evidence |
7
+ | --- | --- | --- | --- | --- | --- | --- | --- |
8
+ | CP-BASE-001 | Unified API and Ghi chép bệnh án AI remain available | yes | yes | no | no | implemented | 96 passed, 1 skipped; mock smoke passed (2026-07-12) |
9
+ | CP-BASE-002 | Interpreter remains translate-only and fail-closed | yes | yes | yes | no | implemented | Ruff; 109 passed, 1 skipped; mock eval 50/50; 4 browser tests passed (2026-07-12) |
10
+ | CP-BASE-003 | Public CarePath site remains Vietnamese-first and deployable | yes | no | yes | yes | implemented | 45 unit, 5 deploy-env, 7 browser tests; Lighthouse 100/100/100 (2026-07-12) |
11
+ | CP-BASE-004 | Interpreter console remains buildable and usable | yes | no | yes | no | implemented | lint; 38 unit; build; 4 browser tests passed (2026-07-12) |
12
+ | GEC-001 | Offline GEC training uses ViMedCSS and synthetic pairs without human-labeling tooling | no | yes | no | no | implemented | Ruff; 26 focused GEC tests; root 95 passed, 1 skipped (2026-07-12) |
13
+ | HARN-001 | Agent work follows durable CarePath intake and proof rules | no | yes | no | no | implemented | pinned merge install, CLI 0.1.11, init, matrix, audit, trace (2026-07-12) |
14
+
15
+ Proof labels mean the relevant layer has evidence for the baseline; they do not
16
+ claim every historical behavior was retested. Story packets define the exact
17
+ commands for future changes.
docs/TOOL_REGISTRY.md ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Tool Registry
2
+
3
+ The harness deals with two distinct kinds of "tool". Keep them separate.
4
+
5
+ | | Capability manifest (outbound) | Inbound tool registry |
6
+ | --- | --- | --- |
7
+ | Direction | harness offers it to the agent | a project equips it for the harness to use |
8
+ | Examples | the `harness-cli` subcommands below | gitnexus, c3, a linter, a deploy check |
9
+ | Presence | always compiled in | optional; may be absent on any machine |
10
+ | If missing | n/a (it is the harness) | clean skip; never blocks the main process |
11
+
12
+ This document describes both. The **inbound registry** is the extension base:
13
+ it is where the harness learns what extra capability is equipped, what purpose
14
+ it serves, and whether it is actually present right now, so a workflow step can
15
+ adapt to what is installed without the core ever depending on it.
16
+
17
+ ## Inbound Registry: Register A Tool
18
+
19
+ ```bash
20
+ scripts/bin/harness-cli tool register \
21
+ --name deploy-check \
22
+ --kind cli \
23
+ --capability deploy-verification \
24
+ --command ./scripts/deploy-check.sh \
25
+ --description "Verify deploy health before release" \
26
+ --responsibility Verification \
27
+ --args "env:enum:required:staging,production"
28
+ ```
29
+
30
+ Fields specific to inbound tools:
31
+
32
+ - `--kind` — how the tool is reached and probed. One of `cli`, `binary`, `mcp`,
33
+ `skill`, `http`. Defaults to `cli`. The kind tells each agent runtime what it
34
+ can orchestrate (a non-Claude agent simply treats a `skill` it cannot run as
35
+ absent) and tells `tool check` which probe to use.
36
+ - `--capability` — the workflow purpose a step looks the tool up by. Free-text
37
+ but normalized to kebab-case, so `Impact Analysis`, `impact_analysis`, and
38
+ `impact-analysis` all register as `impact-analysis`. This is the only coupling
39
+ between a step and a tool; steps reference the capability, never the tool name.
40
+ - `--scan` — for `mcp`/`skill`/`http`, a declarative path or URL that
41
+ `tool check` resolves to decide presence (e.g. `.c3`, `~/.claude/skills/c3`,
42
+ `https://localhost:8080/health`). `cli`/`binary` are probed via their command.
43
+
44
+ `--force` is only needed for `cli`/`binary` whose command is intentionally
45
+ absent on the current machine. `mcp`/`skill`/`http` are not on `PATH` by nature,
46
+ so they register without `--force`; their presence is resolved later by
47
+ `tool check`.
48
+
49
+ Registering an MCP server or a Claude skill (examples):
50
+
51
+ ```bash
52
+ scripts/bin/harness-cli tool register --name gitnexus --kind mcp \
53
+ --capability impact-analysis --scan ".gitnexus" --command "mcp:gitnexus" \
54
+ --description "Code-graph blast radius" --responsibility Verification
55
+ scripts/bin/harness-cli tool register --name c3 --kind skill \
56
+ --capability impact-analysis --scan ".c3" --command "skill:c3" \
57
+ --description "Component model and drift audit (Claude skill)" \
58
+ --responsibility Verification
59
+ ```
60
+
61
+ Remove a tool with:
62
+
63
+ ```bash
64
+ scripts/bin/harness-cli tool remove --name deploy-check
65
+ ```
66
+
67
+ ## Inbound Registry: Check Presence
68
+
69
+ Registration records intent. `tool check` reconciles intent with reality by
70
+ scanning each registered tool and persisting the verdict (`status` and
71
+ `checked_at`). Run it at intake start so status reflects current reality.
72
+
73
+ ```bash
74
+ scripts/bin/harness-cli tool check # scan all registered tools
75
+ scripts/bin/harness-cli tool check --name c3 # scan one
76
+ scripts/bin/harness-cli tool check --json # machine-readable for agents
77
+ ```
78
+
79
+ Probe per kind:
80
+
81
+ | Kind | Probe | `present` means |
82
+ | --- | --- | --- |
83
+ | `cli`, `binary` | command resolves on `PATH` or as a path | installed and runnable |
84
+ | `mcp`, `skill` | `scan_target` path resolves (`~` expands) | equipped/configured on disk |
85
+ | `http` | `scan_target` reachable over TCP (2s), else path | endpoint answers |
86
+
87
+ `tool check` always exits `0`: a missing extension is a fact to report, not a
88
+ CLI failure. A `cli`/`binary` is `present` when runnable. An `mcp`/`skill`/`http`
89
+ `present` means **equipped** (config/file resolves), not **live this session** —
90
+ the agent still confirms live usability at call time, since only the agent
91
+ runtime can see whether its MCP server is actually connected. With no
92
+ `scan_target`, the status is `unknown` and the agent must confirm.
93
+
94
+ ## Inbound Registry: Look Up By Capability
95
+
96
+ A workflow step asks "what is present for this purpose?" rather than naming a
97
+ tool:
98
+
99
+ ```bash
100
+ scripts/bin/harness-cli query tools --capability impact-analysis
101
+ scripts/bin/harness-cli query tools --capability impact-analysis --status present
102
+ ```
103
+
104
+ The result is the set of providers. Multiple tools may provide one capability
105
+ (gitnexus and c3 both serve `impact-analysis` and are complementary), so a step
106
+ reads the set and degrades on how much of it is present.
107
+
108
+ ### Degrade Ladder
109
+
110
+ The CLI reports facts (`status`); the agent applies policy. The generic rule,
111
+ keyed on the present-provider count for a capability:
112
+
113
+ | Providers present | Posture | Agent behavior |
114
+ | --- | --- | --- |
115
+ | none registered | Inactive | clean skip; note `capability X: inactive` in the trace. Not drift. |
116
+ | registered but none/some present | Degraded | run with what resolves; set the `Weak proof` flag; note the gap. |
117
+ | all present | Full | normal operation. |
118
+
119
+ A registered tool that scans as `missing` is a failed validity gate, not a skip.
120
+ A capability with no registered providers is simply inactive and is skipped
121
+ without penalty — this is what keeps the core seamless on a fresh install.
122
+
123
+ ### Recommended Capability Vocabulary
124
+
125
+ Capability is open (no code change to add one), but a step and its providers
126
+ must agree on the exact string. Reuse these where they fit before coining a new
127
+ one; coin new ones in kebab-case:
128
+
129
+ ```
130
+ impact-analysis · deploy-verification · coverage · security-scan
131
+ performance-benchmark · documentation-lookup
132
+ ```
133
+
134
+ ## Inspecting The Registry
135
+
136
+ ```bash
137
+ scripts/bin/harness-cli query tools --summary
138
+ scripts/bin/harness-cli query tools --json
139
+ scripts/bin/harness-cli query tools --responsibility Verification
140
+ ```
141
+
142
+ JSON records carry `kind`, `capability`, `scan_target`, `status`, and
143
+ `checked_at` alongside the existing fields, so any agent can read the registry
144
+ without parsing the human table.
145
+
146
+ ## Compiled Harness Commands (Outbound Manifest)
147
+
148
+ | Command | Responsibility | Purpose | Arguments |
149
+ | --- | --- | --- | --- |
150
+ | `init` | Task state | Create the harness database. | none |
151
+ | `migrate` | Task state | Apply pending schema migrations. | none |
152
+ | `import brownfield` | Project memory | Seed durable records from markdown state. | none |
153
+ | `intake` | Task specification | Record a feature intake classification. | `--type`, `--summary`, `--lane` |
154
+ | `story add` | Task state | Create a durable story record. | `--id`, `--title`, `--lane`, optional `--verify` |
155
+ | `story update` | Task state | Update story status, proof flags, evidence, or verification command. | `--id`, optional proof/status fields |
156
+ | `story verify` | Verification | Run one story `verify_command` and record pass/fail. | story id |
157
+ | `story verify-all` | Verification | Run all configured story verification commands and skip stories without one. | none |
158
+ | `decision add` | Project memory | Create a durable decision record. | `--id`, `--title`, optional `--doc`, `--verify` |
159
+ | `decision verify` | Verification | Run one decision verification command. | decision id |
160
+ | `backlog add` | Entropy auditing | Record a harness improvement proposal. | `--title`, optional pain/suggestion/risk/predicted fields |
161
+ | `backlog close` | Entropy auditing | Close a backlog item with outcome evidence. | `--id`, optional `--status`, `--outcome` |
162
+ | `tool register` | Tool access | Register an external project tool. | `--name`, `--command`, `--description`, `--responsibility`, optional `--kind`, `--capability`, `--scan`, `--args`, `--force` |
163
+ | `tool check` | Tool access | Scan registered tools and persist present/missing/unknown status. | optional `--name`, `--json` |
164
+ | `tool remove` | Tool access | Remove a registered external tool. | `--name` |
165
+ | `intervention add` | Intervention recording | Record a human, reviewer, CI, or agent intervention. | `--type`, `--description`, `--source`, optional `--trace`, `--story`, `--impact` |
166
+ | `trace` | Observability | Record an agent execution trace and print trace quality. | `--summary`, optional trace fields |
167
+ | `score-trace` | Observability | Score trace detail against lane requirements. | optional `--id` |
168
+ | `score-context` | Context selection | Score trace reads against compiled context rules. | trace id |
169
+ | `audit` | Entropy auditing | Run drift checks and compute entropy score. | none |
170
+ | `propose` | Entropy auditing | Generate improvement proposals from friction, interventions, and audit findings. | optional `--commit` |
171
+ | `query matrix` | Task state | Show durable story proof matrix. | optional `--numeric` |
172
+ | `query backlog` | Entropy auditing | Show harness improvement backlog. | optional `--open`, `--closed` |
173
+ | `query decisions` | Project memory | Show durable decision records. | none |
174
+ | `query intakes` | Task specification | Show recent intake records. | none |
175
+ | `query traces` | Observability | Show recent trace records. | none |
176
+ | `query friction` | Failure attribution | Show traces with harness friction. | none |
177
+ | `query tools` | Tool access | Show compiled and registered tool entries. | optional `--json`, `--summary`, `--responsibility`, `--capability`, `--status` |
178
+ | `query interventions` | Intervention recording | Show intervention records. | optional `--trace`, `--story`, `--type` |
179
+ | `query stats` | Task state | Show durable record counts. | none |
180
+ | `query sql` | Tool access | Run arbitrary SQL against `harness.db`. | SQL text |
181
+ | `db changeset apply` | Task state | Apply one semantic changeset idempotently. | changeset path |
182
+ | `db rebuild` | Task state | Rebuild a fresh `harness.db` from semantic changesets. | `--from` changeset directory |
183
+
184
+ ## Validation Rules
185
+
186
+ - Tool names must be unique among registered tools.
187
+ - Descriptions must be 10-200 characters.
188
+ - Responsibilities must match the Runtime Substrate responsibility list.
189
+ - `--kind` must be one of `cli`, `binary`, `mcp`, `skill`, `http`.
190
+ - `--capability` must be kebab-case (lowercase letters, digits, single hyphens);
191
+ spaces and underscores are normalized to hyphens.
192
+ - `--args` entries must use `name:type:required` or
193
+ `name:type:required:help`, with `required` or `optional` as the third field.
194
+ - For `cli`/`binary`, the command must exist as a path or on `PATH`, unless
195
+ `--force` is supplied. `mcp`/`skill`/`http` skip this check.
docs/TRACE_SPEC.md ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Trace Specification
2
+
3
+ The `trace` table records what happened during a Harness task. This document
4
+ defines the expected depth and format for each field so traces are useful for
5
+ review, benchmark scoring, failure attribution, and future harness evolution.
6
+
7
+ The current schema lives in `scripts/schema/001-init.sql` under the `trace`
8
+ table. The schema is not changed by Phase 2.
9
+
10
+ ## Field Reference
11
+
12
+ | Field | Type | Required | Format | Example |
13
+ | --- | --- | --- | --- | --- |
14
+ | `id` | INTEGER | Automatic | SQLite autoincrement primary key. Do not set manually. | `42` |
15
+ | `created_at` | TEXT | Automatic | SQLite `datetime('now')`. Do not set manually. | `2026-05-27 09:24:37` |
16
+ | `task_summary` | TEXT | Yes | One sentence, at least 10 characters, naming the outcome or attempted outcome. | `Completed Phase 2 docs-only observability and taxonomy specification` |
17
+ | `intake_id` | INTEGER | Standard+ when an intake was recorded | Integer id from the related `intake` row. | `36` |
18
+ | `story_id` | TEXT | Standard+ when work maps to one story | Story id from the `story` table. Use the main story when one trace covers several; list the rest in `notes`. | `US-004` |
19
+ | `agent` | TEXT | Optional for minimal; Standard+ expected | Short agent/tool name. | `codex` |
20
+ | `actions_taken` | TEXT | Standard+ | JSON array text. With the current CLI, pass a comma-separated list and the CLI stores JSON text. | `["read PHASE2.md","drafted TRACE_SPEC.md","updated HARNESS.md"]` |
21
+ | `files_read` | TEXT | Standard+ | JSON array text of paths or command names. With the current CLI, pass a comma-separated list. | `["PHASE2.md","docs/HARNESS.md","scripts/bin/harness-cli query matrix"]` |
22
+ | `files_changed` | TEXT | Standard+ | JSON array text of changed file paths. With the current CLI, pass a comma-separated list; omit only when no files changed. | `["docs/TRACE_SPEC.md","docs/HARNESS.md"]` |
23
+ | `decisions_made` | TEXT | Detailed | JSON array text of decision strings. Include scope decisions, validation choices, and explicit non-goals. | `["Kept Phase 2 docs-only; installer propagation remains out of scope"]` |
24
+ | `errors` | TEXT | Standard+ if errors occurred; Detailed always | JSON array text of error or blocker strings. Until the CLI supports empty arrays directly, use `none` when a detailed trace needs explicit no-error evidence. | `["git diff --check failed before whitespace fix"]` |
25
+ | `outcome` | TEXT | Yes before final response | One of `completed`, `blocked`, `partial`, or `failed`. | `completed` |
26
+ | `duration_seconds` | INTEGER | Detailed when available | Positive integer estimate or measured duration. Leave null if unknown. | `1800` |
27
+ | `token_estimate` | INTEGER | Detailed when available | Positive integer estimate. Leave null if unknown. | `24000` |
28
+ | `harness_friction` | TEXT | Standard+ when friction exists; Detailed always | Free text naming what was hard, missing, ambiguous, or repeated. Use `none` only when the agent actively checked and found no friction. | `New Phase 2 docs are not in installer copy list; recorded as out-of-scope follow-up.` |
29
+ | `notes` | TEXT | Optional | Free text for review context that does not fit other fields. | `Trace covers US-003, US-004, US-005, and US-006.` |
30
+
31
+ ## Quality Tiers
32
+
33
+ ### Minimal (score: 1)
34
+
35
+ Minimum fields:
36
+
37
+ - `task_summary` is filled and at least 10 characters.
38
+ - `outcome` is filled before the final response.
39
+
40
+ Acceptable for:
41
+
42
+ - Tiny-lane tasks with no file changes or only low-risk copy/doc edits.
43
+
44
+ Not acceptable for:
45
+
46
+ - Normal or high-risk work.
47
+ - Any work that discovered friction, errors, or a missing validation path.
48
+
49
+ ### Standard (score: 2)
50
+
51
+ Minimum fields:
52
+
53
+ - All Minimal fields.
54
+ - `intake_id` when an intake was recorded.
55
+ - `story_id` when the work maps cleanly to one story.
56
+ - `agent`.
57
+ - `actions_taken` as JSON array text.
58
+ - `files_read` as JSON array text.
59
+ - `files_changed` as JSON array text.
60
+ - At least one of `errors` or `harness_friction`.
61
+
62
+ Required for:
63
+
64
+ - Normal-lane tasks.
65
+ - Tiny tasks that changed Harness instructions, validation expectations, or
66
+ durable records.
67
+
68
+ Standard traces may leave `duration_seconds`, `token_estimate`, and
69
+ `decisions_made` empty when those details are not useful.
70
+
71
+ ### Detailed (score: 3)
72
+
73
+ Minimum fields:
74
+
75
+ - All Standard fields.
76
+ - `decisions_made` as JSON array text.
77
+ - `errors` as JSON array text, using `none` with the current CLI when no
78
+ errors occurred.
79
+ - `harness_friction`, using `none` only after checking for friction.
80
+ - `duration_seconds` or a note explaining why duration is unavailable.
81
+ - `token_estimate` or a note explaining why token estimate is unavailable.
82
+ - `notes` when one trace covers multiple stories, multiple risk flags, or
83
+ skipped validation.
84
+
85
+ Required for:
86
+
87
+ - High-risk tasks.
88
+ - Changes touching architecture direction, source-of-truth hierarchy,
89
+ validation requirements, auth, authorization, data loss, audit/security, or
90
+ external provider behavior.
91
+ - Benchmark or release work where later review needs precise proof.
92
+
93
+ For high-risk work, `decisions_made` in the trace summarizes what was decided.
94
+ It does not replace a durable decision record. If the work changes behavior,
95
+ architecture, authorization, data ownership, API shape, or validation
96
+ requirements, add a `docs/decisions/NNNN-*.md` file and record it with
97
+ `scripts/bin/harness-cli decision add`.
98
+
99
+ ## Lane Mapping
100
+
101
+ | Lane | Expected Tier | Minimum Trace Behavior |
102
+ | --- | --- | --- |
103
+ | Tiny | Minimal | Record summary and outcome; use Standard if friction or Harness docs changed. |
104
+ | Normal | Standard | Record intake, actions, files read, files changed, outcome, and friction/errors. |
105
+ | High-risk | Detailed | Record all fields or explicitly explain unavailable duration/token estimates. |
106
+
107
+ ## Friction Capture Protocol
108
+
109
+ Populate `harness_friction` when any of these occur:
110
+
111
+ - The agent had to infer a missing rule or source of truth.
112
+ - Required validation was unclear, unavailable, or too expensive to run.
113
+ - A document, durable record, or story packet was stale or contradictory.
114
+ - The task revealed a repeated manual step that should become a template,
115
+ command, or checklist.
116
+ - A requested change was out of scope but likely important later.
117
+ - A benchmark or review failure could not be attributed to a component.
118
+
119
+ How to write friction:
120
+
121
+ - Name the concrete pain, not a vague mood.
122
+ - Include the missing capability or contradiction.
123
+ - If the friction should become work, also add or update a backlog item with
124
+ `scripts/bin/harness-cli backlog add`.
125
+ - If there was no friction, use `none` only for Detailed traces.
126
+
127
+ Good friction:
128
+
129
+ ```text
130
+ New Phase 2 docs are not copied by scripts/install-harness.sh, but installer
131
+ propagation is out of scope for docs-only Phase 2.
132
+ ```
133
+
134
+ Weak friction:
135
+
136
+ ```text
137
+ docs confusing
138
+ ```
139
+
140
+ ## Examples
141
+
142
+ ### Good Trace (Detailed)
143
+
144
+ ```bash
145
+ scripts/bin/harness-cli trace \
146
+ --summary "Completed high-risk auth role migration with audit proof" \
147
+ --intake 51 \
148
+ --story US-014 \
149
+ --agent codex \
150
+ --outcome completed \
151
+ --duration 4200 \
152
+ --tokens 52000 \
153
+ --actions "read access-control docs,created migration,updated audit tests,ran integration suite" \
154
+ --read "docs/product/permissions.md,docs/decisions/0008-auth-boundary.md,src/auth/roles.ts" \
155
+ --changed "src/auth/roles.ts,src/audit/events.ts,tests/auth-roles.test.ts" \
156
+ --decisions "kept manager role scoped to workspace,recorded audit event on every role change" \
157
+ --errors "none" \
158
+ --friction "Existing permission docs did not define delegated admin; added backlog item for role glossary." \
159
+ --notes "Detailed trace required because the task touched authorization and audit behavior."
160
+ ```
161
+
162
+ ### Adequate Trace (Standard)
163
+
164
+ ```bash
165
+ scripts/bin/harness-cli trace \
166
+ --summary "Added Phase 2 trace specification and Harness reference" \
167
+ --intake 36 \
168
+ --story US-004 \
169
+ --agent codex \
170
+ --outcome completed \
171
+ --actions "read PHASE2.md,drafted TRACE_SPEC.md,updated HARNESS.md,ran rg checks" \
172
+ --read "PHASE2.md,docs/HARNESS.md,scripts/schema/001-init.sql" \
173
+ --changed "docs/TRACE_SPEC.md,docs/HARNESS.md" \
174
+ --friction "none"
175
+ ```
176
+
177
+ ### Insufficient Trace
178
+
179
+ ```bash
180
+ scripts/bin/harness-cli trace \
181
+ --summary "did phase 2" \
182
+ --outcome completed
183
+ ```
184
+
185
+ Why this is insufficient for normal-lane Phase 2 work:
186
+
187
+ - It does not identify actions.
188
+ - It does not list files read or changed.
189
+ - It does not connect to intake or stories.
190
+ - It gives no friction or error signal.
191
+
192
+ ## Review Checklist
193
+
194
+ Before the final response, check:
195
+
196
+ - The trace tier matches the lane.
197
+ - Review the score printed automatically by `scripts/bin/harness-cli trace`.
198
+ Use `scripts/bin/harness-cli score-trace --id N` when re-checking a specific
199
+ historical trace.
200
+ - `files_changed` matches the actual changed-file set at a useful level.
201
+ - `errors` names real blockers or is `none` for Detailed traces when the
202
+ current CLI is used.
203
+ - `harness_friction` either names a concrete issue or is intentionally `none`.
204
+ - Any friction that should become future work is recorded in the backlog.
docs/decisions/0001-harness-first-development.md ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0001 Harness-First Development
2
+
3
+ Date: 2026-05-05
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ The repository currently contains a product README and a large product
12
+ specification. There is no application implementation yet.
13
+
14
+ The project will likely involve human direction plus agent implementation over
15
+ many evolving stories. A single massive specification is not enough for safe
16
+ agent work because it becomes hard to locate current truth, risk, proof, and
17
+ change history.
18
+
19
+ ## Decision
20
+
21
+ Create Harness v0 before scaffolding product code.
22
+
23
+ Harness v0 defines:
24
+
25
+ - Agent entrypoint.
26
+ - Product doc split.
27
+ - Feature intake and risk lanes.
28
+ - Story packet templates.
29
+ - Decision records.
30
+ - Test matrix.
31
+ - Harness backlog.
32
+
33
+ No application code, fake scripts, CI, or tests are created in this decision.
34
+
35
+ ## Consequences
36
+
37
+ Positive:
38
+
39
+ - Agents have a clear operating model before implementation starts.
40
+ - Product truth can split away from the massive spec.
41
+ - Risky work has a slower lane before code changes.
42
+ - Harness growth becomes part of the work.
43
+
44
+ Tradeoffs:
45
+
46
+ - Some docs are placeholders until real stories exercise them.
47
+ - Validation commands are only contracts until implementation begins.
48
+ - The harness must stay small enough to revise from real friction.
docs/decisions/0002-post-spec-product-lifecycle.md ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0002 Seed Specification Product Lifecycle
2
+
3
+ Date: 2026-05-05
4
+
5
+ ## Status
6
+
7
+ Superseded by `0003-generic-spec-intake-harness.md`
8
+
9
+ ## Context
10
+
11
+ Harness v0 originally assumed the repository would include one seed
12
+ specification file for the first product. This decision explained how agents
13
+ should decompose that initial specification into product docs, story packets,
14
+ implementation, and validation proof, then continue working after the seed was
15
+ exhausted.
16
+
17
+ That approach fit a single project but made the harness less reusable.
18
+
19
+ ## Decision
20
+
21
+ Treat the initial specification as a seed and historical snapshot, not the
22
+ permanent living product plan.
23
+
24
+ After the initial specification has been exhausted, new work should enter
25
+ through the same harness loop as one of these input types:
26
+
27
+ - Change request.
28
+ - New initiative.
29
+ - Maintenance request.
30
+ - Harness improvement.
31
+
32
+ Product docs under `docs/product/`, story packets under `docs/stories/`,
33
+ validation evidence in `docs/TEST_MATRIX.md`, and decision records under
34
+ `docs/decisions/` become the living operating surface.
35
+
36
+ Large future product areas should be captured as scoped initiative notes instead
37
+ of appended to the seed specification or rewritten as a second monolithic spec.
38
+
39
+ ## Consequences
40
+
41
+ Positive:
42
+
43
+ - The original specification remains stable as historical context.
44
+ - Product truth moves into smaller, current, maintainable files.
45
+ - Future work keeps using the same intake, story, proof, and harness-growth
46
+ loop.
47
+ - Large ideas can still be planned without creating another oversized spec.
48
+
49
+ Tradeoffs:
50
+
51
+ - The repository will eventually need an initiative template if large new
52
+ product areas become common.
53
+ - Agents must be careful to update product docs and tests rather than relying on
54
+ the seed specification after initial buildout.
docs/decisions/0003-generic-spec-intake-harness.md ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0003 Generic Spec Intake Harness
2
+
3
+ Date: 2026-05-05
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Harness v0 originally shipped with a project-specific `SPEC.md`, product docs,
12
+ candidate epics, architecture assumptions, and validation examples. That made
13
+ the harness useful for the first project but too specific to reuse as the outer
14
+ shell for a new project.
15
+
16
+ The desired direction is a default harness that can wait for any user-provided
17
+ spec, derive product docs from that spec, and then continue with the same
18
+ intake, story, proof, and decision loop.
19
+
20
+ ## Decision
21
+
22
+ Remove the tracked project-specific spec and pre-sliced product domains from
23
+ Harness v0.
24
+
25
+ The harness now starts with:
26
+
27
+ - No baked-in `SPEC.md`.
28
+ - Empty product docs except for intake guidance.
29
+ - Generic story and epic examples.
30
+ - Stack-neutral architecture discovery rules.
31
+ - Stack-neutral validation columns.
32
+ - A source hierarchy that treats a future user-provided spec as input material,
33
+ not permanent living truth.
34
+
35
+ ## Alternatives Considered
36
+
37
+ 1. Keep the original `SPEC.md` as an example. Rejected because examples can be
38
+ mistaken for current product truth.
39
+ 2. Move the original product docs into an examples folder. Rejected for now
40
+ because the user asked for a clean default harness.
41
+
42
+ ## Consequences
43
+
44
+ Positive:
45
+
46
+ - The repository is easier to reuse for any new project.
47
+ - Future specs can define their own product domains and stack.
48
+ - Agents are less likely to confuse template truth with product truth.
49
+
50
+ Tradeoffs:
51
+
52
+ - The harness has fewer concrete examples until the next spec is supplied.
53
+ - The first spec intake must create product docs and candidate epics before
54
+ implementation planning can be precise.
55
+
56
+ ## Follow-Up
57
+
58
+ - Add a spec-intake template if repeated projects reveal a stable format.
docs/decisions/0004-sqlite-durable-layer.md ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0004 SQLite Durable Layer
2
+
3
+ Date: 2026-05-22
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Harness v0 stores all operational data in markdown files: `TEST_MATRIX.md` rows,
12
+ `HARNESS_BACKLOG.md` items, decision records, and story status. This works for
13
+ human reading but creates friction for agents:
14
+
15
+ - Editing markdown tables is error-prone and hard to validate.
16
+ - There is no structured way to query past intakes, traces, or friction reports.
17
+ - The harness has no observability foundation for future evolution.
18
+
19
+ Recent research on harness engineering (arXiv:2604.25850, arXiv:2605.13357,
20
+ arXiv:2603.28052) identifies observability and structured traces as the
21
+ foundation for harness improvement. All three approaches require queryable
22
+ operational data, not prose documents.
23
+
24
+ ## Decision
25
+
26
+ Add a SQLite database (`harness.db`) and a thin CLI (`scripts/bin/harness-cli`) as the
27
+ durable layer for operational harness data.
28
+
29
+ The database stores:
30
+
31
+ - **Intake records**: classification of incoming work.
32
+ - **Stories**: work packets and their validation proof status (replaces manual
33
+ `TEST_MATRIX.md` rows).
34
+ - **Decisions**: durable records with optional verification commands.
35
+ - **Backlog items**: harness improvement proposals with predicted and actual
36
+ impact.
37
+ - **Traces**: agent execution records including actions, files, errors, outcome,
38
+ and harness friction.
39
+
40
+ The schema is version-controlled under `scripts/schema/`. The database file is
41
+ `.gitignore`d because each project instance generates its own operational data.
42
+
43
+ Policy docs (`HARNESS.md`, `FEATURE_INTAKE.md`, `ARCHITECTURE.md`) remain as
44
+ human-readable references. The database stores what agents produce, not what
45
+ they should do.
46
+
47
+ ## Alternatives Considered
48
+
49
+ 1. Keep everything in markdown. Rejected because it prevents structured queries,
50
+ makes observability impossible, and forces agents to edit fragile tables.
51
+ 2. Use JSON files. Rejected because concurrent writes are unsafe and queries
52
+ require custom tooling.
53
+ 3. Use a full database server. Rejected because it adds deployment complexity
54
+ that does not match Harness v0 scope.
55
+
56
+ ## Consequences
57
+
58
+ Positive:
59
+
60
+ - Agents record structured data instead of editing markdown tables.
61
+ - Intake, story, decision, backlog, and trace data is queryable.
62
+ - The harness has an observability foundation for future evolution.
63
+ - Schema migrations enable the durable layer to grow with the harness.
64
+
65
+ Tradeoffs:
66
+
67
+ - Requires `sqlite3` to be available in the environment.
68
+ - The database is not version-controlled, so each instance starts empty.
69
+ - Markdown docs and the database may drift if agents use one but not the other.
70
+
71
+ ## Follow-Up
72
+
73
+ - Seed existing decisions (0001-0003) into the database during init.
74
+ - Add context engineering rules keyed by task type and risk lane.
75
+ - Add harness maturity ladder (H0-H4) once the durable layer proves useful.
docs/decisions/0005-prebuilt-rust-harness-cli.md ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0005 Prebuilt Rust Harness CLI
2
+
3
+ Date: 2026-05-23
4
+
5
+ ## Status
6
+
7
+ Accepted, amended 2026-05-31, amended 2026-06-09
8
+
9
+ ## Context
10
+
11
+ The durable layer started as a thin shell wrapper around SQLite. That wrapper
12
+ is now large enough to carry meaningful architecture risk: it mixes command
13
+ parsing, SQL construction, migrations, import behavior, query rendering, and
14
+ help text in one script.
15
+
16
+ The previous installer copied a shell wrapper into target repositories. That
17
+ kept Harness easy to install, but it also meant a Rust rewrite was not only an
18
+ implementation change. It changed the distribution contract for every project
19
+ that receives Harness.
20
+
21
+ ## Decision
22
+
23
+ The future Rust implementation of the Harness CLI should be shipped as a
24
+ prebuilt binary downloaded by the installer.
25
+
26
+ The command path for users and agents is the installed Rust binary:
27
+
28
+ ```bash
29
+ scripts/bin/harness-cli <command>
30
+ ```
31
+
32
+ On Windows, the repository-local binary is installed as:
33
+
34
+ ```powershell
35
+ .\scripts\bin\harness-cli.exe <command>
36
+ ```
37
+
38
+ The installer should download, verify, and install the platform-specific Rust
39
+ binary directly at that path. There should be no shell wrapper command contract.
40
+
41
+ The Rust CLI should follow the existing architecture rules:
42
+
43
+ - Domain: harness records, statuses, lanes, and value types.
44
+ - Application: use cases for intake, stories, decisions, backlog, traces, and
45
+ queries.
46
+ - Infrastructure: SQLite repositories and schema migrations.
47
+ - Interface: command-line parsing, terminal output, and installer integration.
48
+
49
+ Release automation now follows the same distribution contract. After a PR is
50
+ merged to `main`, the post-merge maintenance workflow updates `CHANGELOG.md`.
51
+ When the merged PR changed the Rust CLI source, schema, Cargo metadata, or CLI
52
+ release packaging, it also bumps the CLI patch version, updates the installer
53
+ release tag pin, creates a `harness-cli-v*` tag, and invokes the reusable
54
+ Harness CLI release workflow for that tag.
55
+
56
+ ## Alternatives Considered
57
+
58
+ 1. Keep the shell CLI permanently. Rejected because the script has crossed from
59
+ a thin wrapper into a growing application surface with weak testability.
60
+ 2. Copy Rust source into every target project and build locally. Rejected
61
+ because it makes Harness installation depend on a local Rust toolchain and
62
+ increases setup friction for projects that only need the harness.
63
+ 3. Require users to install a global `harness` binary separately. Rejected
64
+ because Harness should remain repository-local for agents.
65
+ 4. Download a prebuilt binary through the installer. Accepted because it keeps
66
+ target repos simple while allowing the CLI internals to become typed,
67
+ testable, and platform-aware.
68
+
69
+ ## Consequences
70
+
71
+ Positive:
72
+
73
+ - The durable-layer CLI can move to typed command parsing and tested use cases.
74
+ - Target projects do not need a Rust toolchain just to use Harness.
75
+ - The `scripts/bin/harness-cli` command is the stable entrypoint for agents on
76
+ macOS/Linux; Windows uses the same repo-local path with the `.exe` suffix.
77
+ - Prebuilt releases can include a known SQLite linkage strategy.
78
+
79
+ Tradeoffs:
80
+
81
+ - The installer must learn platform detection and binary download behavior.
82
+ - Release artifacts need checksums or another integrity check.
83
+ - Unsupported platforms need a clear error path.
84
+ - The project needs a repeatable release process for supported platforms.
85
+
86
+ ## Follow-Up
87
+
88
+ - Implement the migration through `US-002 Rust Harness CLI`.
89
+ - Remove the old shell wrapper from installed project payloads.
90
+ - Add checksum verification for downloaded binaries.
91
+ - Treat the Rust CLI as the primary durable-layer implementation.
docs/decisions/0006-phase-4-benchmark-triage.md ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0006 Phase 4 Benchmark Triage
2
+
3
+ Date: 2026-05-31
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ The first Phase 4 benchmark re-run found that T4 authentication failed
12
+ `decision_recorded` even though the trace included decisions text. The same run
13
+ also showed command churn from agents trying `story update` proof flags with
14
+ `yes` and `no`, and trying to use `story verify` as if it accepted proof flags.
15
+
16
+ ## Decision
17
+
18
+ Harness instructions and CLI help must distinguish durable records from trace
19
+ evidence and must show the current Rust CLI command shape at the point agents
20
+ need it:
21
+
22
+ - High-risk behavior changes require a markdown decision under
23
+ `docs/decisions/` and a durable `decision` row.
24
+ - Trace `--decisions` is evidence for trace quality, not the decision log.
25
+ - `story update` proof flags use `1` and `0`.
26
+ - `story verify <id>` only runs the configured `verify_command`; proof flags
27
+ stay on `story update`.
28
+
29
+ ## Alternatives Considered
30
+
31
+ 1. Rely on trace auto-scoring to catch the missing T4 decision. Rejected because
32
+ trace scoring can confirm detailed trace content but cannot prove a durable
33
+ decision record exists.
34
+ 2. Change the CLI to accept `yes` and `no`. Deferred because v0.1.5 already has
35
+ a numeric command contract and the immediate benchmark issue is stale
36
+ guidance, not missing parser capability.
37
+
38
+ ## Consequences
39
+
40
+ Positive:
41
+
42
+ - High-risk agents get explicit decision-log instructions before closing work.
43
+ - Command examples align with the Rust CLI v0.1.5 parser.
44
+ - `story verify` and `story update` have separate mental models in docs.
45
+
46
+ Tradeoffs:
47
+
48
+ - Docs now duplicate a few command examples so the common path is visible
49
+ without repeated help discovery.
50
+
51
+ ## Follow-Up
52
+
53
+ - Re-run the Phase 4 benchmark and check whether T4 records a durable decision.
54
+ - Watch for remaining command churn around `story update` and `story verify`.
docs/decisions/0007-improvement-proposal-rules.md ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0007 Improvement Proposal Rules
2
+
3
+ Date: 2026-06-04
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Phase 5 adds `harness-cli propose`, which changes the harness evolution model.
12
+ The command must be useful without becoming an unchecked source of scope creep
13
+ or circular recommendations.
14
+
15
+ ## Decision
16
+
17
+ Improvement proposals are advisory, rule-based, and evidence-backed. The command
18
+ may summarize repeated friction, repeated interventions, and audit drift. It may
19
+ create `proposed` backlog items only when `--commit` is supplied.
20
+
21
+ Every proposal must include:
22
+
23
+ - affected Harness component,
24
+ - concrete evidence,
25
+ - predicted impact,
26
+ - risk lane,
27
+ - suggested action,
28
+ - validation plan,
29
+ - confidence level.
30
+
31
+ High-risk proposal implementation still requires human review and a durable
32
+ decision record when it changes source hierarchy, architecture direction,
33
+ validation requirements, or risk policy.
34
+
35
+ ## Alternatives Considered
36
+
37
+ 1. Generate free-form LLM recommendations. Rejected because Phase 5 needs a
38
+ deterministic and auditable evolution role.
39
+ 2. Automatically apply proposed changes. Rejected because the harness must not
40
+ rewrite its own policy without review.
41
+ 3. Only report audit findings. Rejected because H5 requires proposed
42
+ improvements, not just drift detection.
43
+
44
+ ## Consequences
45
+
46
+ Positive:
47
+
48
+ - Repeated operational patterns can become backlog items.
49
+ - Proposal output is explainable and testable.
50
+ - Human review remains the gate for risky harness changes.
51
+
52
+ Tradeoffs:
53
+
54
+ - Rule-based grouping can miss semantically similar phrasing.
55
+ - Audit-based proposals may be housekeeping rather than strategic evolution.
56
+
57
+ ## Follow-Up
58
+
59
+ - Use benchmark runs and closed backlog outcomes to improve proposal quality in
60
+ later phases.
docs/decisions/0008-carepath-harness-adoption.md ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0008 CarePath Harness Adoption
2
+
3
+ Date: 2026-07-12
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ CarePath has two clinical workflows, strict safety invariants, multiple test
12
+ surfaces, and historical plans. Future coding agents need a durable way to
13
+ classify work, preserve those boundaries, and record actual proof.
14
+
15
+ ## Decision
16
+
17
+ Adopt Repository Harness from upstream commit `14e6f102a4a645562d046f7c693c61401261cac6`
18
+ with its pinned, checksum-verified Windows CLI v0.1.11. Keep `AGENTS.md` as the
19
+ highest repository-level safety and UX instruction, tailor the Harness to the
20
+ current CarePath contracts, and load the same instructions from `CLAUDE.md`.
21
+
22
+ ## Alternatives Considered
23
+
24
+ 1. Keep only historical plans and ad-hoc validation notes.
25
+ 2. Adopt a documentation-only workflow without durable local records.
26
+ 3. Replace the existing CarePath instructions with the generic upstream shim.
27
+
28
+ ## Consequences
29
+
30
+ Positive:
31
+
32
+ - New work has explicit risk lanes, proof expectations, and durable traces.
33
+ - Codex and Claude Code share the same project contract.
34
+ - The Harness introduces no product dependencies or CI changes.
35
+
36
+ Tradeoffs:
37
+
38
+ - Agents must perform a small intake and trace step for future work.
39
+ - `harness.db` is local-only, so durable operational records are per clone.
40
+
41
+ ## Follow-Up
42
+
43
+ - Upgrade the Harness only as a separately reviewed maintenance task.
44
+ - Register optional tools only when a recurring validation need proves one.
docs/decisions/0009-restructure-target-layout.md ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0009 CarePath Restructure Target Layout
2
+
3
+ Date: 2026-07-13
4
+
5
+ ## Status
6
+
7
+ Superseded in part by 0016
8
+
9
+ > Location update (2026-07-13): the approved Scribe training boundary now
10
+ > resides at `scribe/training/`. The remaining Interpreter and shared-layout
11
+ > decisions in this record remain accepted.
12
+
13
+ ## Context
14
+
15
+ CarePath serves two independent clinical workflows from one process, while the
16
+ repository currently places their runtime, frontends, tests, evaluation, and
17
+ training assets in mixed top-level locations. The approved restructure requires
18
+ a durable target layout without changing import names, routes, or safety
19
+ behavior.
20
+
21
+ ## Decision
22
+
23
+ Move runtime ownership into `scribe/` and `interpreter/`, and reserve `shared/`
24
+ for the later shared package. Decision 0016 supersedes this record's original
25
+ top-level GEC-training location. Keep the import names `carepath` and `app`,
26
+ keep all public routes unchanged, and retain the root `pyproject.toml` as the
27
+ Scribe distribution. Move the interpreter evaluation harness with
28
+ `interpreter/`; it is not GEC training.
29
+
30
+ Each relocation phase must update path math, packaging, CI, Docker, deployment
31
+ documentation, and the affected product contracts, then pass its relevant
32
+ existing proof before the next phase begins.
33
+
34
+ ## Alternatives Considered
35
+
36
+ 1. Leave the current mixed top-level layout.
37
+ 2. Rename both runtime imports to match their new directory names.
38
+ 3. Create separate Python distributions before the relocations.
39
+
40
+ ## Consequences
41
+
42
+ Positive:
43
+
44
+ - Runtime and training ownership are visible from the repository layout.
45
+ - Existing imports and public API routes remain stable.
46
+ - The risk-evaluation suite stays with the Interpreter that it validates.
47
+
48
+ Tradeoffs:
49
+
50
+ - Relative path calculations and deployment files must be audited after every move.
51
+ - The Vercel project root setting requires owner action when `scribe/frontend/` moves.
52
+
53
+ ## Follow-Up
54
+
55
+ - Record a separate high-risk Harness intake and trace for every phase.
56
+ - Do not begin owner-led clinical-data collection without legal consent and data-handling approval.
docs/decisions/0010-shared-normalization-contract.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0010 Shared Normalization Contract
2
+
3
+ Date: 2026-07-13
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Interpreter, Scribe scoring, training scoring, and both lexical retrievers
12
+ carried local normalization implementations. Their names overlapped, but their
13
+ contracts differed: the Interpreter normalizes units, Vietnamese number words,
14
+ and relative dates; scoring compares case-insensitively without semantic
15
+ conversion; lexical retrieval additionally folds diacritics and punctuation.
16
+
17
+ ## Decision
18
+
19
+ Create the installable `shared/carepath_shared` package. Move the Interpreter
20
+ normalizer there unchanged as `normalize_text`, and make every former local
21
+ normalizer a direct import from this package. Keep the existing scoring and
22
+ retrieval semantics as the separately named `normalize_for_metrics` and
23
+ `normalize_for_match` functions, rather than silently changing metric scores or
24
+ term matching.
25
+
26
+ ## Consequences
27
+
28
+ - Normalization algorithms have one owner and one characterization suite.
29
+ - Existing module import paths remain compatible.
30
+ - A future semantic consolidation must explicitly revise the characterization
31
+ suite and evaluation baseline; it is not part of this restructure.
docs/decisions/0011-canonical-medical-term-source.md ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0011 Canonical Medical-Term Source
2
+
3
+ Date: 2026-07-13
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Scribe retrieval reads `data/medical_lexicon.json`; Interpreter safety glossary
12
+ seeding reads `interpreter/app/glossary/data/seed_glossary.csv`. Both are
13
+ clinician-editable medical terminology, but their serving schemas differ.
14
+
15
+ ## Decision
16
+
17
+ `shared/carepath_shared/terms/medical_terms.json` is the only authored source.
18
+ Each row defines Vietnamese and English terms, kind, aliases, risk flags, and
19
+ target-specific rendering metadata. `scripts/build_term_artifacts.py` emits
20
+ both existing serving artifacts without changing either runtime reader.
21
+
22
+ Interpreter risk lexicons remain independent safety data and are explicitly
23
+ out of scope for this source.
24
+
25
+ ## Consequences
26
+
27
+ - Serving paths and schemas stay stable.
28
+ - CI regenerates artifacts and rejects source/artifact drift.
29
+ - Any taxonomy or risk-flag meaning change now requires this decision's
30
+ characterization and safety proof to be revisited.
docs/decisions/0012-interpreter-runtime-hardening.md ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0012 Interpreter Runtime Hardening
2
+
3
+ Date: 2026-07-13
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ The Interpreter compared admin tokens directly, purged retained sessions only
12
+ at startup, and hard-coded development CORS origins. The combined FastAPI
13
+ service duplicated the standalone Interpreter startup path.
14
+
15
+ ## Decision
16
+
17
+ Use `hmac.compare_digest` for the admin token. Give the Interpreter one shared
18
+ lifespan that seeds, purges on startup, runs a daily retention purge task, and
19
+ cancels it on shutdown; the combined service enters the same lifespan. Parse
20
+ CSV `CORS_ORIGINS` through Interpreter settings, with the existing two Vite
21
+ origins as the default.
22
+
23
+ ## Consequences
24
+
25
+ - Admin authentication avoids an avoidable timing leak.
26
+ - Retention continues while a process stays up.
27
+ - Standalone and combined Interpreter startup cannot drift.
28
+ - Production operators configure allowed cross-origin development clients via
29
+ `.env`; same-origin deployment remains the default topology.
docs/decisions/0013-gec-training-data-governance.md ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0013 GEC Training Data Governance
2
+
3
+ Date: 2026-07-13
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ GEC training previously accepted a dataset name and profile without a durable
12
+ record of its source, consent status, immutable version, or deterministic run
13
+ configuration. Clinical audio is sensitive personal data and cannot be sourced
14
+ or approved by an agent.
15
+
16
+ ## Decision
17
+
18
+ Use versioned JSON run configs with fixed seeds and a dataset-manifest reference.
19
+ `run_pipeline.py` refuses every training stage until the referenced manifest has
20
+ owner-approved consent and a non-placeholder SHA-256. Add a text-only frozen
21
+ stratified evaluation fixture with a separate immutable hash; it contains no
22
+ patient audio or identifiers.
23
+
24
+ ## Consequences
25
+
26
+ - The agent can validate pipeline governance without collecting clinical data.
27
+ - The owner must complete lawful sourcing, consent, de-identification, and hash
28
+ verification before a real training run.
29
+ - Evaluation categories make drug, dosage, laterality, negation, number, and
30
+ diacritic regressions visible independently.
docs/decisions/0014-gec-safety-weighted-regression-gate.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0014 GEC Safety-Weighted Regression Gate
2
+
3
+ Date: 2026-07-13
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Aggregate WER can improve while a correction damages a medication name or a
12
+ dosage. Those errors have a higher clinical cost than ordinary transcription
13
+ differences. The training pipeline also lacked a versioned committed baseline
14
+ that CI could validate without model or GPU dependencies.
15
+
16
+ ## Decision
17
+
18
+ Commit a deterministic report for the hashed, text-only frozen GEC fixture.
19
+ Require its report to stay reproducible in CI. A trained adapter must pass the
20
+ existing aggregate gate and, before export, a frozen-fixture gate that rejects
21
+ any regression in `drug_name.term_recall` or
22
+ `dosage.number_unit_preservation` versus raw ASR.
23
+
24
+ ## Consequences
25
+
26
+ - Overall WER alone can never approve an adapter that harms drug or dosage
27
+ preservation.
28
+ - CI remains CPU-only: it validates the 12-row fixture, committed report, and
29
+ a fake-adapter export/injected-generation smoke test.
30
+ - A real adapter run still needs the owner-approved training manifest and an
31
+ available GPU; this policy does not authorize data collection or training.
docs/decisions/0015-soap-note-measurement-gate.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0015 SOAP Note Measurement Gate
2
+
3
+ Date: 2026-07-13
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ The Scribe SOAP output uses a hosted clinical LLM with an offline fallback.
12
+ There is no legitimate basis to train or tune it from invented examples, and no
13
+ clinical rating protocol existed to distinguish missing content, hallucination,
14
+ and terminology errors.
15
+
16
+ ## Decision
17
+
18
+ Before any SOAP fine-tuning decision, the owner must obtain at least 50
19
+ de-identified pilot notes rated by clinicians under the documented rubric.
20
+ The repository holds only a blank rating schema and a validator that accepts
21
+ anonymous rating metadata; it must never hold source audio, transcripts,
22
+ patient identifiers, or note text.
23
+
24
+ ## Consequences
25
+
26
+ - The agent can make the measurement process reproducible without simulating
27
+ clinical evidence.
28
+ - A rating summary makes serious hallucinations and unsafe dispositions visible
29
+ to the owner before choosing training, retrieval, prompting, or no change.
30
+ - The clinical-data study, ratings, and any subsequent model decision remain
31
+ owner-led and require an approved environment.
docs/decisions/0016-scribe-training-ownership.md ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 0016 Scribe Training Ownership
2
+
3
+ Date: 2026-07-13
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ The offline DARAG/GEC training code, fixtures, reports, notebooks, and scripts
12
+ already support the Scribe's Vietnamese clinical-note workflow. The top-level
13
+ `training/` directory obscures that ownership and risks being confused with the
14
+ Interpreter's safety evaluation harness at `interpreter/eval/`.
15
+
16
+ ## Decision
17
+
18
+ Move the complete offline training boundary to `scribe/training/`. It contains
19
+ the GEC package, configs, fixtures, manifests, reports, notebooks, scripts,
20
+ tests, and SOAP measurement tooling. `interpreter/eval/` remains the
21
+ Interpreter's independent safety regression harness.
22
+
23
+ The Scribe serving package at `scribe/carepath/` must not import training code;
24
+ the production image copies only the Scribe runtime package, not
25
+ `scribe/training/`. Training keeps its standalone `gec.*` command-line import
26
+ boundary without adding a distribution or dependency.
27
+
28
+ This supersedes only the top-level training-location portion of decision 0009.
29
+
30
+ ## Consequences
31
+
32
+ - Training commands and CI use `scribe/training/...` paths.
33
+ - Runtime packaging stays independent of offline model-development artifacts.
34
+ - The repository has a visibly separate Scribe training boundary and
35
+ Interpreter safety-evaluation boundary.
docs/decisions/README.md ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Decisions
2
+
3
+ Decision records explain why important product, architecture, or harness choices
4
+ were made.
5
+
6
+ Use `docs/templates/decision.md` when adding a new decision.
7
+
8
+ After adding or updating a markdown decision file, also add or refresh the
9
+ durable decision row:
10
+
11
+ ```bash
12
+ scripts/bin/harness-cli decision add \
13
+ --id 0008-auth-boundary \
14
+ --title "Auth Boundary" \
15
+ --doc docs/decisions/0008-auth-boundary.md
16
+ ```
17
+
18
+ Trace fields such as `--decisions` summarize task-level choices. They do not
19
+ count as the Harness decision log.
20
+
21
+ Add a decision when:
22
+
23
+ - A locked technical choice changes.
24
+ - A product rule changes meaningfully.
25
+ - A validation requirement is added, removed, or weakened.
26
+ - A high-risk feature chooses one design over another.
27
+ - Auth, authorization, data ownership, audit/security, or API behavior changes.
28
+ - The source-of-truth hierarchy changes.
docs/deploy.md ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath Unified Deploy
2
+
3
+ Use `https://carepath-omega.vercel.app` as the public Scribe site. One Hugging
4
+ Face Space runs the Scribe tool at `/ghi-chep-lam-sang/`, the Scribe API at
5
+ `/api/v1/*`, and the retained Interpreter API at `/api/*` + `/ws/*`.
6
+ `/phien-dich-y-khoa/*` and `/console/*` are intentionally public 404s while
7
+ the Interpreter remains in development.
8
+
9
+ ## Hugging Face Space
10
+
11
+ Reuse the existing Docker Space
12
+ [`tranth3truong/carepath-api`](https://huggingface.co/spaces/tranth3truong/carepath-api),
13
+ served at `https://tranth3truong-carepath-api.hf.space`. Deploy this unified
14
+ repository there; it retains the Interpreter API but does not serve the
15
+ unfinished Interpreter browser workflow.
16
+
17
+ 1. Rebuild the existing `tranth3truong/carepath-api` Space with **Docker** as
18
+ the SDK. Create a replacement only if that Space is no longer available.
19
+ 2. Copy `README.hf-space.md` to the Space as `README.md` so the Space has:
20
+
21
+ ```yaml
22
+ ---
23
+ title: CarePath
24
+ sdk: docker
25
+ app_port: 7860
26
+ ---
27
+ ```
28
+
29
+ 3. Push this repo to the Space. The root `Dockerfile` builds `scribe/frontend/` and
30
+ `interpreter/frontend/` in a node stage (the site build enforces the Vietnamese
31
+ diacritics gate), installs both API packages, pre-downloads the Gipformer
32
+ int8 ONNX files, and starts Uvicorn on port `7860`.
33
+ Set the Docker build arg `VITE_PUBLIC_SITE_URL=https://carepath-omega.vercel.app`
34
+ so the Interpreter's “Tất cả chức năng” link returns to the public site
35
+ with the selected language.
36
+ 4. Set these Space secrets:
37
+
38
+ ```text
39
+ LLM_PROVIDER=ckey
40
+ LLM_API_KEY=<your CKey key>
41
+ LLM_MODEL=gpt-5.4
42
+ TEAM_CODE=<shared internal demo code>
43
+ SOAP_RATE_LIMIT_PER_IP_HOUR=3
44
+ SOAP_RATE_LIMIT_PER_IP_DAY=10
45
+ SOAP_RATE_LIMIT_GLOBAL_DAY=100
46
+ APP_ENV=prod
47
+ CORS_ORIGINS=https://carepath-omega.vercel.app
48
+ ```
49
+
50
+ The interpreter module runs in mock mode by default and needs no secrets.
51
+ When its cloud track lands, it will additionally need `PROVIDER_MODE=cloud`,
52
+ `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and a non-default `ADMIN_TOKEN`
53
+ (startup refuses `change-me` in cloud mode).
54
+
55
+ The Vercel site uploads Scribe audio directly to the Space, so its exact origin
56
+ must be present in `CORS_ORIGINS`. Add local Vite origins as comma-separated
57
+ values only when testing local frontends against the deployed API.
58
+
59
+ Requests with header `X-Team-Code: <TEAM_CODE>` bypass the SOAP rate limits
60
+ for internal doctor-comparison runs. Limited requests return HTTP `429`,
61
+ `Retry-After`, and JSON body
62
+ `{"detail":{"message":"...","retry_after_seconds":3600}}` — the Scribe tool
63
+ surfaces that message to the user.
64
+
65
+ ## Local Docker Check
66
+
67
+ ```powershell
68
+ docker build -t carepath .
69
+ docker run --rm -p 7860:7860 `
70
+ -e LLM_PROVIDER=ckey `
71
+ -e "LLM_API_KEY=$env:LLM_API_KEY" `
72
+ -e LLM_MODEL=gpt-5.4 `
73
+ -e APP_ENV=prod `
74
+ carepath
75
+ ```
76
+
77
+ Keyless variant (mock ASR + offline LLM + mock interpreter — must also work):
78
+
79
+ ```powershell
80
+ docker run --rm -p 7860:7860 `
81
+ -e ASR_PROVIDER=mock -e ALLOW_MOCK_ASR=true -e LLM_PROVIDER=offline `
82
+ carepath
83
+ ```
84
+
85
+ In another terminal:
86
+
87
+ ```powershell
88
+ curl.exe http://127.0.0.1:7860/api/v1/health
89
+ curl.exe http://127.0.0.1:7860/api/health
90
+ curl.exe -o NUL -w "%{http_code}`n" http://127.0.0.1:7860/
91
+ curl.exe -o NUL -w "%{http_code}`n" http://127.0.0.1:7860/ghi-chep-lam-sang/
92
+ curl.exe -o NUL -w "%{http_code}`n" http://127.0.0.1:7860/phien-dich-y-khoa/
93
+ curl.exe -X POST http://127.0.0.1:7860/api/v1/soap-notes `
94
+ -F "audio=@C:\path\to\demo.wav" `
95
+ -F "encounter_context=Phòng khám nội tổng quát"
96
+ ```
97
+
98
+ ## Canonical Vercel site
99
+
100
+ The `scribe/frontend/` directory is the static marketing deployment at
101
+ `https://carepath-omega.vercel.app`:
102
+
103
+ 1. In the Vercel project settings, change **Root Directory** from the removed
104
+ `apps/web-next` to `scribe/frontend` (framework/build/output come from
105
+ `scribe/frontend/vercel.json`).
106
+ 2. Set these Vercel environment variables:
107
+
108
+ ```text
109
+ VITE_API_BASE=https://tranth3truong-carepath-api.hf.space
110
+ VITE_CONSOLE_URL=https://tranth3truong-carepath-api.hf.space/phien-dich-y-khoa/
111
+ VITE_LEAD_ENDPOINT=<optional lead endpoint>
112
+ VITE_LEAD_EMAIL=<pilot contact email>
113
+ ```
114
+
115
+ 3. Confirm the Space contains the Vercel origin configured above. Do not add
116
+ Vercel API or WebSocket rewrites; the Space owns those routes.
117
+
118
+ The Vercel build runs `npm run validate:deploy` before compiling. It fails when
119
+ either URL is missing or invalid, does not use HTTPS, uses a different origin,
120
+ contains a query/fragment, or does not use the exact `/` and `/phien-dich-y-khoa/`
121
+ pathnames. Local
122
+ and combined-service builds still use same-origin fallbacks because the normal
123
+ `npm run build` does not run this deployment-only check.
124
+
125
+ The Interpreter backend stays on the Space because it needs the WebSocket API,
126
+ but its browser frontend is disabled. `VITE_CONSOLE_URL` remains a build-time
127
+ compatibility setting until the public-site validation is simplified. The pilot
128
+ form remains client-side unless `VITE_LEAD_ENDPOINT` is configured.
129
+
130
+ ## Keep-Alive
131
+
132
+ The workflow in `.github/workflows/keepalive.yml` pings the Space every 12
133
+ hours. Set the GitHub repository variable:
134
+
135
+ ```text
136
+ SPACE_URL=https://tranth3truong-carepath-api.hf.space
137
+ ```
138
+
139
+ Then run **Actions > Keep HF Space Awake > Run workflow** once and confirm the
140
+ job succeeds.
141
+
142
+ ## Final Smoke
143
+
144
+ 1. Open the Space URL: the CarePath landing renders, Vietnamese by default.
145
+ 2. Run the scripted interpreter simulation on the landing.
146
+ 3. Open `/ghi-chep-lam-sang/`, upload a short clip, and verify the SOAP draft renders
147
+ with the review banner.
148
+ 4. Confirm `/phien-dich-y-khoa/` and `/console/` return HTTP 404.
149
+ 5. Confirm `GET /api/v1/health` reports `llm_provider: ckey` and
150
+ `asr_ready: true`, and `GET /api/health` reports `provider_mode: mock`.
docs/history/DEMO-SITE-PLAN.md ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath Interpreter — Demo Website Plan
2
+
3
+ A public demo/marketing site for the product. Separate track from PLAN.md (the product);
4
+ do not touch `backend/` or `frontend/` for this work. Everything lives in a new `/site`
5
+ folder. Read [docs/research.md](docs/research.md) for the evidence base the copy draws on.
6
+
7
+ **Executor:** codex-5.5 (xhigh). Work tickets S.0 → S.7 in order, one commit per ticket,
8
+ same conventions as AGENTS.md. All copy that appears in Vietnamese MUST have full
9
+ diacritics — this is a hard rule (see AGENTS.md).
10
+
11
+ ---
12
+
13
+ ## 1. Purpose, audience, and the one metric
14
+
15
+ The site convinces **Vietnamese clinic owners and hospital administrators** (secondary:
16
+ pilot clinicians, investors) that CarePath is a safe, compliant way to run consultations
17
+ with English-speaking patients — and converts them into **pilot-program requests**.
18
+ One conversion goal: the "Đăng ký thí điểm" (Request a pilot) form. Everything on the
19
+ page exists to move a skeptical healthcare buyer toward that form.
20
+
21
+ Language: **Vietnamese default, English toggle** (persist choice in localStorage).
22
+
23
+ ## 2. Architecture (decided)
24
+
25
+ - **Static site, no backend.** New `/site` folder: Vite + React 18 + TypeScript — same
26
+ stack and lint rules as `frontend/`, but an independent app (own package.json). Output
27
+ is plain static files deployable to any host (GitHub Pages/Netlify/nginx).
28
+ - **The interactive demo is a scripted, client-only simulation.** It replays canned
29
+ consultation turns that reproduce the real product UX (push-to-talk feel, bilingual
30
+ transcript, risk highlighting, read-back confirmation, escalation button). No real
31
+ ASR/MT calls, no API keys, no audio recording, no PHI — the browser never captures
32
+ the mic. Seed the scripts from `eval/fixtures/eval_starter.tsv` scenarios (they are
33
+ already clinically shaped and bilingual).
34
+ - **Lead capture without a server:** the pilot-request form POSTs to a configurable
35
+ `VITE_LEAD_ENDPOINT`; when unset, it falls back to a prefilled `mailto:` link. Mark
36
+ this as the single integration point. Store nothing in the browser beyond the form
37
+ draft.
38
+ - Simple i18n: one `strings.ts` dictionary module (`vi`/`en` keys), no i18n library.
39
+ - No analytics, no cookies, no tracking in MVP. A comment marks where a privacy-safe
40
+ counter could go later.
41
+
42
+ ## 3. Honesty guardrails (non-negotiable)
43
+
44
+ The product's brand IS safety. The site models the same honesty the app enforces:
45
+
46
+ 1. The demo is clearly labeled as a simulation: "Bản mô phỏng — không phải bản dịch
47
+ trực tiếp" visible while the demo plays.
48
+ 2. Never claim autonomy or diagnosis. The tagline space says *translation-and-
49
+ verification aid with human-interpreter escalation* — mirror AGENTS.md invariant 1.
50
+ 3. Banned patterns: fake urgency ("only 3 pilot slots left!"), fake scarcity, countdown
51
+ timers, guilt-trip copy ("No thanks, I prefer miscommunication"), pre-checked
52
+ marketing-consent boxes, hidden pricing.
53
+ 4. Every statistic shown must come from docs/research.md and carry its citation in a
54
+ tooltip/footnote (e.g., 40–80% of verbal medical information is immediately
55
+ forgotten — Kessels 2003; up to 66% of MT'd discharge-instruction sets contained
56
+ an inaccuracy — BMJ Qual Saf 2025).
57
+ 5. Loss-aversion and contrast framing must be factual (real costs, real risks), never
58
+ fabricated numbers. Pricing figures are placeholders marked `TODO-pricing` for the
59
+ founder to fill; do not invent prices presented as real.
60
+
61
+ ## 4. Page architecture — each section wired to a persuasion principle
62
+
63
+ Single long-scroll landing page + the embedded demo. Section order is the persuasion
64
+ sequence; the six principles are design mechanics, not decoration:
65
+
66
+ | # | Section | Principle applied | Mechanic |
67
+ |---|---|---|---|
68
+ | 1 | **Hero** | Reciprocity | Value before any ask: headline + the live demo sits above the fold, playable immediately. No form, no email gate anywhere before section 7. CTA: "Xem demo 90 giây" scrolls into the demo. |
69
+ | 2 | **Interactive demo** | Smart defaults + Goal gradient + IKEA | See §5. Scenario pre-selected and pre-loaded (smart default: "Khám ngoại trú — kê đơn thuốc", the most relatable case). A 4-step progress rail starts with step 1 already checked: "✓ Kịch bản đã chọn" — the visitor begins at 25%, not zero. Customization panel (IKEA): clinic name, specialty, scenario choice — reflected live in the demo header ("Phòng khám Đa khoa An Bình — Demo"). |
70
+ | 3 | **The problem** | Loss aversion (ethical) | What clinics lose *today*: cited stats on miscommunication (research §Exec Summary), the cost/scarcity of qualified interpreters, compliance exposure. Frame: "Mỗi lượt khám không được phiên dịch đúng là một rủi ro bạn đang gánh" — protecting what they have (patients, reputation, license), not threatening to take features away. |
71
+ | 4 | **Safety by design** | Trust builder (no trick) | The product's differentiator. Render the real safety mechanics as cards: read-back confirmation, risk highlighting, low-confidence flagging, one-tap interpreter escalation, no-audio-storage privacy mode. Copy source: PLAN.md §2 invariants, translated for a non-technical buyer. |
72
+ | 5 | **How it works** | — | 3 illustrated steps (speak → verify → confirm), one line each. |
73
+ | 6 | **Cost framing** | Contrast effect (ethical) | Anchor with the true, cited costs of the status quo: full-time bilingual staff or per-visit professional interpreter rates, and the cost of a single adverse event. Then the pilot offer (placeholder `TODO-pricing`). The anchor numbers must be real and sourced — contrast through honest arithmetic, not a fake slashed price. |
74
+ | 7 | **Pilot CTA + form** | Reciprocity + IKEA + Loss aversion payoff | By now the visitor has used the demo and customized it. Form headline: "Giữ lại bản demo bạn vừa tạo" — submitting sends them their configured demo transcript (attach the transcript text into the form payload). Fields: name, clinic, role, email/Zalo, pre-filled message (smart default) summarizing their chosen scenario. ≤5 fields. |
75
+ | 8 | **Footer** | — | Compliance posture line (Decree 13/PDP-aware design, §1557-aligned positioning), AI-use honesty statement, contact. |
76
+
77
+ ## 5. The interactive demo spec (the heart of the site)
78
+
79
+ A `DemoPlayer` component simulating one consultation:
80
+
81
+ - **Scenario scripts:** 3 scripted conversations (JSON in `site/src/demo/scenarios/`),
82
+ ~8 turns each, adapted from eval fixtures: (a) prescription + dosage (default),
83
+ (b) allergy check with a negation moment, (c) chest-pain red flag → escalation.
84
+ Each turn: speaker, Vietnamese text, English text, risk tier, risk spans, and for
85
+ high/critical turns a read-back payload (entities: drug/dose/frequency/negation).
86
+ - **Playback:** turns appear one-by-one with a typing/speaking animation and a subtle
87
+ push-to-talk button pulse (autoplay ~4s per turn; controls: play/pause, next, replay).
88
+ Visitor can also click "Thử tự gõ" to type one custom line that gets echoed into the
89
+ transcript with a canned translation — participation, not real MT (label it).
90
+ - **The safety moment is the hero moment:** when the dosage/allergy turn arrives,
91
+ playback *stops*, the read-back confirmation card slides in (real product styling:
92
+ entity table, Confirm / Edit / Escalate), and the progress rail advances only when
93
+ the visitor clicks Confirm. In scenario (c), the red-flag turn triggers the
94
+ full-screen escalation banner exactly like the product.
95
+ - **Progress rail (goal gradient):** `✓ Kịch bản` → `Nghe hội thoại` → `Xác nhận
96
+ read-back` → `Nhận bản ghi`. Step 4 unlocks a "Tải bản ghi demo" button (downloads
97
+ the bilingual transcript as a formatted .txt/.html — the free cookie they keep).
98
+ - Visual fidelity: match the real product's transcript layout and risk badge colors
99
+ (lift the palette from `frontend/src/App.css`) so the demo IS the product, not a
100
+ cartoon of it.
101
+
102
+ ## 6. Design direction
103
+
104
+ - Clinical-trust aesthetic: calm, spacious, high contrast; one accent color for risk/
105
+ CTA moments; light + dark theme. No stock-photo doctors, no purple-gradient AI slop,
106
+ no emoji in headings. Vietnamese typography checked with real diacritics at display
107
+ sizes (choose a font that renders Vietnamese well — e.g. Be Vietnam Pro, self-hosted).
108
+ - Responsive: the demo must work on a phone (clinic owners will open this from Zalo).
109
+ - Accessibility is part of the pitch: WCAG AA contrast, full keyboard path through the
110
+ demo, `prefers-reduced-motion` respected (no autoplay animation), semantic landmarks.
111
+ - Performance: static, self-hosted font subset, no external requests at runtime except
112
+ the lead endpoint on submit. Lighthouse ≥95 performance/accessibility/best-practices.
113
+
114
+ ## 7. Tickets
115
+
116
+ - **S.0 Scaffold.** `/site` Vite React-TS app, eslint config copied from frontend,
117
+ `npm run dev/build/test`, README section. Commit this plan file with it.
118
+ *Accept:* `npm run build` outputs static files; CI-ready.
119
+ - **S.1 Demo engine.** Scenario JSON schema + 3 scripts + `DemoPlayer` with playback,
120
+ read-back stop, escalation moment, progress rail, transcript download. *Tests:*
121
+ vitest — playback advances, confirmation gates progress, download produces bilingual
122
+ content; scripts validated against the schema.
123
+ - **S.2 Page sections.** Sections 1, 3–6, 8 with bilingual copy (research-cited stats
124
+ with footnotes; `TODO-pricing` placeholders). *Accept:* full page renders in vi + en;
125
+ no diacritic-stripped Vietnamese anywhere (add a test that greps built output for
126
+ the corrected consent-style strings).
127
+ - **S.3 Persuasion wiring.** Smart-default scenario preselection, customization panel
128
+ (clinic name/specialty live in demo header), form pre-fill from demo state, "keep
129
+ your demo" transcript attach. *Tests:* customization propagates; form payload
130
+ contains scenario summary.
131
+ - **S.4 Language toggle.** `strings.ts`, vi default, persisted choice, `<html lang>`
132
+ switches. *Tests:* toggle flips all sections.
133
+ - **S.5 Lead form.** `VITE_LEAD_ENDPOINT` POST with mailto fallback, ≤5 fields, inline
134
+ validation, success state, zero persistence beyond the draft. *Tests:* endpoint mode
135
+ + fallback mode.
136
+ - **S.6 A11y + e2e.** Keyboard-only Playwright run through the whole demo flow to form
137
+ success; reduced-motion snapshot; axe-core pass with no serious violations.
138
+ - **S.7 CI.** New `site` job: lint, test, build, run the S.6 e2e against `vite preview`.
139
+ *Accept:* CI green end to end.
140
+
141
+ ## 8. Non-goals
142
+
143
+ No real translation calls, no account system, no CMS, no blog, no analytics, no A/B
144
+ testing framework, no multi-page router (one page + anchors), no video production
145
+ (the scripted demo replaces a demo video). Pricing numbers are founder input, not
146
+ codex's to invent.
docs/history/JUDGE.md ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # JUDGE.md — claude-fable-5 review protocol for the CarePath unification
2
+
3
+ **Who runs this:** claude-fable-5, in a fresh session, after codex finishes MERGE-PLAN.md.
4
+ **What is judged:** the `carepath-unified` branch, ticket commits M.0 → M.8.
5
+ **Baselines for comparison:** `origin/main` (scriber contract) and
6
+ `origin/carepath-interpreter-demo` (interpreter behavior + S.8 design).
7
+
8
+ Judge the work, not the plan. If MERGE-PLAN.md itself turns out to be wrong somewhere
9
+ and codex deviated for a good, documented reason, that is acceptable — say so explicitly
10
+ in the verdict instead of failing the ticket.
11
+
12
+ ---
13
+
14
+ ## 1. Hard gates — any failure ⇒ overall NEEDS WORK
15
+
16
+ Run every gate. Report each as PASS / FAIL with evidence (command output, file:line).
17
+
18
+ ### G1. Everything green
19
+
20
+ Run the full Verify inventory (MERGE-PLAN.md §3) on a clean checkout of
21
+ `carepath-unified`:
22
+
23
+ ```text
24
+ pip install -e ".[dev]" -e "./backend[dev]" # one Python 3.12 venv
25
+ pytest # root (scriber + combined-app test)
26
+ python scripts/smoke_backend.py
27
+ cd backend && ruff check . && pytest && cd ..
28
+ python eval/run_eval.py --set eval/fixtures/eval_starter.tsv --providers mock
29
+ cd frontend && npm ci && npm run lint && npm test && cd ..
30
+ cd site && npm ci && npm run lint && npm test && npm run build && cd ..
31
+ # e2e (needs built app / mock backend per ci.yml):
32
+ cd frontend && npm run e2e ; cd ../site && npm run e2e
33
+ ```
34
+
35
+ ### G2. Scriber API contract frozen
36
+
37
+ The deployed HF Space clients must not break:
38
+
39
+ ```text
40
+ git diff origin/main carepath-unified -- apps/api/carepath/schemas.py
41
+ ```
42
+
43
+ Schema diff must be empty (or provably additive-only). Then compare every `/api/v1/*`
44
+ route signature, status codes, and rate-limit/TEAM_CODE behavior in
45
+ `apps/api/carepath/main.py` against `origin/main` — changes must be additions
46
+ (interpreter routers, static mounts, lifespan additions), never modifications to
47
+ existing scriber behavior.
48
+
49
+ ### G3. Safety invariants intact (AGENTS.md §2 / MERGE-PLAN.md §2)
50
+
51
+ Audit with greps + targeted reads on the merged tree:
52
+
53
+ 1. **No raw-audio persistence** in the interpreter path: no audio columns in
54
+ `backend/app/crud.py` models, no `tempfile`/disk writes of turn audio in
55
+ `backend/app/session.py` or `api.py`. (The scriber's documented tempfile
56
+ normalization of *uploaded clips* on `origin/main` is pre-existing and allowed.)
57
+ 2. **Consent before mic**: every `getUserMedia` call site in `frontend/` and `site/`
58
+ (including the new scribe view) is gated behind the consent flow.
59
+ 3. **Risk blocking**: high/critical turns still blocked pre-confirmation — spot-check
60
+ `backend/app/session.py` + `frontend/src/components/InterpreterConsole.tsx` are
61
+ unchanged from the interpreter branch (or changed only for import/serving reasons).
62
+ 4. **Fail-closed**: pipeline error paths in `backend/app/api.py` unchanged.
63
+ 5. **No advice generation** introduced anywhere in new copy or code.
64
+ 6. **Diacritics**: `site/` build gate ran; spot-check new Vietnamese copy (Scribe
65
+ section, error messages) for full diacritics.
66
+
67
+ ### G4. Keyless boot
68
+
69
+ With **no** API keys in the environment (`PROVIDER_MODE=mock`, `ASR_PROVIDER=mock`,
70
+ `ALLOW_MOCK_ASR=true`, `LLM_PROVIDER=offline`): the combined uvicorn app boots and
71
+ serves `/api/health`, `/api/v1/health`, a mock `POST /api/v1/soap-notes`, a created
72
+ interpreter session + WebSocket handshake, and (if dists are built) `/` and `/console/`.
73
+
74
+ ### G5. Retirement + hygiene
75
+
76
+ - `git ls-files apps/web apps/web-next` → empty.
77
+ - `grep -ri "carepath translate" site/src docs README.md` → empty.
78
+ - No secrets/keys anywhere in `git diff origin/main...carepath-unified`.
79
+ - Root `package-lock.json` orphan (if still present without a root `package.json`) —
80
+ flag for deletion.
81
+ - `.env.example` documents both products; defaults match the keyless demo profile.
82
+
83
+ ## 2. Scored review — 1 (poor) to 5 (excellent) each
84
+
85
+ | Dimension | What 5 looks like |
86
+ |---|---|
87
+ | Brand/UI consistency | Landing, scribe view, and console read as one product on the S.8 design system; logo/name unified; no leftover Translate branding or old apps/web styling. |
88
+ | Code quality | Matches AGENTS.md conventions (ruff, TS strict, small components, data-not-code lexicons); no copy-paste from app.js left un-Reactified; no dead code. |
89
+ | Commit hygiene | Exactly one commit per ticket, M.0→M.8 in order, subjects match, bodies explain any deviation from the plan. |
90
+ | Minimalism | No unrequested abstractions, no new deps beyond plan, hash route not a router lib, mounts/env kept simple. |
91
+
92
+ ## 3. Verdict format
93
+
94
+ 1. **Per-ticket table**: ticket · commit sha · gates touched · PASS / NEEDS WORK · one-line note.
95
+ 2. **Hard-gate table**: G1–G5 with evidence.
96
+ 3. **Scores** with one sentence each.
97
+ 4. **Overall: PASS or NEEDS WORK.** If NEEDS WORK: a numbered, codex-executable fix
98
+ list — each item states the file, the defect, the expected behavior, and which gate
99
+ it unblocks. No vague items.
docs/history/MERGE-PLAN.md ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CarePath Unification Plan — merge Scriber + Interpreter into one product
2
+
3
+ **Executor:** codex-5.6 terra (fallback: codex-5.5 xhigh). Work tickets M.0 → M.8 in
4
+ order, **one commit per ticket**, commit subject `M.x <imperative summary>`. Every
5
+ ticket ends green: run that ticket's Verify list before committing. If a Verify step
6
+ fails, fix it inside the same ticket — never commit red, never skip ahead.
7
+
8
+ **Judge:** after M.8, claude-fable-5 reviews the branch against `JUDGE.md`. Anything
9
+ that fails a hard gate there comes back as a fix list — save everyone a round trip by
10
+ running the gates yourself first.
11
+
12
+ ---
13
+
14
+ ## 1. What is being merged
15
+
16
+ The repo holds two products with **unrelated git histories**:
17
+
18
+ | | Scriber (`origin/main`) | Interpreter (`origin/carepath-interpreter-demo`) |
19
+ |---|---|---|
20
+ | Backend | `apps/api/carepath` FastAPI: `/api/v1/health`, `/api/v1/corrections`, `/api/v1/soap-notes` | `backend/app` FastAPI: `/api/*` REST + `/ws/sessions/{id}` WebSocket, risk engine, admin review |
21
+ | ASR / LLM | Gipformer ONNX (local, keyless) + ckey OpenAI-compatible LLM. **Deployed, working** (HF Space Docker) | OpenAI + Anthropic cloud providers (no keys) → **mock mode only** |
22
+ | Frontends | `apps/web` (static tool), `apps/web-next` (Next.js landing) | `frontend/` (interpreter console), `site/` (marketing demo site — the S.8 clinical redesign) |
23
+
24
+ Target: **one product, "CarePath"**, on branch `carepath-unified`:
25
+
26
+ 1. **One FastAPI service** (single deploy): scriber routes stay at `/api/v1/*`,
27
+ interpreter routes at `/api/*` + `/ws/*`, one combined lifespan.
28
+ 2. **Interpreter stays mock-only for now.** Do not touch the provider abstraction or
29
+ wire new providers. Real interpreter providers are a later, separate track.
30
+ 3. **`site/` becomes the entire public face**, rebranded "CarePath Translate" →
31
+ "CarePath" with two modules: **Interpreter** and **Scribe**. The newer branch's
32
+ UI/UX (logos, design system) wins everywhere. `apps/web` and `apps/web-next` are
33
+ retired.
34
+ 4. **Histories are preserved** via `git merge --allow-unrelated-histories`.
35
+
36
+ ## 2. Non-negotiable invariants (inherited from AGENTS.md — full text there)
37
+
38
+ These apply to every ticket. The judge greps for regressions on each one.
39
+
40
+ 1. Translate-only: never generate medical advice, diagnoses, or drug recommendations.
41
+ 2. High/critical-risk turns stay blocked from patient display + TTS until doctor confirms.
42
+ 3. Low-confidence output is always visibly flagged, never silently delivered.
43
+ 4. Raw audio is never persisted by the interpreter — memory-only. No audio columns, no temp files.
44
+ 5. No mic capture before recorded consent.
45
+ 6. On pipeline/reviewer failure, fail closed — never fail open to the patient.
46
+ 7. Vietnamese copy always carries full diacritics, NFC-normalized. `site/` build enforces this.
47
+ 8. **The scriber API contract is frozen**: request/response schemas and routes under
48
+ `/api/v1/*` must be byte-for-byte compatible with `origin/main` (`carepath/schemas.py`
49
+ and the endpoint signatures in `carepath/main.py`). The deployed HF Space and its
50
+ clients must keep working.
51
+ 9. Keyless boot is a hard requirement end-to-end: `PROVIDER_MODE=mock` +
52
+ `LLM_PROVIDER=offline` + `ASR_PROVIDER=mock`/`ALLOW_MOCK_ASR=true` must run the whole
53
+ combined product with zero API keys.
54
+ 10. Secrets only via env. `.env` gitignored, `.env.example` stays current. No new
55
+ dependencies beyond those named in this plan without a written why in the commit body.
56
+
57
+ ## 3. Verify command inventory
58
+
59
+ Used throughout the tickets (all verified to exist on their source branches):
60
+
61
+ ```text
62
+ # scriber (repo root, Python 3.12 venv with: pip install -e ".[dev]")
63
+ pytest # root suite (tests/, pythonpath apps/api)
64
+ python scripts/smoke_backend.py # forces mock ASR + offline LLM internally
65
+
66
+ # interpreter backend (from backend/, same venv with: pip install -e ".[dev]")
67
+ ruff check .
68
+ pytest
69
+
70
+ # eval regression (repo root)
71
+ python eval/run_eval.py --set eval/fixtures/eval_starter.tsv --providers mock
72
+
73
+ # interpreter console (from frontend/)
74
+ npm ci && npm run lint && npm test && npm run e2e # e2e needs PROVIDER_MODE=mock backend
75
+
76
+ # demo site (from site/)
77
+ npm ci && npm run lint && npm test && npm run build # build runs check-diacritics.mjs
78
+ npm run e2e
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Tickets
84
+
85
+ ### M.0 — Unify the histories
86
+
87
+ 1. `git checkout -b carepath-unified origin/main`
88
+ 2. `git merge --allow-unrelated-histories origin/carepath-interpreter-demo`
89
+ 3. Exactly three paths collide — resolve as:
90
+ - `README.md`: temporary stub — unified title, one paragraph per product, links to
91
+ both quickstarts. Rewritten properly in M.8.
92
+ - `.gitignore`: union of both, deduplicated.
93
+ - `.env.example`: both files concatenated under `# --- Scriber (apps/api) ---` and
94
+ `# --- Interpreter (backend/) ---` section headers. Properly merged in M.2.
95
+ 4. Nothing else changes in this ticket. No restructuring, no renames.
96
+
97
+ **Verify:** root `pytest` passes; `python scripts/smoke_backend.py` passes;
98
+ `cd backend && pytest` passes; `frontend/` and `site/` `npm test` pass.
99
+
100
+ ### M.1 — One FastAPI service
101
+
102
+ Goal: a single uvicorn process serves both API surfaces.
103
+
104
+ 1. Root `pyproject.toml`: no changes to the `carepath` package config. The interpreter
105
+ backend stays where it is and keeps its own `backend/pyproject.toml`; the combined
106
+ env simply installs both: `pip install -e ".[dev]" -e "./backend[dev]"`. Confirm the
107
+ resolver accepts both dependency sets on Python 3.12 (backend requires >=3.12).
108
+ 2. Extend `apps/api/carepath/main.py`:
109
+ - `app.include_router(api_router)` and `app.include_router(ws_router)` from
110
+ `app.api` (the interpreter package is importable as `app` once installed). Register
111
+ routers **before** the `app.mount("/", StaticFiles(...))` call so routes win.
112
+ - Extend the existing lifespan: after scriber warmup, run the interpreter startup
113
+ sequence exactly as `backend/app/main.py` does today — `validate_runtime_settings()`,
114
+ `init_db()`, then in a DB session `seed_glossary(db)` and
115
+ `crud.purge_old_sessions(db, settings.retention_days)`.
116
+ - Do **not** add the interpreter's CORSMiddleware; the scriber's origin-guard +
117
+ CORS config governs the combined app.
118
+ 3. Leave `backend/app/main.py` untouched — it remains the standalone dev/test app, and
119
+ the interpreter pytest suite keeps running against it unmodified.
120
+ 4. Route collision check: scriber owns `/api/v1/*`; interpreter owns `/api/health`,
121
+ `/api/sessions*`, `/api/turns*`, `/api/admin/*`, `/ws/sessions/*`. `/api/health` and
122
+ `/api/v1/health` are distinct — keep both.
123
+
124
+ Watch-outs:
125
+ - WebSocket route through the combined app: verify `/ws/sessions/{id}` accepts a
126
+ connection (the interpreter e2e covers this in M.5's CI wiring; here a manual
127
+ `pytest`-style check or a small added test against the combined app is enough).
128
+ - The scriber origin-guard middleware only rejects when `CORS_ORIGINS` is set and the
129
+ Origin header mismatches — document in `.env.example` (M.2) that local Vite dev
130
+ origins (`http://localhost:5173`) must be listed when developing against it.
131
+
132
+ **Verify:** `uvicorn carepath.main:app --app-dir apps/api` boots keyless (env:
133
+ `PROVIDER_MODE=mock`, `ASR_PROVIDER=mock`, `ALLOW_MOCK_ASR=true`, `LLM_PROVIDER=offline`)
134
+ and answers `GET /api/v1/health` **and** `GET /api/health`; root `pytest`;
135
+ `python scripts/smoke_backend.py`; `cd backend && pytest`; add one combined-app test
136
+ (root `tests/test_combined_app.py`) asserting both health endpoints and a WebSocket
137
+ handshake on a created session — this test is the ticket's artifact.
138
+
139
+ ### M.2 — Config and env unification
140
+
141
+ 1. Rewrite `.env.example` as one documented file: shared section (nothing collides —
142
+ verified), scriber section (ASR_*, GIPFORMER_*, LLM_*, CORS_ORIGINS, TEAM_CODE,
143
+ SOAP_RATE_LIMIT_*), interpreter section (PROVIDER_MODE, ADMIN_TOKEN,
144
+ CONFIDENCE_THRESHOLD, RETENTION_DAYS, DATABASE_URL, MAX_TURN_AUDIO_BYTES, provider
145
+ models/keys marked "later track — mock mode needs none").
146
+ 2. Defaults must produce a keyless boot: `PROVIDER_MODE=mock`, `LLM_PROVIDER=offline`
147
+ documented as the demo profile. Keep `.env.local.example` / `.env.ckey.example`
148
+ consistent or fold them in — fewest files wins, but don't break
149
+ `scripts/setup_local.ps1`, which copies `.env.local.example`.
150
+ 3. sqlite `DATABASE_URL` default stays (ephemeral on HF Space is acceptable for the
151
+ mock demo; note this in the file).
152
+
153
+ **Verify:** fresh env from the new `.env.example` defaults boots the combined app
154
+ keyless; `python scripts/smoke_backend.py`; `cd backend && pytest`.
155
+
156
+ ### M.3 — Rebrand `site/` to unified CarePath — **ALREADY DONE on the interpreter branch**
157
+
158
+ This ticket was executed by claude-fable-5 directly on `carepath-interpreter-demo`
159
+ before the merge (commit(s) touching `site/` after S.8): brand is now "CarePath"
160
+ (logo/favicon/titles/package `carepath-site`), the landing is a two-module story
161
+ (hero + module tiles + a `#scribe` chapter with a scripted `ScribeShowcase`
162
+ ASR→correction→SOAP walkthrough), and all tests/build/e2e are green.
163
+
164
+ **Your job in this ticket is verification only:** from `site/` run `npm run lint`,
165
+ `npm test`, `npm run build` (diacritics gate), `npm run e2e`; grep gate:
166
+ `grep -ri "carepath translate" site/src` returns nothing. Fix anything the merge broke;
167
+ otherwise commit nothing and move on.
168
+
169
+ ### M.4 — Port the Scribe tool into `site/`, retire the old frontends
170
+
171
+ 1. Rebuild the `apps/web/app` tool (record/upload audio → raw transcript → corrected
172
+ transcript → SOAP draft with retrieved terms) as a React view inside `site/`, using
173
+ the site's design system and `strings.ts` i18n.
174
+ 2. Routing: `site/` has no router — add a **hash route** (`#/scribe`) with a small
175
+ `location.hash` switch in `App.tsx`. No router dependency, no server-side SPA
176
+ fallback needed. Note: the landing already has a `#scribe` **anchor** (the Scribe
177
+ overview chapter with the scripted `ScribeShowcase`) — keep it, and add a "Mở công
178
+ cụ Scribe / Open the Scribe tool" CTA inside that chapter linking to the `#/scribe`
179
+ tool route.
180
+ 3. API calls (see `apps/web/app.js` on `origin/main` for the exact flow):
181
+ - `GET {base}/api/v1/health` for the status badge,
182
+ - `POST {base}/api/v1/soap-notes` (multipart file upload),
183
+ - base URL from `VITE_API_BASE`, defaulting to `""` (same-origin, matching M.5).
184
+ - Handle 400 (bad audio), 413/oversize, and 429 rate-limit responses with bilingual
185
+ messages; support an optional `X-Team-Code` header from a `VITE_TEAM_CODE` env or
186
+ input field (it bypasses the scriber's rate limit — never hardcode a value).
187
+ 4. Mic/consent: the scribe records clinician dictation. Reuse the site's existing
188
+ consent-gate pattern before any `getUserMedia` call (invariant 5) — file upload
189
+ needs no consent gate.
190
+ 5. Delete `apps/web/` and `apps/web-next/` entirely (git history preserves them).
191
+ Remove now-dead references: the `app.mount("/", StaticFiles(directory=WEB_DIR...))`
192
+ block keeps working until M.5 swaps the directory — if `WEB_DIR` points at the
193
+ deleted `apps/web`, make the mount conditional on the directory existing so the API
194
+ still boots; M.5 finishes the job.
195
+
196
+ **Verify:** `site/` lint + test + build + e2e green (add at least one e2e that walks
197
+ the scribe route against a mocked fetch or the local keyless API); combined app still
198
+ boots; `git ls-files apps/web apps/web-next` returns nothing.
199
+
200
+ ### M.5 — Serve the frontends from the API
201
+
202
+ 1. `frontend/` (interpreter console): set Vite `base: "/console/"`, make its API base
203
+ same-origin-relative in production (keep the localhost dev default working).
204
+ 2. Combined app static serving, in this order after all routers:
205
+ - `app.mount("/console", StaticFiles(directory=<frontend/dist>, html=True))`
206
+ - `app.mount("/", StaticFiles(directory=<site/dist>, html=True))`
207
+ - Directories configurable via env (`SITE_DIST_DIR`, `CONSOLE_DIST_DIR`) with those
208
+ defaults; mounts are skipped with a logged warning when the dir is missing (dev
209
+ and CI run the Vite dev servers instead).
210
+ 3. Landing links: Interpreter module CTA → `/console`, Scribe CTA → `#/scribe`.
211
+ 4. WebSocket URL in the console must derive from `window.location` when served
212
+ same-origin (ws/wss scheme).
213
+
214
+ **Verify:** build both frontends, boot the combined app keyless, manually fetch `/`,
215
+ `/console/`, `/api/health`, `/api/v1/health`; `frontend/` mock-mode Playwright e2e
216
+ green; `site/` e2e green.
217
+
218
+ ### M.6 — One CI workflow
219
+
220
+ Merge into a single `.github/workflows/ci.yml` (keep `keepalive.yml` as-is) with jobs:
221
+
222
+ 1. `scriber`: Python 3.12, `pip install -e ".[dev]"`, root `pytest`,
223
+ `python scripts/smoke_backend.py`.
224
+ 2. `interpreter-backend`: `pip install -e "./backend[dev]"`, `ruff check backend`,
225
+ backend `pytest`, eval regression run.
226
+ 3. `combined-app`: install both packages, run the M.1 combined-app test + keyless boot
227
+ check.
228
+ 4. `frontend`: existing lint + vitest job.
229
+ 5. `site`: existing lint + vitest + build (diacritics) job.
230
+ 6. `e2e`: existing Playwright jobs for `frontend/` (against `PROVIDER_MODE=mock`
231
+ backend) and `site/` — preserve their current setup from the interpreter branch's
232
+ ci.yml (S.7 wiring).
233
+
234
+ **Verify:** `git push` the branch and confirm all CI jobs green, or run each job's
235
+ commands locally in a clean venv/node_modules if CI isn't available to you.
236
+
237
+ ### M.7 — Docker / deploy
238
+
239
+ 1. Multi-stage `Dockerfile`:
240
+ - `node:22-slim` stage: `npm ci && npm run build` for `site/` and `frontend/`
241
+ (frontend built with `base=/console/`; site build runs the diacritics gate).
242
+ - Python stage (keep the existing base, env, Gipformer int8 pre-download exactly as
243
+ today): additionally `pip install ./backend`, copy the two dist folders, set
244
+ `SITE_DIST_DIR`/`CONSOLE_DIST_DIR`, same `CMD` (port 7860).
245
+ 2. Update `docs/deploy.md` and `README.hf-space.md`: one Space serves the landing,
246
+ console, scribe, and both APIs; document the interpreter env vars (mock defaults, ADMIN_TOKEN
247
+ note: the combined app runs `validate_runtime_settings`, which only enforces
248
+ ADMIN_TOKEN when `PROVIDER_MODE=cloud`).
249
+ 3. `apps/web-next` is gone — remove Vercel references from docs; note the old Vercel
250
+ project can be deleted.
251
+
252
+ **Verify:** `docker build .` succeeds; `docker run` with no API keys boots and serves
253
+ `/`, `/console/`, `/api/health`, `/api/v1/health`, and a mock `POST /api/v1/soap-notes`
254
+ (smoke-style WAV) — mirror what `scripts/check_goal5_deploy.ps1` checks where practical.
255
+
256
+ ### M.8 — Docs
257
+
258
+ 1. Rewrite `README.md` for the unified product: what CarePath is (two modules), local
259
+ quickstart (one venv, both packages, combined uvicorn command, both frontends),
260
+ keyless demo profile, test commands, deploy pointer.
261
+ 2. Update `AGENTS.md`: unified command list, invariants unchanged, plan pointers —
262
+ `PLAN.md` and `DEMO-SITE-PLAN.md` marked historical (do not delete), `MERGE-PLAN.md`
263
+ marked done, `JUDGE.md` referenced as the review protocol.
264
+ 3. Sweep for stale references: `grep -ri "web-next\|apps/web\b\|carepath translate"`
265
+ across docs and configs; fix stragglers.
266
+
267
+ **Verify:** every command in the new README executes as written on a clean checkout;
268
+ full Verify inventory from §3 green one last time.
269
+
270
+ ---
271
+
272
+ ## 4. Out of scope — do not do
273
+
274
+ - No real interpreter providers (no Gipformer-for-interpreter, no ckey MT/reviewer, no
275
+ new keys). Mock stays.
276
+ - No changes to the GEC training pipeline, notebooks, `scripts/gec/`, or eval datasets.
277
+ - No auth/multi-tenant, no analytics, no new runtime dependencies beyond what this plan
278
+ names (the hash route explicitly avoids react-router).
279
+ - No visual redesign of the S.8 system — extend it.