app/CLAUDE.md
John Mizerek 151106aa8e Initial commit: Add Months MVP
Local-first Flutter app that identifies the single behavioral change
most likely to extend lifespan using hazard-based modeling.

Features:
- Risk engine with hazard ratios from meta-analyses
- 50 countries mapped to 4 mortality groups
- 6 modifiable factors: smoking, alcohol, sleep, activity, driving, work hours
- SQLite local storage (no cloud, no accounts)
- Muted clinical UI theme
- 23 unit tests for risk engine

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-20 21:25:00 -08:00

7.4 KiB
Raw Blame History

Add Months

Local-first Flutter app that identifies the single behavioral change most likely to extend lifespan using hazard-based modeling.

Quick Start

flutter pub get
flutter test test/risk_engine/    # 23 unit tests
flutter run                       # Debug mode
flutter run --release -d <device> # Release build

Architecture

lib/
├── main.dart                 # App entry, routing logic
├── theme.dart                # Muted clinical color palette
├── models/
│   ├── enums.dart            # Sex, SmokingStatus, AlcoholLevel, etc.
│   ├── user_profile.dart     # Age, sex, country, height, weight, diagnoses
│   ├── behavioral_inputs.dart # Modifiable behaviors
│   └── result.dart           # LifespanDelta, RankedFactor, CalculationResult
├── risk_engine/
│   ├── hazard_ratios.dart    # HR constants from meta-analyses
│   ├── mortality_tables.dart # 50 countries → 4 mortality groups
│   └── calculator.dart       # Core ranking algorithm
├── screens/
│   ├── welcome_screen.dart   # Onboarding
│   ├── baseline_screen.dart  # Demographics, BMI, conditions
│   ├── behavioral_screen.dart # Modifiable factors input
│   └── results_screen.dart   # Dominant challenge display
└── storage/
    └── local_storage.dart    # SQLite persistence

Core Principles

  1. Local-first: All data on device, no cloud, no accounts, no analytics
  2. Evidence-based: Hazard ratios from peer-reviewed meta-analyses
  3. Privacy: Delete All Data = full wipe including encryption keys
  4. Neutral tone: "Exposure", "Factor", "Estimated gain" — no moral language

Risk Engine

Hazard Ratio Model

Combined HR = Smoking × Alcohol × Sleep × Activity × BMI × Driving × WorkHours

Capped at 4.0 to prevent unrealistic compounding.

Key Hazard Ratios

Factor Level HR
Smoking Never 1.0
Former 1.3
Current (<10/day) 1.8
Current (10-20/day) 2.2
Current (>20/day) 2.8
Alcohol None/Light 1.0
Moderate (8-14/wk) 1.1
Heavy (15-21/wk) 1.3
Very Heavy (21+/wk) 1.6
Sleep 7-8 hrs 1.0
6-7 hrs 1.05
<6 hrs 1.15
>8 hrs 1.10
+ Inconsistent ×1.05
Activity High 1.0
Moderate 1.05
Light 1.15
Sedentary 1.4
BMI 18.5-25 1.0
25-30 1.1
30-35 1.2
35-40 1.4
40+ 1.8
Driving <50 mi/wk 1.0
50-150 1.02
150-300 1.04
300+ 1.08
Work Hours <40 1.0
40-55 1.05
55-70 1.15
70+ 1.3

Existing Conditions (Non-modifiable)

Condition HR Multiplier
Cardiovascular 1.5
Diabetes 1.4
Cancer (active) 2.0
COPD 1.6
Hypertension 1.2

Delta Calculation

// Simplified Gompertz-style approximation
rawDeltaYears = baselineYears × (1 - modifiedHR/currentHR) × 0.3

// Convert to months with uncertainty range
lowMonths = rawDeltaYears × 12 × 0.6
highMonths = rawDeltaYears × 12 × 1.4

Ranking Algorithm

  1. For each modifiable behavior:
    • Compute HR with behavior set to optimal
    • Calculate delta months gained
  2. Sort by midpoint delta descending
  3. Filter out behaviors already at optimal
  4. Return ranked list with confidence levels

Confidence Levels

