@@ -165,14 +165,10 @@ final class TypeDistributionBin {
|
||
| 165 | 165 |
// TypeCount owns zero or more TypeDistributionBin records. |
| 166 | 166 |
// These bins store sample counts and import anchors, not raw health values. |
| 167 | 167 |
|
| 168 |
-// Interface updated 2026-05-12 — see AGENTS.md |
|
| 169 |
-// Models/HealthRecord.swift |
|
| 170 |
-// HealthRecord stores one anonymized HealthKit record fingerprint plus its start/end dates. |
|
| 171 |
-// It intentionally does not store raw health values, device identifiers, or source metadata. |
|
| 172 |
-// UI may compare HealthRecord fingerprints between adjacent snapshots to expose local |
|
| 173 |
-// record-level changes that are masked by newly-added records with the same total count. |
|
| 174 |
-// High-volume snapshots store these records in TypeCount.recordArchiveData instead of |
|
| 175 |
-// creating one SwiftData model per record, avoiding main-thread stalls after import. |
|
| 168 |
+// Interface updated 2026-05-26 — see AGENTS.md |
|
| 169 |
+// Models/HealthRecord.swift no longer defines a SwiftData model. It now keeps |
|
| 170 |
+// the HealthRecordValue DTO plus compact archive helpers used by archive/cache |
|
| 171 |
+// record previews. The authoritative record store is SQLite. |
|
| 176 | 172 |
|
| 177 | 173 |
// Interface updated 2026-05-13 — see AGENTS.md |
| 178 | 174 |
// TypeDistributionBin also stores content hashes and HealthKit query anchors. |
@@ -48,7 +48,7 @@ Detailed checkable milestones live in [`Refactoring-Plan.md`](Refactoring-Plan.m |
||
| 48 | 48 |
|
| 49 | 49 |
- SwiftData currently blocks iOS 15-era device support. |
| 50 | 50 |
- Some screens still imply snapshot-count monitoring rather than Time Machine inspection. |
| 51 |
-- Current UI/cache layers still depend on 9 SwiftData-backed files for launch container, capture review actions, capture bridge writes, and remaining model definitions. |
|
| 51 |
+- Current UI/cache layers still depend on 8 SwiftData-backed files for launch container, capture review actions, capture bridge writes, and remaining model definitions. |
|
| 52 | 52 |
- Snapshots timeline/detail rows, Data Types list/detail rows, and record drill-down are archive/cache-backed for new archive v2 observations when cache rows exist. |
| 53 | 53 |
- Legacy SwiftData-only snapshots are reset for archive v2 test installs rather than migrated. |
| 54 | 54 |
- Capture strategy and some legacy SwiftData transition paths may still decode or cache too much data for low-end devices. |
@@ -10,7 +10,7 @@ local settings stored outside SwiftData where needed. |
||
| 10 | 10 |
## Current Count |
| 11 | 11 |
|
| 12 | 12 |
After moving the Snapshots and Data Types tab roots to archive/cache |
| 13 |
-observations and deleting unused legacy repair/detail/delta services, 9 app |
|
| 13 |
+observations and deleting unused legacy repair/detail/delta services, 8 app |
|
| 14 | 14 |
files still have SwiftData imports because capture, Dashboard review actions, |
| 15 | 15 |
and remaining model definitions still use prototype snapshot handles. |
| 16 | 16 |
|
@@ -29,7 +29,6 @@ Retirement path: |
||
| 29 | 29 |
These files define SwiftData `@Model` classes and are the largest retirement |
| 30 | 30 |
block: |
| 31 | 31 |
|
| 32 |
-- `HealthProbe/Models/HealthRecord.swift` |
|
| 33 | 32 |
- `HealthProbe/Models/HealthSnapshot.swift` |
| 34 | 33 |
- `HealthProbe/Models/TypeCount.swift` |
| 35 | 34 |
- `HealthProbe/Models/TypeDistributionBin.swift` |
@@ -37,8 +36,7 @@ block: |
||
| 37 | 36 |
|
| 38 | 37 |
Retirement path: |
| 39 | 38 |
- replace `HealthSnapshot`, `TypeCount`, `YearlyCount`, |
| 40 |
- `TypeDistributionBin`, and `HealthRecord` active reads/writes with |
|
| 41 |
- archive/cache DTOs; |
|
| 39 |
+ and `TypeDistributionBin` active reads/writes with archive/cache DTOs; |
|
| 42 | 40 |
- retire active reads/writes before removing the launch container. |
| 43 | 41 |
|
| 44 | 42 |
## Capture And Maintenance Services |
@@ -133,6 +131,10 @@ The following SwiftData dependencies were removed from active flows: |
||
| 133 | 131 |
`HealthProbe/Models/TypeDeltaClassification.swift` was deleted. |
| 134 | 132 |
Capture no longer writes prototype `SnapshotDelta`/`TypeDelta` rows after the |
| 135 | 133 |
archive observation is saved. |
| 134 |
+- The unused SwiftData `HealthRecord` model was deleted from |
|
| 135 |
+ `HealthProbe/Models/HealthRecord.swift` and removed from `ModelContainer`. |
|
| 136 |
+ The file now only contains the `HealthRecordValue` DTO and compact archive |
|
| 137 |
+ helpers used by archive/cache record previews. |
|
| 136 | 138 |
- The unused `HealthProbe/Views/DataTypes/TypeEvolutionTimeline.swift` legacy |
| 137 | 139 |
chart was deleted, and the remaining `TypeDiff`/`DiffFilter` DTOs now live in |
| 138 | 140 |
`HealthProbe/Models/TypeDiff.swift` instead of the removed |
@@ -27,7 +27,7 @@ struct HealthProbeApp: App {
|
||
| 27 | 27 |
_ = try PrototypeStoreResetPolicy.applyIfNeeded() |
| 28 | 28 |
|
| 29 | 29 |
let fullSchema = Schema([ |
| 30 |
- HealthSnapshot.self, TypeCount.self, YearlyCount.self, HealthRecord.self, TypeDistributionBin.self, |
|
| 30 |
+ HealthSnapshot.self, TypeCount.self, YearlyCount.self, TypeDistributionBin.self, |
|
| 31 | 31 |
]) |
| 32 | 32 |
|
| 33 | 33 |
let appSupportURL = URL.applicationSupportDirectory |
@@ -35,7 +35,7 @@ struct HealthProbeApp: App {
|
||
| 35 | 35 |
let uiCacheStoreURL = appSupportURL.appending(path: "HealthProbeRecords.store") |
| 36 | 36 |
|
| 37 | 37 |
let uiCacheModels = Schema([ |
| 38 |
- HealthSnapshot.self, TypeCount.self, YearlyCount.self, HealthRecord.self, TypeDistributionBin.self, |
|
| 38 |
+ HealthSnapshot.self, TypeCount.self, YearlyCount.self, TypeDistributionBin.self, |
|
| 39 | 39 |
]) |
| 40 | 40 |
|
| 41 | 41 |
let uiCacheConfig = ModelConfiguration( |
@@ -1,5 +1,4 @@ |
||
| 1 | 1 |
import Foundation |
| 2 |
-import SwiftData |
|
| 3 | 2 |
|
| 4 | 3 |
struct HealthRecordValue: Codable, Hashable, Identifiable, Sendable {
|
| 5 | 4 |
var id: String { recordFingerprint }
|
@@ -336,31 +335,3 @@ enum HealthRecordArchive {
|
||
| 336 | 335 |
} |
| 337 | 336 |
} |
| 338 | 337 |
} |
| 339 |
-// Interface updated 2026-05-12 — see AGENTS.md |
|
| 340 |
-@Model final class HealthRecord {
|
|
| 341 |
- var id: UUID = UUID() |
|
| 342 |
- var typeIdentifier: String = "" |
|
| 343 |
- var sampleUUIDHash: String = "" |
|
| 344 |
- var recordFingerprint: String = "" |
|
| 345 |
- var startDate: Date = Date.distantPast |
|
| 346 |
- var endDate: Date = Date.distantPast |
|
| 347 |
- var displayValue: String? |
|
| 348 |
- var typeCount: TypeCount? |
|
| 349 |
- |
|
| 350 |
- init( |
|
| 351 |
- typeIdentifier: String, |
|
| 352 |
- sampleUUIDHash: String, |
|
| 353 |
- recordFingerprint: String, |
|
| 354 |
- startDate: Date, |
|
| 355 |
- endDate: Date, |
|
| 356 |
- displayValue: String? = nil |
|
| 357 |
- ) {
|
|
| 358 |
- self.id = UUID() |
|
| 359 |
- self.typeIdentifier = typeIdentifier |
|
| 360 |
- self.sampleUUIDHash = sampleUUIDHash |
|
| 361 |
- self.recordFingerprint = recordFingerprint |
|
| 362 |
- self.startDate = startDate |
|
| 363 |
- self.endDate = endDate |
|
| 364 |
- self.displayValue = displayValue |
|
| 365 |
- } |
|
| 366 |
-} |
|
@@ -18,8 +18,6 @@ import SwiftData |
||
| 18 | 18 |
var snapshot: HealthSnapshot? |
| 19 | 19 |
@Relationship(deleteRule: .cascade, inverse: \YearlyCount.typeCount) |
| 20 | 20 |
var yearlyCounts: [YearlyCount]? = [] |
| 21 |
- @Relationship(deleteRule: .cascade, inverse: \HealthRecord.typeCount) |
|
| 22 |
- var records: [HealthRecord]? = [] |
|
| 23 | 21 |
@Relationship(deleteRule: .cascade, inverse: \TypeDistributionBin.typeCount) |
| 24 | 22 |
var distributionBins: [TypeDistributionBin]? = [] |
| 25 | 23 |
|
@@ -49,7 +47,6 @@ extension TypeCount {
|
||
| 49 | 47 |
|
| 50 | 48 |
func setRecordValues(_ values: [HealthRecordValue]) {
|
| 51 | 49 |
recordArchiveData = HealthRecordArchive.encode(values) |
| 52 |
- records?.removeAll() |
|
| 53 | 50 |
} |
| 54 | 51 |
|
| 55 | 52 |
@MainActor var detailCache: TypeCountDetailCache? {
|
@@ -2029,7 +2029,6 @@ private struct TypeCountFetchResult: Sendable {
|
||
| 2029 | 2029 |
|
| 2030 | 2030 |
if let recordArchiveData {
|
| 2031 | 2031 |
typeCount.recordArchiveData = recordArchiveData |
| 2032 |
- typeCount.records?.removeAll() |
|
| 2033 | 2032 |
} else {
|
| 2034 | 2033 |
typeCount.setRecordValues(records.map { recordData in
|
| 2035 | 2034 |
HealthRecordValue( |