HealthProbe is built by multiple AI models, each owning a distinct domain.
This document defines boundaries, interfaces, and handoff contracts.
| 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 |
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.
All service boundaries are defined as Swift protocols.
Claude Code (UI) consumes protocols — never concrete implementations.
/// Owned by: Services agent
/// Consumed by: UI (DashboardViewModel)
protocol HealthMonitorProtocol {
var currentStatus: HealthStatus { get }
var lastChecked: Date? { get }
func runCheck() async throws
}
/// Owned by: Services agent
/// Consumed by: UI (AnomalyListViewModel)
protocol AnomalyStoreProtocol {
var anomalies: [DetectedAnomaly] { get }
func markResolved(_ anomaly: DetectedAnomaly) async throws
}
/// Owned by: Services agent
/// Consumed by: UI (AuditTrailView)
protocol AuditTrailProtocol {
var entries: [AuditTrailEntry] { get }
func export() async throws -> Data // JSON
}
/// Owned by: Services agent
/// Consumed by: UI (SyncViewModel)
protocol SyncMonitorProtocol {
var iCloudEnabled: Bool { get }
var lastSyncDate: Date? { get }
var stateChanges: [SyncStateChange] { get }
}
These types are defined once in Models/ and shared across all agents:
// 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.
// Interface updated 2026-05-17 — see AGENTS.md
// Models/TypeCount.detailCacheData stores precomputed detail data for the current
// TypeCount compared with the immediately previous snapshot on the same device.
// The cache contains aggregate added/disappeared counts, capped preview records for
// UI drill-down, and daily change bins for temporal charts. It must be computed when
// snapshots are saved and refreshed for neighboring snapshots when snapshot deletion
// changes chain links. Existing stores are backfilled incrementally with a strict
// per-launch TypeCount cap to avoid decoding many large archives in one run.
// Interface updated 2026-05-17 — see AGENTS.md
// Models/HealthSnapshot.contentEquivalentSnapshotID marks snapshots whose TypeCount
// content is identical to a previous snapshot on the same device. These snapshots are
// retained as temporal labels but behave as aliases to the representative content
// snapshot for expensive detail cache/diff work.
// Interface updated 2026-05-17 — see AGENTS.md
// Models/TypeCount.contentEquivalentTypeCountID marks individual data types whose
// content is identical to the previous snapshot's same TypeCount. This allows a
// snapshot to contain real changes for some metrics while long-stable metrics behave
// as temporal aliases and skip per-type detail cache/diff work.
// Interface updated 2026-05-17 — see AGENTS.md
// Models/HealthSnapshot stores cached overview scalars for UI consumption:
// tracked type count, aggregate record count, and overall oldest/newest record dates.
// These values must be computed during snapshot save while TypeCount data is already
// in memory, so snapshot list/detail screens never recompute them by traversing
// snapshot.typeCounts on the UI thread.
// Interface updated 2026-05-17 — see AGENTS.md
// Models/SnapshotDelta stores cached list/detail summary scalars derived from TypeDelta.
// Overview screens consume these scalars and type-delta summaries directly instead of
// recalculating per-snapshot changes from HealthSnapshot.typeCounts.
// 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.
When a module is ready to be consumed by another agent:
Services/Protocols/ (services agent)Utilities/Mocks.swift (Claude Code)This allows UI development and service development to proceed in parallel.
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
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
When one agent needs to communicate a decision or change to another:
AGENTS.md) with the protocol/interface changeServices/Protocols/// Interface updated YYYY-MM-DD — see AGENTS.md| 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 |