Backend: orchestrator API, PRD-aligned scoring, multimodal fusion + safety#2
Open
jasonca2023 wants to merge 9 commits into
Open
Backend: orchestrator API, PRD-aligned scoring, multimodal fusion + safety#2jasonca2023 wants to merge 9 commits into
jasonca2023 wants to merge 9 commits into
Conversation
- FastAPI app on :8001 — /stimulus/send, /response/submit, /score, /brain, /history, /stimuli, /health - Orchestrates signals (8002) + ML (8003); degrades to local fallback scoring when either is offline so the backend runs standalone - SQLite via SQLAlchemy: users, sessions, score_records (+ raw signal history) - shared/contract.json reconciled to the live signals stimulus shape; shared/stimuli.json canonical manifest (mirrors signals bank ids/baselines) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eo endpoints
- Restructure to prefix-based routers: /stimulus, /response, /score, /brain, /history, /metrics, /video
- Contract v2: stimulus {type,url,category,prompt}; user_response +response_latency_ms +source(app|sms); burnout_result +breakdown{imessage,typing,facial,voice,tribe}
- New: GET /metrics (trend + latest breakdown + total), POST /video/submit (forwards to video svc :8004, VideoRecord table)
- Rename tribe_client -> ml_client (+get_baseline); add video_client; signal_client.send_alert matches Dhruva's live POST /alert (requires phone)
- /stimulus/today daily rotation; /score returns friendly default before first check-in; keeps graceful fallback when signals/ML/video offline
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eo service
- /video/submit now reads top-level combined_score from the video service response and persists it (VideoRecord.combined_score)
- contract.json: video /analyze/video documented as -> { facial{facial_stress_score,...}, voice, combined_score }
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…hone) + /register-phone
- signal_client.send_alert now POSTs /alert/send {user_id, score, level, intervention} (phone removed; signals looks it up)
- add signal_client.register_phone -> POST /register-phone
- response.py fires the red alert without a phone gate (signals owns phone lookup)
- contract.json: document real signals endpoints (/alert/send, /register-phone, /send-checkin, /sms/webhook, /signals/{id}/history) and flat /analyze response
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…afety, brain explanations - Multimodal fusion (PRD 4.5): /video/submit fuses facial+voice into a burnout score (facial weighted highest), stored source=video; breakdown surfaces facial/voice; /response/submit folds in latest video signals - Safety (PRD 6): new safety.py enforces that every RED result carries a human-support path (988 + Crisis Text Line + campus counseling + trusted contact); applied in response + video routes and burnout_result.support - Brain (PRD 5.2): /brain returns plain-English, non-clinical region explanations - contract.json: burnout_result +support +source(app|sms|video); /video/submit returns burnout_result; raw video never stored (PRD 8) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Hi @jasonca2023! 👋
Your private repo does not have access to Sourcery.
Please upgrade to continue using Sourcery ✨
…stent /score default + SQLite busy timeout QA pass (28/28 edge-case tests green): - scoring helpers coerce None/strings and clamp out-of-range so the fallback path never 500s (negatives, huge values, null combined_signal_score, etc.) - SAFETY: normalize_ml_result reconciles level with score — an invalid level derives from score, and a red-range score (>=65) is never downgraded, so the human-support path always attaches (PRD 6) - /score default (pre-first-checkin) now returns the full burnout_result shape incl. support[] so the frontend never hits a missing key - SQLite busy timeout (30s) so concurrent app + SMS writes don't error with 'database is locked' Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Found by a 30-way concurrent first-submit stress test (app + SMS hitting a brand-new user at once), which previously TIMED OUT every request: - ensure_user did get-then-insert with no IntegrityError handling; a losing race left a failed transaction holding the SQLite write lock, stalling all other requests until timeout. Now catches IntegrityError, rolls back, and reuses the row the winner created. - SQLite: enable WAL journal mode + busy_timeout=8s + synchronous=NORMAL, and a larger pool (20+30), so concurrent reads/writes don't block. .gitignore covers -wal/-shm sidecars. Verified: 30x6 concurrent submits + 15 concurrent video = 0 failures; 28/28 regression still green. Co-Authored-By: Claude Opus 4.8 <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 free
to 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.
Backend (orchestrator) —
feat/jason-api→devFastAPI orchestrator on :8001 + SQLite. Wesley's app and Dhruva's SMS bot both call this service; it calls signals (:8002), ML/TRIBE (:8003), and video (:8004), stores everything, and serves history/metrics/brain.
Endpoints
GET /health,GET /stimulus/today/{user_id},GET /stimulus/allPOST /response/submit(app + sms) — orchestrates signals → ML → store → red alertGET /score/{user_id},GET /history/{user_id},GET /metrics/{user_id}GET /brain/{user_id}— TRIBE regions + plain-English explanationsPOST /video/submit— fuses facial + voice into a burnout scorePRD alignment
breakdown= {imessage, typing, facial, voice, tribe}; video check-ins move the score (facial weighted highest).Resilience
Degrades gracefully: if signals / ML / video are offline, returns a fallback result (
source=fallback) instead of erroring, so the backend runs standalone for the demo.Contract
Updates
shared/contract.json(owned here): stimulus shape,user_response(+sourceapp|sms),burnout_result(+breakdown, +support), and the real signals endpoints (/alert/send,/register-phone).🤖 Generated with Claude Code