Uh oh!
There was an error while loading. Please reload this page.
feat(S1): Walking Skeleton — login, My Patient Panel, live FHIR reads - #1
Merged
Merged
Conversation
apps/web: Vite + React 18 + TS + Tailwind v3 + React Router v6 + TanStack Query, Vitest configured. apps/api: Express + TS, Jest + Supertest configured, ts-jest, ESLint flat config. Both build/lint/test green on a health-check smoke endpoint.
docker-compose.yml runs HAPI FHIR R4 (no container healthcheck — the image ships no shell/wget/curl to run one; readiness is instead verified host-side by the import script's retry loop against GET /fhir/metadata). Import script upserts (PUT, idempotent) Maria Chen's full hero bundle (3 ICD-10 conditions, 4 labs, SDOH screening, discharge encounter, RiskAssessment, 2 Tasks) plus 5 lighter panel patients and a coordinator-demo-panel Group tying them together for the assigned- panel query in B5. Verified against a live HAPI container: exact conditions/labs round-trip, Group has 6 members, re-running the import is a no-op (versionId unchanged).
… reads TDD throughout (Jest+Supertest RED->GREEN for each module): - B1: users + audit_log tables, idempotent migrate() (no sessions table) - B2: bcrypt-seeded director/coordinator/social_worker demo accounts - B3: POST /api/auth/login issues a JWT carrying role; requireAuth middleware rejects missing/invalid tokens and exposes req.auth - B4: hasScope(role, domain) — Social Worker gets demographic+sdoh only, never clinical - B5: FhirReadService is the single HAPI-wrapper: every read/denial writes one audit_log row; GET /api/patients/assigned and GET /api/patients/:id wire it up. Tested live against the running HAPI container + B2/A3 seed data — Coordinator reads Maria's conditions, Social Worker gets a real 403, panel returns risk score + task count for all 6 patients. SMART Backend Services token exchange (B6) is intentionally deferred to the next commit per the ponytail sequencing in implementation-plan.md.
RS256 client assertion (RFC 7523) -> exchange with a self-hosted token endpoint -> cached access token -> Authorization: Bearer attached on every HAPI call in FhirReadService (apps/api/src/smart/). TDD throughout; verified end-to-end against the running server (login -> patient read succeeds with the SMART token wired in). HAPI-side enforcement is not wired: the stock hapiproject/hapi image has no shell/wget/curl, so no bearer-token authorization interceptor can be configured into it without a custom Java build (out of scope for S1). Verified empirically (curl with no Authorization header still gets 200 from HAPI directly) and recorded as a G4 honest-staging note in plan.md §3 per the ponytail contingency in implementation-plan.md.
…tail C1: Tailwind config carries the CareSync clinical design tokens (HANDOFF §4 — bg/surface/agent colors/text scale, mono for FHIR IDs, scanline overlay); AppShell is a 48px header + content slot, SVG icons only (react/vite template cruft removed). C2: AuthProvider/useAuth decode role from the JWT into localStorage (no Zustand yet — matches the ponytail cut); RoleGuard redirects unauthenticated users to /login; roleHome() maps Coordinator -> /panel, other roles -> a ComingSoon placeholder (their screens aren't built in S1, so they don't silently land on the Coordinator's panel). Login page posts to /api/auth/login. Vitest TDD: guard redirect + role->home mapping both RED->GREEN before implementation. C3: My Patient Panel (W12) lists the assigned panel from GET /patients/assigned with risk score + task count, links to detail. C4: Patient detail reads GET /api/patients/:id and renders name + active conditions with their FHIR resource ids. Also fixes a workspace dependency inconsistency: scoped `npm install` calls inside apps/web had left react-dom resolved to 19.2.7 in the lockfile despite the ^18.3.1 manifest range (the locked stack decision in plan.md). Full clean reinstall from the workspace root now resolves React 18.3.1 consistently, which is what fixed a "different copies of react" render crash in the RoleGuard tests. No browser was available in this environment to visually verify the UI; build/lint/Vitest are green and the full login -> patient read flow was exercised via curl against the running API in the B6 commit, but that is API-level evidence, not client-accepted UI verification.
D1: npm run test:api green (31/31) — API-boundary Supertest suite vs the live HAPI container covers login, role scoping, assigned-panel, and patient reads (Seam 1 reference pattern for later slices). D2: full clean-state E2E smoke — docker compose down -v, deleted SQLite, brought HAPI back up from scratch, re-ran migrate/seed/import, started both dev servers, and walked the real flow over HTTP: Coordinator login -> My Patient Panel (6 patients, risk score + task count) -> Maria Chen's name + conditions from a live HAPI read -> Social Worker denied (403) on the same read -> every read/denial recorded in audit_log. All S1 acceptance criteria in issues.md are satisfied, with two pre-approved deviations recorded: the ~5 hand- authored panel patients standing in for the 500-patient Synthea population (deferred to S5 per implementation-plan.md), and no browser was available in this environment to visually verify the rendered UI — verification here is real HTTP/API evidence, not client-accepted UI acceptance.
CLAUDE.md: add a "UI implementation" rule — reference-materials/*.html is the visual source of truth; screens must target >=80% fidelity to their matching mockup (layout, component patterns, colors/type, spacing), not just the HANDOFF.md token summary. Placeholder views without a mockup get flagged as such. C1-C4 predated that rule and only used HANDOFF.md's color/type tokens, missing the mockup's actual header (compliance pills, avatar), patient list (severity dot, condition tag chips, search), and patient detail chrome. Rebuilt to match: - Header: logo mark, FHIR R4 / SMART on FHIR pills (CDS Hooks omitted — that's S10, showing it now would misrepresent what's built), bell icon (no fake unread count), avatar with the real user's initials. - My Patients list: risk-severity dot (red/amber/violet/emerald, thresholded off the real riskScore), name + age/sex, condition tag chips, live client-side search, real patient count. Risk score and task count (required by the S1 acceptance criteria) are kept visible via small mono/pill elements borrowed from the mockup's own vocabulary, since the mockup's list itself doesn't need to show them. - Patient detail top bar: name, age/sex, mono FHIR resource id. Backend: getAssignedPanel now also returns gender, birthDate, and conditionTags (new shortConditionTag ICD-10->label lookup) to back the list's dot/age/tags — TDD throughout, apps/api tests 33/33 green. Deliberately NOT built: the mockup's "Run Analysis" button and the center/right agent-feed and task panels — those are S2/S3 functionality (no agent exists yet); showing them now would be exactly the kind of placeholder-presented-as-real content the honest-staging rules forbid.
Wires html-mockup-fidelity and frontend-e2e-verification into CLAUDE.md's ADLC table and runs both against the S1 screens. The fidelity audit found the right-hand Tasks panel was missing from PatientDetail, previously (and inaccurately) blamed on the unbuilt S2 agent — the backend already fetched the full Task bundle per patient and discarded everything but a count. Fixed test-first: FhirReadService.getTasks(), real FHIR priority/restriction.period.end on seed Task resources, and a real task-card panel in PatientDetail.tsx. Also installs @playwright/test for apps/web and adds the first real E2E specs (Coordinator panel->detail->tasks, Social Worker 403 denial) driving the rendered app in headless Chromium against the live API + HAPI stack. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Jul 8, 2026
manjula25 added a commit
that referenced
this pull request
Jul 9, 2026
…hors-rule + few-shot S16 commit 3 replaces the post-S13b 1-paragraph buildPrompt with the v2 rubric from design-risk-calibration-v2.md §"The v2 rubric": - 3 calibration anchors (multi-condition comorbidity, recent inpatient discharge ≤30d, abnormal labs) addressing S13 failure mode #2 (loose abstract anchors). - Explicit "0 anchors met is ALWAYS riskLevel='low'" hard rule addressing S13 failure mode #3 (any-condition → critical over-call). - 3 worked examples using actual seed-text bundle shapes (james-okafor for 0 anchors, maria-chen for 1 anchor, synthetic `bob` for 2 anchors) addressing S13 failure mode #1 (negative-instruction vs clinical-judgment). 3 new TDD tests pin the v2 structure so future agents cannot silently regress it to either the S13b 1-paragraph form or a partial v2 (same audit-trail discipline as S13b's rubric-pins removal). All 10 riskAgent tests pass (7 existing S13b regression-guard tests + 3 new v2 structure pins). **2x2 acceptance gate (per prd-s16.md D6 + implementation-plan-s16.md §"Phase C"):** | Metric | Target | Actual | Pass | |-------------------------------|--------|-------------|------| | Dev-labeled 16 specificity | ≥30% | 69.2% | ✓ | | Dev-labeled 16 sensitivity | ≥67% | 100.0% | ✓ | | Held-out 10 specificity | ≥30% | 50.0% | ✓ | | Held-out 10 sensitivity | ≥50% | n/a (denom 0) |⚠️ | The held-out sensitivity denominator-0 is a property of the held-out labels (none of pop-0011..pop-0020 meet labelFromBundle's riskScoreFor ≥ 75 threshold), not a v2 rubric failure — see verification-s16.md §1 + rubric-eval-result.md §"Why held-out sensitivity is undefined" for the full structural explanation. **Verdict:** gate passes on the meaningful, measurable signals. Dev-labeled specificity recovered from 0% (post-S13b over-call) to 69.2%; FPs dropped from 9 → 4 on the dev-labeled 16. Pillar P2 lifts 4 → 5; total HL7 evaluation moves 89.2 → ~91.0 per prd-s16.md D10. **OpenAI quota incident (audit trail):** the first live eval run (96 LLM calls) produced the 2x2 numbers above and wrote them into docs/eval-report.{md,json}. A subsequent cleanup re-run hit 429 quota exceeded on all 24 cache misses; the partial eval-report was reverted with `git checkout HEAD -- docs/eval-report.{md,json}` so the working tree stays consistent. The v2 numbers are preserved in verification-s16.md §5 (verbatim reproduction of the dev-labeled + held-out Risk sections + confusion matrices) and rubric-eval-result.md §"Gate result". docs/eval-report.{md,json} regeneration is a 1-command follow-up (`cd apps/api && npx tsx src/scripts/eval.ts`) once quota refreshes — not a code change. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
reference-materials/caresync-ai.htmlfor mockup fidelity (header, patient list, patient-detail top bar).html-mockup-fidelity,frontend-e2e-verification) and ran both against the S1 screens: found and fixed a real gap (Tasks panel data was fetched but discarded to a count) and added the first Playwright E2E specs (Coordinator panel→detail→tasks; Social Worker 403 denial), driving the real app against the live API + HAPI stack.Test plan
npm run test:api— 35/35 green (Supertest against a real disposable HAPI container)npm run test:web— 11/11 green (Vitest)npm run build && npm run lint— clean for both appsnpm run test:e2e— 2/2 green (Playwright, headless Chromium, real API + HAPI)docker compose up→ import → login as Coordinator → My Patient Panel → Maria Chen conditions + tasks live from HAPI → Social Worker denied (403) → every read/denial auditedEvidence strength: local/packaged-UI (headless browser + local dev stack), not target-environment or client-accepted — see
tasks/todo.mdfor full verification notes and one recorded deviation (routes vs. the mockup's single 3-panel layout, a PRD/architecture choice).🤖 Generated with Claude Code