Pratyush Singh
Back to all work

StrideAI

How do you launch an AI recommendation where a bad call can injure someone? I ran an adaptive running coach as a full technical program: charter, RAID log, five architecture decisions, an executive status, and a rollout gated on evidence. Then I built it, as a FastAPI service with 171 tests and an iOS companion. Real validation ended up changing what "a good recommendation" means.

Role
Independent build: program lead, PM and engineer
Stack
Python, FastAPI, SQLite, OpenAI Responses API, Expo/React Native
Program artifacts
Strategy, 5 ADRs, backlog, RAID, eval framework, exec status
Evidence
171 automated tests, CI, regression gates

Core principle: rules decide, the LLM explains

Telling a runner to push through fatigue is a safety decision. So the training call is made by deterministic logic that is predictable, testable and auditable. The LLM receives an evidence package containing the decision that's already been approved, and it can only explain it. If its output is invalid or contradicts the decision, the system falls back to a deterministic explanation.

  1. Workout and recovery signals go into deterministic decision logic, with hard safety overrides.
  2. Historical retrieval builds an immutable evidence package.
  3. An optional LLM explanation is written from that package.
  4. An action-consistency guardrail rejects explanations that change the decision or make unsupported numeric claims.
  5. The recommendation and its trace are stored. Outcomes and overrides flow back into metrics and a regression gate.

The program

Before writing code, I planned it the way I'd run it with a real team: a six-week delivery plan, a Jira-style backlog, and five ADRs (async processing, safety rules, a confidence engine, a wearable abstraction layer, and LLM explanation).

RAID log, excerpt

RiskImpactTriggerMitigationContingency
Recommendation quality below thresholdCriticalWeek-3 gate missedFatigue task force, alternative signalsControlled rollout
Insufficient recovery dataHighMissing critical signalsLower confidence, alternative signalsNo auto-adjustment
Wearable API instabilityHighError or sync spikeRetry, monitoring, abstraction layerSafe no-adaptation mode
User distrustHighAcceptance falls, overrides riseExplanations plus user controlRevisit strategy
Safety defectCriticalConfirmed critical violationDeterministic rules plus testsImmediate pause or rollback

The log also tracks four assumptions with owners and how each gets validated, and five critical-path dependencies, from the Garmin API through the fatigue model to the mobile contract and safety sign-off.

The rollout decision

The executive status is a week-3 scenario: the fatigue model's expert agreement comes in at 74% against an MVP bar of 80%, a few weeks before a launch tied to a commercial partnership. Delaying risks the partnership. Launching at 100% risks the trust the product depends on.

My recommendation: protect the date with controlled exposure, and protect the quality bar with gates. Internal, then beta, then 20%, 40% and 100%. Rollout percentage is decided by evidence, not by calendar dates.

The status report asks leadership for exactly one decision: approve the controlled rollout and its predefined quality and safety gates.

The 74% figure is a simulated planning scenario, used to practise the call. It isn't a measured result.

The build

I then built it in five milestones, each with tests:

  1. Deterministic API. A FastAPI endpoint with typed contracts, fatigue and risk rules, safety overrides, and autonomy based on confidence.
  2. Guarded explanation. Historical retrieval, the evidence package, optional LLM explanations, a deterministic fallback, and tracing of latency, tokens and fallbacks.
  3. Real data. Garmin and Strava file ingestion, SQLite persistence, Docker and CI.
  4. Quality loop. Acceptance, override and outcome-coverage metrics, groundedness and unsupported-number checks, regression gates and a small dashboard.
  5. Accumulated recovery debt. 3-day and 7-day recovery windows, repeated short-sleep detection, HRV against the wearable's own baseline range, and resting-heart-rate trends.

The iOS companion (Expo and React Native) syncs HealthKit data, backfilling up to 35 days. On the baseline evaluation set the engine scores full action accuracy with zero safety violations.

What validation changed

The first retrospective comparison against one athlete's sanitized wearable history made StrideAI look too conservative. The athlete kept choosing to maintain training while the engine kept suggesting a reduction. Then a target race came in well below expectation, and in hindsight the athlete judged those warnings as directionally right.

The lesson: agreement with the user's morning decision is the wrong success metric for a coach. So the system now keeps three things separate: what the athlete decided at the time, what StrideAI recommended, and the later assessment with the outcome known. It also stopped judging today's snapshot alone. One bad night now raises a warning without changing the plan; repeated poor recovery escalates step by step to less intensity, then less volume, then human review.

Limits I'd state in an interview: the real validation sample is small and retrospective, and it doesn't prove that following StrideAI would have improved the result. What it does show is evidence changing a product hypothesis without rewriting the original labels.