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

277 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Add Months
Local-first Flutter app that identifies the single behavioral change most likely to extend lifespan using hazard-based modeling.
## Quick Start
```bash
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
```dart
// 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
```dart
// Survivors have higher LE than birth cohort suggests
survivorBonus = currentAge × 0.15 // capped at 5
remainingLE = (leAtBirth - currentAge) + survivorBonus
```
## Storage
### SQLite Schema
```sql
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
```dart
await db.delete('user_data'); // Wipes all rows
```
## UI Theme
### Colors (Muted Clinical)
```dart
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
```bash
# 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.
```bash
dart run tool/generate_icon.dart
dart run flutter_launcher_icons
```
## Model Versioning
```dart
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
```yaml
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