Signal/docs/support-manual.md
Kisa 7053e4e061 docs: add build spec, support manual, and shared current-state context
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 17:38:31 -04:00

8 KiB

Signal Support Manual

Curated operations knowledge for the Signal CGM documentation readiness platform. Support bot reads this + support-api-ref.json + Barrier Log for troubleshooting. See signal/docs/support-api-ref.json for auto-generated API routes and error codes.


CSV Import

Signal ingests order data from any DME order management CSV export.

Required Columns

Column names are matched case-insensitively. At minimum, the CSV must contain identifying and status fields. Signal evaluates each row against documentation requirements and produces a status per patient.

Column Required Purpose
patient_name Yes Patient identifier
cgm_type Yes Device type for LCD rule matching
sw0_status No Signed written order status
qualifying_visit_date No Last qualifying visit date
pa_status No Prior authorization status
next_shipment_date No Expected resupply date
payer No Payer name for routing checks

If a column is absent, Signal treats the requirement as "not evaluated" — not a gap. This prevents false negatives when a supplier's export format omits fields they don't track.

Validation Rules

  • Rows with empty patient_name are skipped
  • Unknown cgm_type values log a warning and skip LCD matching
  • Date columns must be ISO 8601 (YYYY-MM-DD) or a parseable US format
  • Files over 10MB are rejected (supplier sends manageable subsets)

Error Messages (common)

Error Cause Fix
"Missing required columns" CSV missing patient_name or cgm_type Check export template
"Upload failed — auth error" API key missing or expired Generate new key in Railway env
"Upload failed — CORS error" Frontend domain not in allow list Add domain to ALLOWED_ORIGINS_REGEX
"Upload failed — server error" Backend crashed or timed out Check Railway logs
"No parsable rows found" All rows failed validation Check column names in export

API Reference

See signal/docs/support-api-ref.json for full auto-generated route listing.

Authentication

  • All endpoints require X-API-Key header matching the value in Railway env vars
  • Clerk-authenticated endpoints use Bearer JWT tokens
  • Dev keys are for sandbox only; rotate before any external user accesses the app

Key Endpoints

Endpoint Method Purpose
/api/health GET Health check — returns {"status": "ok"}
/api/upload-csv POST Upload and process CSV file
/api/patients GET List all patients with status summary
/api/patients/{id} GET Single patient detail and cascade
/api/confirm-visit POST Record qualifying visit confirmation
/api/update-doc-status POST Update document status for a requirement
/api/export GET Download Signal Report as CSV

Common Response Codes

Code Meaning Likely Cause
200 Success
400 Bad request Missing or malformed parameters
401 Unauthorized Missing or invalid API key
403 Forbidden Valid key, insufficient scope
404 Not found Patient ID doesn't exist
500 Server error Backend exception (check logs)
503 Service unavailable Database connection issue or deployment cycling

Status Labels

Signal uses 4 UI tabs. The backend computes 8 internal flags that map to these.

Internal Flags (backend)

Flag Meaning Trigger
SUPPLY_LAPSED Patient is past resuppy date next_shipment_date passed
VISIT_REQUIRED 6-month qualifying visit expired qualifying_visit_date > 6 months ago
RENEWAL_CRITICAL Prescription renewal due within 15 days Calculated from renewal date
RENEWAL_ELEVATED Renewal due within 30 days
RENEWAL_SOON Renewal due within 60 days
RESUPPLY_READY All requirements met, ready to ship SWO on file + PA approved + visit current + no cascade gaps
ACTIVE Patient is stable, no flags Nothing due, no gaps
TRANSFER_PENDING Incoming from another supplier Set manually in CSV or UI

UI Tabs (frontend, mapped from internal flags)

Tab Internal Flags Included
At Risk SUPPLY_LAPSED
Action Needed VISIT_REQUIRED, RENEWAL_CRITICAL, RENEWAL_ELEVATED
Clear to Ship RESUPPLY_READY (with no cascade items)
On Track ACTIVE, RENEWAL_SOON, TRANSFER_PENDING, NO_RECENT_SHIPMENT

Documentation Requirements (Cascade)

Each patient has a cascade — a list of documentation actions needed to reach Clear to Ship. Cascade items are only shown when their source column was supplied in the CSV.

Possible Cascade Items

Item Cause Cleared By
Signed Written Order (SWO) sw0_status is not "On File" Update sw0_status or use "Confirm Visit"
Qualifying Visit qualifying_visit_date missing or > 6 months Schedule and confirm visit
Prior Authorization pa_status is not "Approved" Submit PA and update status in CSV
Prescription Renewal renewal_date approaching or passed Obtain new prescription

Common Failures & Resolutions

Issues from the Barrier Log that appear most often. Full history at STTIL-Vault/Projects/Barrier-Log.md.

Uploads Fail Silently

Symptoms: CSV uploads return success but worklist stays empty or shows wrong statuses. No error message shown to user.

Root cause: api.js had catch { return null } blocks swallowing all errors. Fixed by re-throwing real errors and adding toast notifications.

Status: Fixed and deployed. If it recurs, check that:

  1. The frontend is deployed from the fix branch (vercel --prod)
  2. The backend is deployed from the matching fix (railway up --detach)
  3. ALLOWED_ORIGINS_REGEX includes the domain

Clear to Ship Never Goes Green

Symptoms: All patients show amber status, even resupply-ready ones. Green count is permanently 0.

Root cause: The backend scored missing CSV columns as doc gaps. An absent "sw0_status" column meant every patient had a "missing SWO" cascade item. Green = "no cascade items" so green was unreachable.

Fix: Added "supplied" sentinel flags. An absent column is "not evaluated," not a gap. Green means "no known blocker from the data provided."

Status: Fixed and deployed. Verify by uploading a CSV with resupply-ready patients — they should show green.

CORS Errors on Vercel Deploy

Symptoms: Upload fails with browser CORS error on preview URLs.

Root cause: ALLOWED_ORIGINS was a fixed list. Vercel preview URLs (project-xxxx.vercel.app) weren't included.

Fix: Changed to ALLOWED_ORIGINS_REGEX to accept *.vercel.app patterns.

Status Count Mismatch (Stat Card vs Row Count)

Symptoms: The stat card shows a different green count than filtering by "Clear to Ship" tab.

Root cause: Stat card counted RESUPPLY_READY. Tab counted RESUPPLY_READY AND cascade empty. Cascade was never empty (see above).

Fix: Both now use the same logic: RESUPPLY_READY with no cascade gaps.


Known Issues (Active)

Issue Status Workaround
Clerk production migration deferred Blocking real supplier login Use sandbox keys for dev; manual Google OAuth setup needed
Gaboro demo API key in Railway env Security risk before external access Rotate before Robert Robinson pilot
granola-ingest portable path Needs path update Script works from full path; symlink/alias pending

Cross-References

  • State machine code: python-backend/core/doc_state_machine.py
  • Cascade builder: python-backend/core/doc_state_machine.py (_build_cascade)
  • Frontend status mapping: signal-ui/src/components/WorklistTable.jsx
  • Upload handler: signal-ui/src/lib/api.js
  • API auth: python-backend/api/main.py (X-API-Key middleware)
  • Barrier Log (all resolved issues): STTIL-Vault/Projects/Barrier-Log.md
  • TriLane research library: Signal workspace (research docs, payer matrix, synthesis)