@@ -25,7 +25,7 @@ There are no real deployments, only test installations. Existing prototype datab |
||
| 25 | 25 |
|------|----------------|--------------------| |
| 26 | 26 |
| Product docs | Updated | Keep `HealthProbe/Doc/README.md` as canonical index | |
| 27 | 27 |
| HealthKit capture | Capture now opens one archive observation per user-visible snapshot, attaches HealthKit pages, deleted-object evidence, and type verification to that observation id before finishing it, no longer aborts initial full-history imports after a fixed 30-minute wall-clock cap while page-level HealthKit timeouts remain in place, defers grouped observation summary/daily aggregate rebuilds until per-type verification instead of rebuilding after every imported page, and persists large HealthKit pages in smaller archive chunks while using type-specific import strategies: conservative paging for the heaviest metrics, more aggressive pages/chunks for ordinary metrics, adaptive write chunk sizing, batched deleted-object persistence, explicit task yields, and lower-allocation streaming loops to avoid long monolithic SQLite stalls | Continue moving UI/cache reads to archive-backed observation ids and revisit full checkpoint/resume and background collection separately | |
| 28 |
-| SQLite archive | Archive v2 schema, snapshot-level observation grouping, differential write path, v2 verification/delete bookkeeping, daily aggregate rebuilds, integrity report, v2 record reads, SQL diff/count/aggregate/provenance/consolidation-evidence APIs, large synthetic diff pagination coverage, formal timing/memory metrics, and XCTest coverage are in place; the legacy `archive_samples` mirror has been removed, the hot write path now reuses prepared SQLite statements within grouped page writes instead of reparsing the same SQL for every sample, caches repeated sample-type/source/source-revision/device/metadata id lookups within grouped writes, skips redundant visibility close/existence checks when grouped imports create a brand-new sample or payload version, reuses verification aggregates instead of rescanning them twice, drives per-type finalize queries from sample-type-filtered sample ids, processes sample rows in a lower-allocation streaming loop, batches same-page deleted-object evidence in one transaction, adds composite indexes for visibility-range and sample-uuid hot lookups, and opens SQLite connections with import-friendly busy timeout / synchronous / temp-store pragmas | Continue moving capture/Dashboard actions to archive/cache DTOs | |
|
| 28 |
+| SQLite archive | Archive v2 schema, snapshot-level observation grouping, differential write path, v2 verification/delete bookkeeping, daily aggregate rebuilds, integrity report, v2 record reads, SQL diff/count/aggregate/provenance/consolidation-evidence APIs, large synthetic diff pagination coverage, formal timing/memory metrics, and XCTest coverage are in place; the legacy `archive_samples` mirror has been removed, the hot write path now reuses prepared SQLite statements within grouped page writes instead of reparsing the same SQL for every sample, caches repeated sample-type/source/source-revision/device/metadata id lookups within grouped writes, skips redundant visibility close/existence checks when grouped imports create a brand-new sample or payload version, skips follow-up id lookup queries when SQLite confirms new sample/sample-version inserts, reuses verification aggregates instead of rescanning them twice, drives per-type finalize queries from sample-type-filtered sample ids, processes sample rows in a lower-allocation streaming loop, batches same-page deleted-object evidence in one transaction, adds composite indexes for visibility-range and sample-uuid hot lookups, and opens SQLite connections with import-friendly busy timeout / synchronous / temp-store pragmas | Continue moving capture/Dashboard actions to archive/cache DTOs | |
|
| 29 | 29 |
| Core Data cache | Initial programmatic Core Data model, full-cache rebuild service, read DTOs for observation/type/diff/health rows, and Dashboard archive-cache status wiring are in place | Move remaining export/report paths to cache DTOs and add targeted partial invalidation | |
| 30 | 30 |
| SwiftData cache | Exists; test builds now reset legacy prototype UI/archive/cache stores once for archive v2 so old SwiftData-only snapshots are not treated as backed-up observations. Metric timeout calibration, local device profile settings, operation logging, ContentView preview, Settings data maintenance, legacy detail/PDF views, unused legacy repair/observer services, Dashboard view/view-model access, and legacy anomaly/count-drop review have moved outside SwiftData or been removed. Remaining SwiftData imports are inventoried in [`SwiftData-Retirement-Inventory.md`](SwiftData-Retirement-Inventory.md) | Treat as disposable prototype data; stop returning/storing `HealthSnapshot` bridge handles before removing `ModelContainer` | |
| 31 | 31 |
| UI | Prototype exists; Dashboard status reads archive/cache observation rows and shows cache health, and Dashboard view/view-model code no longer imports SwiftData or reads `ModelContext`; capture/review actions now route through DTOs and snapshot ids, with the remaining legacy bridge isolated in `HealthKitService`. Snapshots and Data Types tab roots no longer import SwiftData, load Core Data cached observation rows, and open archive/cache-backed detail rows; `SnapshotArchiveDetailView` and `DataTypeArchiveDetailView` read Core Data type/diff summaries and page record drill-down through SQLite; unused legacy SwiftData snapshot/type detail and PDF views have been deleted; record-change evolution and temporal distribution screens now receive DTO rows/cache input instead of querying SwiftData directly; export preview reads the archive export API before showing/exporting JSON; simplified detail mode replaces heavy charts with summary rows on small/accessibility layouts or when enabled in Settings; visible change labels now use neutral new/missing/change-review language; Settings can now schedule a full test-database reset for the next app launch | Stop writing prototype `HealthSnapshot` bridge rows during capture/review | |
@@ -2659,13 +2659,18 @@ actor SQLiteHealthArchiveStore: HealthArchiveStore {
|
||
| 2659 | 2659 |
} |
| 2660 | 2660 |
} |
| 2661 | 2661 |
let inserted = sqlite3_changes(db) > 0 |
| 2662 |
- let id = try requiredInt64( |
|
| 2663 |
- "SELECT id FROM samples WHERE sample_type_id = ? AND strict_fingerprint = ? LIMIT 1", |
|
| 2664 |
- db: db, |
|
| 2665 |
- statementCache: statementCache |
|
| 2666 |
- ) { statement in
|
|
| 2667 |
- bindInt64(sampleTypeID, to: 1, in: statement) |
|
| 2668 |
- bindText(row.strictFingerprint, to: 2, in: statement) |
|
| 2662 |
+ let id: Int64 |
|
| 2663 |
+ if inserted {
|
|
| 2664 |
+ id = sqlite3_last_insert_rowid(db) |
|
| 2665 |
+ } else {
|
|
| 2666 |
+ id = try requiredInt64( |
|
| 2667 |
+ "SELECT id FROM samples WHERE sample_type_id = ? AND strict_fingerprint = ? LIMIT 1", |
|
| 2668 |
+ db: db, |
|
| 2669 |
+ statementCache: statementCache |
|
| 2670 |
+ ) { statement in
|
|
| 2671 |
+ bindInt64(sampleTypeID, to: 1, in: statement) |
|
| 2672 |
+ bindText(row.strictFingerprint, to: 2, in: statement) |
|
| 2673 |
+ } |
|
| 2669 | 2674 |
} |
| 2670 | 2675 |
return (id, inserted) |
| 2671 | 2676 |
} |
@@ -2721,13 +2726,18 @@ actor SQLiteHealthArchiveStore: HealthArchiveStore {
|
||
| 2721 | 2726 |
} |
| 2722 | 2727 |
} |
| 2723 | 2728 |
let inserted = sqlite3_changes(db) > 0 |
| 2724 |
- let id = try requiredInt64( |
|
| 2725 |
- "SELECT id FROM sample_versions WHERE sample_id = ? AND payload_hash = ? LIMIT 1", |
|
| 2726 |
- db: db, |
|
| 2727 |
- statementCache: statementCache |
|
| 2728 |
- ) { statement in
|
|
| 2729 |
- bindInt64(sampleID, to: 1, in: statement) |
|
| 2730 |
- bindText(row.payloadHash, to: 2, in: statement) |
|
| 2729 |
+ let id: Int64 |
|
| 2730 |
+ if inserted {
|
|
| 2731 |
+ id = sqlite3_last_insert_rowid(db) |
|
| 2732 |
+ } else {
|
|
| 2733 |
+ id = try requiredInt64( |
|
| 2734 |
+ "SELECT id FROM sample_versions WHERE sample_id = ? AND payload_hash = ? LIMIT 1", |
|
| 2735 |
+ db: db, |
|
| 2736 |
+ statementCache: statementCache |
|
| 2737 |
+ ) { statement in
|
|
| 2738 |
+ bindInt64(sampleID, to: 1, in: statement) |
|
| 2739 |
+ bindText(row.payloadHash, to: 2, in: statement) |
|
| 2740 |
+ } |
|
| 2731 | 2741 |
} |
| 2732 | 2742 |
return (id, inserted) |
| 2733 | 2743 |
} |