Factor Confidence Rationale
Smoking High Extremely well-documented
Alcohol (heavy) High Strong epidemiological data
Physical Activity High Large meta-analyses
BMI (extreme) High Well-established
Sleep Moderate Growing evidence, some confounding
Work Hours Moderate Decent studies, cultural variation
Driving Emerging Harder to isolate, regional variation

Mortality Tables

Country Groups

Group LE at Birth (M) Countries
A 81 Japan, Switzerland, Singapore, Spain, Italy, Australia, Iceland, Israel, Sweden, France, South Korea, Norway
B 77 USA, UK, Germany, Canada, Netherlands, Belgium, Austria, Finland, Ireland, New Zealand, Denmark, Portugal, Czech Republic, Poland, Chile, Costa Rica, Cuba, UAE, Qatar, Taiwan
C 72 China, Brazil, Mexico, Russia, Turkey, Argentina, Colombia, Thailand, Vietnam, Malaysia, Iran, Saudi Arabia, Egypt, Ukraine, Romania, Hungary, Peru, Philippines
D 65 India, Indonesia, South Africa, Pakistan, Bangladesh, Nigeria, Kenya, Ghana, Ethiopia, Myanmar, Nepal, Cambodia

Female LE = Male LE + 4.5 years

Remaining Life Expectancy

// Survivors have higher LE than birth cohort suggests
survivorBonus = currentAge × 0.15  // capped at 5
remainingLE = (leAtBirth - currentAge) + survivorBonus

Storage

SQLite Schema

CREATE TABLE user_data (
  key TEXT PRIMARY KEY,
  value TEXT NOT NULL,      -- JSON
  updated_at INTEGER NOT NULL
)

Stored Keys

  • profile: UserProfile JSON
  • behaviors: BehavioralInputs JSON
  • lastResult: CalculationResult JSON

Delete All Data

await db.delete('user_data');  // Wipes all rows

UI Theme

Colors (Muted Clinical)

primary:       #4A90A4  // Muted teal
primaryDark:   #2D6073
primaryLight:  #7BB8CC
surface:       #F8FAFB
textPrimary:   #1A2B33
textSecondary: #5A6B73
success:       #4A9A7C
warning:       #B8934A
error:         #A45A5A

Typography

  • Headlines: SF Pro Display style, tight letter-spacing
  • Body: 16px, 1.5 line height
  • Labels: 600 weight

Testing

# Run all risk engine tests
flutter test test/risk_engine/

# 23 tests covering:
# - Hazard ratios for each behavior
# - Mortality table lookups
# - Combined HR calculation
# - Ranking algorithm
# - Confidence assignments
# - Existing conditions impact

Widget tests require SQLite mocking — integration test on device.

App Icon

Generated programmatically: muted teal tree on white background.

dart run tool/generate_icon.dart
dart run flutter_launcher_icons

Model Versioning

const modelVersion = '1.0';

Stored with each calculation result. Future updates can show: "Results updated under model v1.1"

Screen Flow

Welcome → Baseline → Behavioral → Results
              ↑                      ↓
              └────── Recalculate ───┘

Results screen shows:

  • Dominant Challenge (largest gain)
  • Estimated Gain range (e.g., "36-60 months")
  • Confidence level (High/Moderate/Emerging)
  • Secondary factor
  • All other factors (if any)
  • Delete All Data button

Key Design Decisions

  1. BMI is baseline only — affects calculation but not shown as a "challenge"
  2. Cigarettes/day — slider with haptic at 20 (one pack), max 40
  3. Country — full dropdown (50 countries), mapped internally to groups
  4. No gamification — no streaks, badges, or progress tracking
  5. No notifications — user controls when to recalculate

Dependencies

dependencies:
  sqflite: ^2.3.0         # Local database
  path: ^1.8.3            # Path utilities
  flutter_secure_storage: # Encryption key storage (future)

dev_dependencies:
  flutter_launcher_icons: ^0.14.1

Future Enhancements (Out of MVP Scope)

  • Partner mode (compare two profiles)
  • Export PDF summary
  • Drug use factor
  • Diet quality factor
  • Stress/mental health factor
  • Location-based mortality refinement
  • Longitudinal tracking