HealthProbe / AGENTS.md
Newer Older
248 lines | 9.416kb
Bogdan Timofte authored a month ago
1
# HealthProbe – Multi-Model Development Guide
2

            
3
## Overview
4

            
5
HealthProbe is built by multiple AI models, each owning a distinct domain.
6
This document defines boundaries, interfaces, and handoff contracts.
7

            
8
---
9

            
10
## Model Allocation
11

            
12
| Domain | Owner | Tools |
13
|--------|-------|-------|
14
| **UI / SwiftUI Views** | Claude Code | Xcode, SwiftUI, CLAUDE.md |
15
| **Data Models (SwiftData)** | Dedicated model session | Xcode, Swift |
16
| **HealthKit Integration** | Dedicated model session | Xcode, HealthKit docs |
17
| **Anomaly Detection Algorithms** | Dedicated model session | Swift, statistical references |
18
| **Sync Monitoring** | Dedicated model session | Xcode, CloudKit docs |
19
| **Documentation** | Claude Code + dedicated session | Markdown |
20
| **Tests** | Dedicated model session | XCTest, Swift Testing |
21

            
22
---
23

            
24
## Directory Ownership
25

            
26
```
27
HealthProbe/
28
├── Views/           ← Claude Code (UI)
29
├── ViewModels/      ← Claude Code (UI)
30
├── Utilities/       ← Claude Code (shared helpers, mocks)
31
├── Models/          ← Models agent (SwiftData schemas)
32
├── Services/        ← Services agent (HealthKit, anomaly, sync)
33
└── Tests/           ← Tests agent
34
```
35

            
36
**Rule:** Each agent writes only within its owned directories.
37
Cross-boundary changes require an explicit interface contract (protocol) first.
38

            
39
---
40

            
41
## Interface Contracts
42

            
43
All service boundaries are defined as Swift protocols.
44
Claude Code (UI) consumes protocols — never concrete implementations.
45

            
46
### HealthMonitorProtocol
47

            
48
```swift
49
/// Owned by: Services agent
50
/// Consumed by: UI (DashboardViewModel)
51
protocol HealthMonitorProtocol {
52
    var currentStatus: HealthStatus { get }
53
    var lastChecked: Date? { get }
54
    func runCheck() async throws
55
}
56
```
57

            
58
### AnomalyStoreProtocol
59

            
60
```swift
61
/// Owned by: Services agent
62
/// Consumed by: UI (AnomalyListViewModel)
63
protocol AnomalyStoreProtocol {
64
    var anomalies: [DetectedAnomaly] { get }
65
    func markResolved(_ anomaly: DetectedAnomaly) async throws
66
}
67
```
68

            
69
### AuditTrailProtocol
70

            
71
```swift
72
/// Owned by: Services agent
73
/// Consumed by: UI (AuditTrailView)
74
protocol AuditTrailProtocol {
75
    var entries: [AuditTrailEntry] { get }
76
    func export() async throws -> Data  // JSON
77
}
78
```
79

            
80
### SyncMonitorProtocol
81

            
82
```swift
83
/// Owned by: Services agent
84
/// Consumed by: UI (SyncViewModel)
85
protocol SyncMonitorProtocol {
86
    var iCloudEnabled: Bool { get }
87
    var lastSyncDate: Date? { get }
88
    var stateChanges: [SyncStateChange] { get }
89
}
90
```
91

            
92
---
93

            
94
## Shared Types (Models Agent)
95

            
96
These types are defined once in `Models/` and shared across all agents:
97

            
98
```swift
99
// Models/TypeDistributionBin.swift
100
@Model
101
final class TypeDistributionBin {
102
    var bucketStart: Date
103
    var bucketEnd: Date
104
    var count: Int
105
}
106

            
107
// Models/TypeCount.swift
Bogdan Timofte authored 3 weeks ago
108
// TypeCount owns zero or more TypeDistributionBin records.
109
// These bins store sample counts and import anchors, not raw health values.
110

            
111
// Interface updated 2026-05-12 — see AGENTS.md
112
// Models/HealthRecord.swift
113
// HealthRecord stores one anonymized HealthKit record fingerprint plus its start/end dates.
114
// It intentionally does not store raw health values, device identifiers, or source metadata.
115
// UI may compare HealthRecord fingerprints between adjacent snapshots to expose losses
116
// that are masked by newly-added records with the same total count.
117
// High-volume snapshots store these records in TypeCount.recordArchiveData instead of
118
// creating one SwiftData model per record, avoiding main-thread stalls after import.
119

            
120
// Interface updated 2026-05-13 — see AGENTS.md
121
// TypeDistributionBin also stores content hashes and HealthKit query anchors.
122
// Import uses a global anchored query per data type so follow-up snapshots fetch only
123
// HealthKit deltas instead of scanning calendar blocks with fixed per-query latency.
Bogdan Timofte authored a month ago
124

            
Bogdan Timofte authored 3 weeks ago
125
// Interface updated 2026-05-14 — see AGENTS.md
126
// TypeCount.recordArchiveData is stored with SwiftData external storage.
127
// The archive remains a complete per-record forensic snapshot, but large blobs should
128
// not be kept inline with the TypeCount row because high-volume HealthKit stores can
129
// exceed device memory during import or detail inspection.
130
// Initial high-volume imports stream records directly into a compact binary archive
131
// instead of building a full in-memory dictionary/array; plist archives remain readable
132
// for backwards compatibility.
133

            
Bogdan Timofte authored 3 weeks ago
134
// Interface updated 2026-05-17 — see AGENTS.md
135
// Models/TypeCount.detailCacheData stores precomputed detail data for the current
136
// TypeCount compared with the immediately previous snapshot on the same device.
137
// The cache contains aggregate added/disappeared counts, capped preview records for
138
// UI drill-down, and daily change bins for temporal charts. It must be computed when
139
// snapshots are saved and refreshed for neighboring snapshots when snapshot deletion
140
// changes chain links. Existing stores are backfilled incrementally with a strict
141
// per-launch TypeCount cap to avoid decoding many large archives in one run.
142

            
Bogdan Timofte authored 3 weeks ago
143
// Interface updated 2026-05-17 — see AGENTS.md
144
// Models/HealthSnapshot.contentEquivalentSnapshotID marks snapshots whose TypeCount
145
// content is identical to a previous snapshot on the same device. These snapshots are
146
// retained as temporal labels but behave as aliases to the representative content
147
// snapshot for expensive detail cache/diff work.
148

            
149
// Interface updated 2026-05-17 — see AGENTS.md
150
// Models/TypeCount.contentEquivalentTypeCountID marks individual data types whose
151
// content is identical to the previous snapshot's same TypeCount. This allows a
152
// snapshot to contain real changes for some metrics while long-stable metrics behave
153
// as temporal aliases and skip per-type detail cache/diff work.
154

            
Bogdan Timofte authored a month ago
155
// Models/DetectedAnomaly.swift
156
enum AnomalyType: String, Codable {
157
    case historicalInsertion = "historical_insertion"
158
    case silentDeletion      = "silent_deletion"
159
    case duplicate           = "duplicate"
160
    case divergence          = "divergence"
161
}
162

            
163
enum Severity: String, Codable, Comparable {
164
    case info, warning, critical
165
}
166

            
167
enum HealthStatus: String {
168
    case healthy, warning, critical, unknown
169
}
170
```
171

            
172
Any model changes must be announced in this file before other agents consume them.
173

            
174
---
175

            
176
## Handoff Process
177

            
178
When a module is ready to be consumed by another agent:
179

            
180
1. **Define the protocol** in `Services/Protocols/` (services agent)
181
2. **Implement a mock** in `Utilities/Mocks.swift` (Claude Code)
182
3. **Build UI against the mock** (Claude Code)
183
4. **Replace mock with real implementation** (services agent)
184
5. **Integration test** (tests agent)
185

            
186
This allows UI development and service development to proceed in parallel.
187

            
188
---
189

            
190
## Algorithms & Detection Logic
191

            
192
The following modules involve non-trivial logic and should be reviewed carefully:
193

            
194
| Module | File | Description |
195
|--------|------|-------------|
196
| **Anomaly Detector** | `Services/AnomalyDetector.swift` | Statistical detection: insertions, deletions, duplicates, divergence |
197
| **Divergence Engine** | `Services/DivergenceEngine.swift` | Time-series trend analysis, σ comparison |
198
| **Fingerprinter** | `Services/SampleFingerprinter.swift` | Duplicate detection via sample hashing |
199
| **Snapshot Comparator** | `Services/SnapshotComparator.swift` | Diff between two HealthKit snapshots |
200
| **Distribution Comparator** | `Services/SnapshotDiffService.swift` | Daily per-type distribution diff to reveal old-data disappearance masked by new data |
201

            
202
**Guidelines for algorithm modules:**
203
- Document assumptions explicitly (e.g., "assumes continuous monitoring since install")
204
- All thresholds (e.g., `age > 7 days`) must be configurable constants, not magic numbers
205
- Include unit tests for edge cases (empty snapshots, partial data, clock skew)
206
- No UI code; return plain Swift types only
207

            
208
---
209

            
210
## Privacy Directives — All Agents
211

            
212
**Mandatory across all modules:**
213
- No credentials, API keys, tokens, or certificates in any file
214
- No personal data: names, emails, phone numbers, dates of birth
215
- No device identifiers: UDID, serial number, advertising ID, device name
216
- No account identifiers: Apple ID, iCloud account info, CloudKit record IDs
217
- No raw health values in code, tests, previews, logs, or comments
218
- No location data or patterns enabling re-identification
219
- Synthetic data only in tests and previews
220

            
221
---
222

            
223
## Communication Between Agents
224

            
225
When one agent needs to communicate a decision or change to another:
226

            
227
1. **Update this file** (`AGENTS.md`) with the protocol/interface change
228
2. **Update the relevant protocol** in `Services/Protocols/`
229
3. **Add a comment** in the affected file: `// Interface updated YYYY-MM-DD — see AGENTS.md`
230

            
231
---
232

            
233
## Current Status
234

            
235
| Module | Status | Owner |
236
|--------|--------|-------|
237
| SwiftData Models | ✅ Done | Models agent |
238
| HealthKit Integration | ✅ Done | Services agent |
239
| Snapshot Diff Service | ✅ Done | Services agent |
240
| Service Protocols | ⏳ Not started | Services agent |
241
| Anomaly Detection | ⏳ Not started | Services agent |
242
| Sync Monitor | ⏳ Not started | Services agent |
243
| UI – App entry + TabView | ✅ Done | Claude Code |
244
| UI – Dashboard | ✅ Done (functional, minimal) | Claude Code |
245
| UI – Snapshots + Detail | ✅ Done | Claude Code |
246
| UI – Data Types | ✅ Done | Claude Code |
247
| UI – Settings | ✅ Done | Claude Code |
248
| Unit Tests | ⏳ Not started | Tests agent |