# HealthProbe – Multi-Model Development Guide

## Overview

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

---

## Model Allocation

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

---

## Directory Ownership

```
HealthProbe/
├── Views/           ← Claude Code (UI)
├── ViewModels/      ← Claude Code (UI)
├── Utilities/       ← Claude Code (shared helpers, mocks)
├── Models/          ← Models agent (SwiftData schemas)
├── Services/        ← Services agent (HealthKit, anomaly, sync)
└── Tests/           ← Tests agent
```

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

---

## Interface Contracts

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

### HealthMonitorProtocol

```swift
/// Owned by: Services agent
/// Consumed by: UI (DashboardViewModel)
protocol HealthMonitorProtocol {
    var currentStatus: HealthStatus { get }
    var lastChecked: Date? { get }
    func runCheck() async throws
}
```

### AnomalyStoreProtocol

```swift
/// Owned by: Services agent
/// Consumed by: UI (AnomalyListViewModel)
protocol AnomalyStoreProtocol {
    var anomalies: [DetectedAnomaly] { get }
    func markResolved(_ anomaly: DetectedAnomaly) async throws
}
```

### AuditTrailProtocol

```swift
/// Owned by: Services agent
/// Consumed by: UI (AuditTrailView)
protocol AuditTrailProtocol {
    var entries: [AuditTrailEntry] { get }
    func export() async throws -> Data  // JSON
}
```

### SyncMonitorProtocol

```swift
/// Owned by: Services agent
/// Consumed by: UI (SyncViewModel)
protocol SyncMonitorProtocol {
    var iCloudEnabled: Bool { get }
    var lastSyncDate: Date? { get }
    var stateChanges: [SyncStateChange] { get }
}
```

---

## Shared Types (Models Agent)

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

```swift
// Models/TypeDistributionBin.swift
@Model
final class TypeDistributionBin {
    var bucketStart: Date
    var bucketEnd: Date
    var count: Int
}

// Models/TypeCount.swift
// TypeCount owns zero or more TypeDistributionBin records.
// These bins store sample counts and import anchors, not raw health values.

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

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

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

// Models/DetectedAnomaly.swift
enum AnomalyType: String, Codable {
    case historicalInsertion = "historical_insertion"
    case silentDeletion      = "silent_deletion"
    case duplicate           = "duplicate"
    case divergence          = "divergence"
}

enum Severity: String, Codable, Comparable {
    case info, warning, critical
}

enum HealthStatus: String {
    case healthy, warning, critical, unknown
}
```

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

---

## Handoff Process

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

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

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

---

## Algorithms & Detection Logic

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

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

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

---

## Privacy Directives — All Agents

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

---

## Communication Between Agents

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

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

---

## Current Status

| Module | Status | Owner |
|--------|--------|-------|
| SwiftData Models | ✅ Done | Models agent |
| HealthKit Integration | ✅ Done | Services agent |
| Snapshot Diff Service | ✅ Done | Services agent |
| Service Protocols | ⏳ Not started | Services agent |
| Anomaly Detection | ⏳ Not started | Services agent |
| Sync Monitor | ⏳ Not started | Services agent |
| UI – App entry + TabView | ✅ Done | Claude Code |
| UI – Dashboard | ✅ Done (functional, minimal) | Claude Code |
| UI – Snapshots + Detail | ✅ Done | Claude Code |
| UI – Data Types | ✅ Done | Claude Code |
| UI – Settings | ✅ Done | Claude Code |
| Unit Tests | ⏳ Not started | Tests agent |
