Signal/CLAUDE.md
sososttil 65d0e13008 fix(auth): stop redirecting sign-in to the dead Vercel origin
signal-ui/src/main.jsx hardcoded WEBAPP_URL to https://signal-ui-xi.vercel.app
and passed it to signInUrl/signUpUrl/afterSignInUrl/afterSignUpUrl. The
production Clerk instance (clerk.sttilsolutions.com) rejects that origin with
400 origin_invalid on every write path, so sign-in was handed back to an origin
that cannot authenticate. Verified live: POST /v1/client/sign_ins returns 400
from the Vercel origin and 200/422 from signal.sttilsolutions.com.

Redirect target now derives from window.location.origin, overridable via
VITE_APP_URL, so it cannot drift from the deployed domain again. Also replaced
afterSignInUrl/afterSignUpUrl with signInFallbackRedirectUrl/
signUpFallbackRedirectUrl, deprecated in Clerk Core 2.

Build verified: pnpm build succeeds, dead Vercel URL absent from dist output.
NOT verified: a real sign-in completing end to end. Needs deploy first.

Also updates the pilot readiness table: hosted-URL row now names
signal.sttilsolutions.com (confirmed canonical by Kisa 2026-07-27), login row
moved from PASS to OPEN. Honest count 11/13 clean, 1 open, 1 disputed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Aqzsyo1PudjabuV9XQzxwp
2026-07-27 19:41:49 -04:00

211 lines
14 KiB
Markdown

# STTIL Solutions — Signal | Active Build Context
## What This Tool Does
Signal is a B2B DMEPOS documentation readiness tracker for CGM suppliers.
It ingests order data from any DME order management CSV export (e.g., Brightree),
evaluates each patient against documentation requirements (6-month qualifying
visit, PECOS enrollment, SWO, resupply eligibility), and produces an actionable
worklist for supplier staff to prioritize outreach and capture revenue before it leaks.
NOTE: Signal identifies gaps. It does not conduct outreach. Never write copy
implying Signal contacts prescribers or patients directly.
## Current State (deprecated — see `context/current-state.md`)
This block is deprecated to stop state drift. The active, canonical project state lives in **`context/current-state.md`** (schema `v:1`). Read and write it via the `state-sync` skill: at session start, `git pull --rebase` then read it; at wrap-up, update ACTIVE/NEXT, append one author-stamped decision, then commit + push. Do not keep rolling state in this file.
## Core Value Proposition
Shifts supplier staff time from reactive (appeals after denial)
to proactive (preventing denial conditions).
The workload curve: appeals volume drops over time as proactive
coverage management replaces it. Outreach volume starts manageable
and stays predictable.
## PHI Architecture — Non-Negotiable
- STTIL never stores patient names, SSNs, DOBs, or contact info
- Sole crosswalk key: patient_id (DME's internal MRN or account #)
- DME staff maintain the patient_id ↔ real identity mapping locally
- AI/calculation layer sees: patient_id, device_type, shipment_date,
quantity, payer — NOTHING else
- All logs use hashed patient_id, never raw
**DISPUTED, awaiting counsel (flagged 2026-07-26).** The bullets above describe an
architecture that excludes direct identifiers, and that is accurate. They do NOT
establish that Signal is therefore PHI-free, and must not be read that way. An
internal account number is one of HIPAA's 18 identifiers, so `patient_id` itself
may be PHI. The attorney bundle sent to Clyde Mathes ~2026-07-23 asks this exact
question and the answer governs. Until it returns, build to the more restrictive
reading: treat `patient_id` as potentially PHI. Cross-reference:
`context/current-state.md` Stack section carries the matching flag.
Never state externally that Signal is HIPAA compliant, holds no PHI, or needs no
BAA; see the NEVER-CLAIM list in `docs/build-plans/03-game-center-token-layer.md:51`.
## Current Stack (Updated 2026-06-22)
- Backend: Railway (Python/FastAPI) — live at <https://signal-api-production-91c2.up.railway.app>
- Database: Supabase (PostgreSQL + RLS policies + Third Party Auth with Clerk)
- Auth: Clerk — production key deployed. Frontend: `pk_live` on Vercel. JWKS: `clerk.sttilsolutions.com/.well-known/jwks.json` on Railway.
- Frontend: Vite/React (signal-ui) — deployed at <https://signal-ui-xi.vercel.app>
- Orgs in Clerk: STTIL Solutions (default), Gaboro DME (org_3EPAEcAw06V2yGMSkxE3UjqIA3c)
## Run Commands
- Frontend (local): `cd signal-ui && pnpm dev` → localhost:5173
- Backend deploy (code change): `railway up --detach` from project root — forces fresh build
- Backend redeploy (no code change): `railway redeploy` — reuses existing image
## Active Files
- signal-ui/src/App.jsx — Clerk auth gate, OrganizationSwitcher
- signal-ui/src/components/WorklistTable.jsx — main worklist display
- signal-ui/src/components/CSVImport.jsx — CSV upload
- signal-ui/src/components/CSVExport.jsx — CSV export
- python-backend/core/coverage_calculator.py — gap detection logic (see Known Bugs)
- python-backend/core/audit_logger.py
- python-backend/core/persistence.py
- python-backend/core/supabase_client.py
- python-backend/api/main.py
- python-backend/api/normalizer.py
- python-backend/config/payer_rules.json
## Known Bugs — Fix Before Pilot
1. ~~**Payer matching**~~ — FIXED 2026-05-29. `_normalize_payer()` added to `coverage_calculator.py`. Handles: "Medicare Part B" → medicare, "Tricare for Life" / "TFL" → medicare, "Medicaid - GA" → medicaid, commercial insurer names → commercial.
2. **Visit date**: coverage_calculator.py uses shipment_date as proxy for qualifying visit, not an actual visit date. Fix: use stored confirmed visit date when available; fall back to shipment_date - 30 days labeled as estimated.
## Features Not Yet Built — Pilot Priority
- **Confirm Visit workflow**: staff button on each worklist row to record a confirmed visit date. Signal stores it against patient_id in Supabase. This is Signal's core persistent value — without it, visit dates never improve beyond estimates.
- **Frontend public URL**: DEPLOYED 2026-05-29 — <https://signal-ui-xi.vercel.app>
- **25 CSV variant test suite**: whitepaper requirement. Generate and test 25 mock CSVs with different column orders, headers, date formats, and payer name variants.
- **Mapping review interface**: confidence score display, user override dropdown per column (per whitepaper spec).
## Pilot Readiness — Authoritative Gauge
**Progress is measured against the whitepaper checklist only. Do not estimate % from feel.**
Whitepaper: `/Users/sttil-solutions/Documents/Obsidian_Vault/STTIL-Vault/Projects/2026-05-18-pilot-readiness-whitepaper.md`
### Checklist Status (updated 2026-07-27) — 11/13 clean, 1 open, 1 disputed
> **Do not quote "100% pilot-ready" or 13/13.** Superseded 2026-07-27. The hosted-URL
> row is now correct (Kisa confirmed `signal.sttilsolutions.com` as canonical, so the
> Clerk `origin_invalid` fault no longer applies to the URL under test). The login row
> is **not** clean: Clerk's `after_sign_in_url` still points at `https://sttilsolutions.com`,
> so a successful sign-in lands on the marketing site rather than the app. That fix
> needs a **production** Clerk secret (`sk_live_`) via the Backend API; the
> `CLERK_SECRET_KEY` currently in `~/.claude/.secrets.env` is `sk_test_` and belongs to
> an unrelated **development** instance (`holy-gar-49.clerk.accounts.dev`, created
> 2026-06-29) — it authenticates with HTTP 200 against the wrong instance, which is why
> its presence is not the same as the blocker being cleared.
> The honest external number is **11 of 13 clean**. Re-test the login row after Fault B
> is fixed; re-counting alone is not enough when a row is stale.
| Checklist Item | Status |
|---|---|
| App hosted behind stable URL | PASS — <https://signal.sttilsolutions.com> (confirmed canonical by Kisa 2026-07-27; the Vercel URL `signal-ui-xi.vercel.app` is NOT canonical and cannot authenticate) |
| Demo login / controlled access working | **OPEN (2026-07-27)** — origin fault resolved by the canonical URL, but Clerk `after_sign_in_url` still redirects to the marketing site. Blocked on a production Clerk secret. Not a PASS. |
| Synthetic sample data loads end to end | PASS — verified as Gaboro DME org 2026-06-10 |
| 25 CSV variants pass ingestion tests | PASS — 50 new files generated (PA + NJ sets), 100% normalizer pass rate 2026-06-07 |
| Import flow: mapping, validation, warnings | PASS — mapping review step built 2026-06-10; confidence display, override dropdown, unmapped column notice, required-missing notice all implemented in CSVImport.jsx |
| Report generation calculates from backend | PASS |
| Each status has reason + recommended action | PASS — visit date proxy bug fixed 2026-06-09; `_resolve_visit_date()` implements full priority chain (CSV column > Supabase confirmed > shipment-30d estimate) |
| Export CSV works and opens cleanly | PASS — verified end to end 2026-06-10 |
| Placeholder content removed | PASS — StatCard undefined variables fixed 2026-06-09; empty state heading "Drop your file here" + StatusLegend below; stoplight colors + ✓ for Clear to Ship; tab counts and percentages; legend bar removed from worklist header — all deployed 2026-06-16 |
| Browser smoke test passes | PASS — CSV import, all filter tabs, Confirm Visit, Export all verified 2026-06-10; sidebar count sync fixed |
| Data handling rules documented | PASS — privacy-policy.md + data-handling.md written 2026-06-07; minimum necessary fields, CSV disposition policy, retention, and payer_rules.json cadence all documented |
| Real PHI blocked | **PASS, BUT DISPUTED (flagged 2026-07-27)** — this PASS rests on the same architecture reading flagged as DISPUTED in the PHI Architecture section above. It is sound in the narrow sense that no real supplier data has been loaded, and unsound as evidence that the design excludes PHI, which is the open question with counsel. Do not cite this row as proof Signal holds no PHI. |
| Pilot success metrics written down | PASS |
Update this table every build session. Re-count PASS items before quoting a % to anyone.
---
## Compliance Readiness Checklist
Source: `/Users/sttil-solutions/Documents/Obsidian_Vault/STTIL-Vault/Projects/2026-06-04-signal-compliance-whitepaper.md`
This checklist tracks compliance gates separately from build readiness. Update it alongside the pilot readiness table above.
### Gate: Pilot (before any supplier sees the product)
| Compliance Item | Status |
|---|---|
| HTTPS enforced across all surfaces | PASS |
| CORS locked to Vercel domain (ALLOWED_ORIGINS env var) | PASS |
| API key auth on upload and export endpoints | PASS |
| Clerk JWT validation active | PASS |
| Supabase RLS enabled | PASS |
| PHI fields (name, DOB, SSN) blocked at normalizer | PASS |
| patient_id as sole crosswalk key | PASS |
| SHA-256 hashed identifiers in all audit log entries | PASS |
| Service role keys absent from frontend env vars (VITE_) | PASS — verified 2026-06-05 |
| Railway-to-Supabase TLS | PASS — Supabase SDK manages SSL at infrastructure level |
| CSV file disposition post-normalization confirmed | PASS — raw bytes discarded; only hash + normalized records persist |
| Audit log WORM enforcement (RLS blocks UPDATE/DELETE on audit_log) | PASS — migration 20260607000001_audit_log_worm.sql applied via CLI 2026-06-07; audit_log table created with RLS + WORM policies live in Supabase |
| PostgreSQL as primary audit log retention sink documented (6-year) | NOT DONE |
| MFA confirmed on all admin accounts (AWS, Supabase, Railway, Vercel, Clerk) | NOT VERIFIED |
| payer_rules.json quarterly update cadence documented | PASS — documented in docs/compliance/data-handling.md 2026-06-07 |
### Gate: First Supplier (before Robert Robinson or any pilot partner uploads data)
| Compliance Item | Status |
|---|---|
| Privacy Policy published at stable public URL | PASS — privacy-policy.md written 2026-06-07; Privacy.jsx deployed to <https://signal-ui-xi.vercel.app/privacy> |
| FDA CDS exemption memo written and attorney-reviewed | NOT DONE |
| Supabase plan tier confirmed (Pro vs Team) and PHI posture documented | PASS — Pro plan confirmed 2026-06-10 ($25/mo). HIPAA available as paid add-on on Team ($599/mo) — deferred to post-funding per Real PHI gate. Pro is correct posture for pilot. |
| Pilot LOI reviewed by attorney | PARTIAL — template ready; **with Clyde Mathes, bundle sent ~2026-07-23, reply expected within days** (corrected 2026-07-26; the prior "Bittinger/Nixon review pending" note was stale) |
| NDA template reviewed by attorney | PARTIAL — template ready; **with Clyde Mathes, same bundle, sent ~2026-07-23** (corrected 2026-07-26) |
| Pilot LOI executed with supplier | NOT DONE |
| NDA executed with supplier | NOT DONE |
| Minimum necessary field documentation written (why each of 5 fields is required) | PASS — documented in docs/compliance/data-handling.md 2026-06-07 |
| Incident response procedure written (includes breach notification timeline) | PASS — docs/compliance/incident-response.md written 2026-06-07 |
| Data retention and deletion procedure written | PASS — retention and deletion policy documented in docs/compliance/data-handling.md 2026-06-07 |
| Deletion procedure tested against Gaboro test batch | NOT DONE |
| Internal tabletop incident exercise completed | NOT DONE |
| Production access scope documented (who has access and why) | NOT DONE |
| CMS AI governance quarterly monitoring cadence set (WISeR reminder) | NOT DONE |
| labABLE kit-in-kit arrangement reviewed for Anti-Kickback Statute exposure | NOT DONE — required before any labABLE agreement is executed |
### Gate: Real PHI (post-funding, before any direct patient identifiers enter the system)
| Compliance Item | Status |
|---|---|
| AWS RDS encryption at rest confirmed when activated | NOT DONE |
| Supabase upgraded to Team plan or replaced with AWS RDS | NOT DONE |
| Railway replaced with BAA-capable host (AWS ECS Fargate or equivalent) | NOT DONE |
| Full HIPAA Security Rule administrative safeguards review with attorney | NOT DONE |
### Gate: Token Layer (before Med Tracker starts)
| Compliance Item | Status |
|---|---|
| Token generation service built | NOT DONE |
| Crosswalk handoff protocol defined for clinic onboarding | NOT DONE |
| Signal updated to accept tokens instead of raw patient_ids | NOT DONE |
## What Is Tabled — Do Not Build Yet
| Item | Phase | Reason |
|---|---|---|
| AWS infrastructure | Post-pilot | Railway is sufficient until live PHI contracts signed |
| Dexcom OAuth API | Phase 2 | Requires vendor agreement + PHI scope expansion |
| Billing system API (Brightree, etc.) | Phase 2 | Build after pilot reveals which systems suppliers use |
| CMS / Salesforce integration | Phase 2 | Pilot feedback needed first |
| Prescriber fax automation | Phase 2 | Manual outreach sufficient for pilot |
| Patient-facing SMS | Phase 3 | PHI transmission requires BAA + consent layer |
| Doc upload + AI validation | Phase 2 | Explicitly deferred |
| Consortium strategy | 18-24 months | Need 15+ paying Level 1 suppliers first |
## Instructions for Claude Code Sessions
- Work only on pilot-scope items from the checklist above
- Never suggest adding PHI fields beyond patient_id
- Flag any vendor integration that would require a new BAA
- When building calculations, reference payer_rules.json for wear days
- When building audit logs, always hash patient_id before storing
- Use "resupply" not "refill" — CGM supply allowances are exempt from Medicare refill rules
- Always calculate progress against the whitepaper checklist table above — not subjective feel
- Before quoting any % complete to Kisa, count the PASS items in the checklist