Skip to content

Commit 2a37cdf

Browse files
committed
Reject late hidden insulin history and prepare 0.1.11
1 parent 6a0a789 commit 2a37cdf

9 files changed

Lines changed: 105 additions & 3 deletions

File tree

‎AI_NOTES.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1+
# Insulin History Knowledge Boundary And 0.1.11 - 2026-10-23
2+
3+
- Main6a0a7894 CI39881365894 passed all three jobs. Native basal/profile source
4+
and main integration are now verified; complete physical delivery is separate.
5+
- Three failing-first regressions reproduced an insulin inventory returning
6+
earlier absence after a later edit moved the dose outside the query. Include
7+
shortened/deleted rows, unrelated/empty snapshots and native Room cache/reopen.
8+
Initial sandbox run could not access the existing Gradle cache; the authorized
9+
rerun executed37tests and reproduced all three intended failures.
10+
- Check the retained collection revision before insulin-window filtering, matching
11+
the profile-history knowledge boundary. No synthetic archive or old-dose fallback.
12+
- All131focused checks passed with one existing private-input skip and real SDK
13+
TLS2.279s. Frozen full test/lint/compile/assemble passed in8m12s:6793passed,
14+
six existing skips, zero failures/errors, real SDK TLS2.254s and zero lint errors
15+
with382existing warnings/eight hints. All1431source hashes stayed unchanged.
16+
- Prepare0.1.11/code12 for existing internet updates:39,730,208bytes and the same
17+
independently checked signing identity. APK retention passed. Exact-head CI/main
18+
and public-download gates remain pending until independently verified.
19+
- No AAPS source/device, AI service, schema, dose, target, alarm or live recommended
20+
eating-time admission is changed. Missing upstream/pump/clock receipts and
21+
prospective forecast/controller validation cannot be replaced by software tests.
22+
123
# Native Reported Basal Segments - 2026-10-23
224

325
- Continue from PR24/main4f1d173d. All six source checks passed and merged/tested

‎android-app/app/build.gradle.kts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ android {
1717
applicationId = "io.aaps.predictivecopilot"
1818
minSdk = 31
1919
targetSdk = 36
20-
versionCode = 11
21-
versionName = "0.1.10"
20+
versionCode = 12
21+
versionName = "0.1.11"
2222

2323
testInstrumentationRunner = "io.aaps.copilot.CopilotTestRunner"
2424
vectorDrawables.useSupportLibrary = true

‎android-app/app/src/main/kotlin/io/aaps/copilot/service/AapsV3InsulinInventory.kt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ internal class AapsV3InsulinInventoryTimeline(snapshot: LocalV3RetainedSnapshot)
9191
if (fromMs !in 1..atMs || atMs > knownAtMs || knownAtMs > LocalNightscoutV3Store.MAX_TIME)
9292
return unavailable(AapsV3ObservedInsulinStatus.INVALID)
9393
failure?.let { return unavailable(it) }
94+
// Latest retained versions cannot recover a record moved outside this earlier query.
95+
if (revision > knownAtMs) return unavailable(AapsV3ObservedInsulinStatus.LATE_EVIDENCE)
9496
val relevant = entries.filter { it.atMs <= atMs &&
9597
(it.observation == null || it.atMs >= fromMs || it.observation.endAtMs > fromMs) }
9698
if (relevant.any { it.observation == null }) return unavailable(AapsV3ObservedInsulinStatus.INVALID)

‎android-app/app/src/test/kotlin/io/aaps/copilot/service/AapsV3EffectiveProfileSourceTest.kt‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,29 @@ class AapsV3EffectiveProfileSourceTest {
105105
assertNull(read.profile.observation)
106106
}
107107

108+
@Test fun movedInsulinCorrectionCannotHideFromAsKnownReadAcrossReopen() = runBlocking {
109+
store().create(input("profile", at - 60_000))
110+
fun dose(time: Long) = LocalV3DocumentInput(LocalV3Collection.TREATMENTS, "dose", "local-v3-owner", time,
111+
buildJsonObject { put("eventType", "Correction Bolus"); put("date", time); put("insulin", 2.2) }.toString())
112+
val original = store().create(dose(at - 1)).document
113+
val source = AapsV3EffectiveProfileSource(store())
114+
val previousRevision = original.modifiedRevision
115+
assertEquals(1, source.readEvidence(at - 30_000, at, previousRevision).insulin.records.size)
116+
val changed = store().update(dose(at + 1), original.modifiedRevision).document
117+
suspend fun verify(reader: AapsV3EffectiveProfileSource) {
118+
val historical = reader.readEvidence(at - 30_000, at, previousRevision)
119+
assertEquals(AapsV3ObservedInsulinStatus.LATE_EVIDENCE, historical.insulin.status)
120+
assertTrue(historical.insulin.records.isEmpty())
121+
assertFalse(historical.insulin.upstreamCompletenessVerified)
122+
assertEquals(AapsV3ObservedInsulinStatus.NOT_OBSERVED,
123+
reader.readEvidence(at - 30_000, at, changed.modifiedRevision).insulin.status)
124+
}
125+
verify(source)
126+
db.close(); db = open()
127+
verify(AapsV3EffectiveProfileSource(store()))
128+
assertTrue(db.therapyDao().since(0).isEmpty())
129+
}
130+
108131
@Test fun cachedScheduleCannotBeModifiedByAReader() = runBlocking {
109132
store().create(input("profile"))
110133
val profile = observed(AapsV3EffectiveProfileSource(store()).read(at)).profile

‎android-app/app/src/test/kotlin/io/aaps/copilot/service/AapsV3InsulinInventoryTest.kt‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,38 @@ class AapsV3InsulinInventoryTest {
130130
assertTrue(result.records.isEmpty())
131131
}
132132

133+
@Test fun lateMovedShortenedOrDeletedDeliveryCannotBecomeEarlierAbsence() {
134+
val changed = listOf(
135+
row(time = at + 1, revision = at + 10),
136+
row(time = at - 7_200_000, revision = at + 10),
137+
row(time = at - 7_200_000, revision = at + 10, fields = buildJsonObject {
138+
put("eventType", "Temp Basal"); put("duration", 1); put("absolute", 0.8)
139+
}),
140+
row(time = at + 1, revision = at + 10, deleted = true)
141+
)
142+
for (source in changed) {
143+
val result = read(source)
144+
assertEquals(AapsV3ObservedInsulinStatus.LATE_EVIDENCE, result.status)
145+
assertTrue(result.records.isEmpty())
146+
assertFalse(result.upstreamCompletenessVerified)
147+
}
148+
}
149+
150+
@Test fun newerEmptyOrUnrelatedSnapshotCannotReconstructEarlierInventory() {
151+
val unrelated = row("note", time = at + 1, revision = at + 10,
152+
fields = buildJsonObject { put("eventType", "Note") })
153+
for (rows in listOf(emptyList(), listOf(unrelated), listOf(row(), unrelated))) {
154+
val timeline = AapsV3InsulinInventoryTimeline(LocalV3RetainedSnapshot.Complete(at + 10, rows))
155+
val historical = timeline.read(at - 3_600_000, at, at)
156+
assertEquals(AapsV3ObservedInsulinStatus.LATE_EVIDENCE, historical.status)
157+
assertTrue(historical.records.isEmpty())
158+
val current = timeline.read(at - 3_600_000, at, at + 10)
159+
assertEquals(if (rows.size == 2) AapsV3ObservedInsulinStatus.OBSERVED
160+
else AapsV3ObservedInsulinStatus.NOT_OBSERVED, current.status)
161+
assertFalse(current.upstreamCompletenessVerified)
162+
}
163+
}
164+
133165
@Test fun emptyAndOverLimitAreExplicitAndNeverProveCoverage() {
134166
val empty = read()
135167
assertEquals(AapsV3ObservedInsulinStatus.NOT_OBSERVED, empty.status)

‎docs/AAPS4_INSULIN_OBSERVATIONS.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ insulin indexes for the same retained revision and then drops raw JSON.
2121
Unknown bolus ICfg stays unknown. Contradictory bolus duration, malformed amounts,
2222
invalid source metadata or duplicate pump keys reject without partial success.
2323
Late retained revisions cannot be used as data available to an earlier prediction.
24+
This check applies to the entire collection revision before filtering the window,
25+
including empty or unrelated snapshots. A later edit can move, shorten or delete
26+
the only relevant dose, so checking the returned rows alone cannot establish
27+
earlier absence. Latest retained versions are not a historical version archive.
2428
Queries include intervals that start before the requested window and overlap it.
2529
Malformed records cannot be declared expired using an unknown duration.
2630

‎docs/ARCHITECTURE.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ and counts without an additional worker. Native schedule lookup uses the device'
3333
system clock, so serialized profile timezone cannot attest historical clock
3434
changes. No observed interval can create MealBasalHistory or unlock meal advice
3535
without separate coverage/clock/delivery admission. See AAPS4_REPORTED_BASAL.md.
36+
The insulin index, like profile history, rejects a newer retained collection
37+
revision before window filtering. Revisions of excluded rows must not erase
38+
exposure from an earlier as-known query; this is not a versioned history archive.
3639

3740
## RC1 Target Transaction Boundary
3841

‎docs/INVARIANTS.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
cannot attest historical device-clock changes. Do not reapply EPS modifiers.
4343
- Immutable reported spans/quantities remain observational, not physical delivery,
4444
complete source/pump coverage, MealBasalHistory or live timer/therapy permission.
45+
- As-known insulin reads reject a collection revision newer than knowledge time
46+
before filtering. A moved/shortened/deleted dose, unrelated change or empty
47+
latest snapshot cannot be used to reconstruct an earlier absence of delivery.
4548

4649
## RC1 Target Admission
4750

‎docs/PLAN.md‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# PLAN
22

3+
## Insulin History Knowledge Boundary And 0.1.11 (2026-10-23)
4+
5+
- [x] Confirm main6a0a7894 CI39881365894 passed all three jobs.
6+
- [x] Reproduce three failures for hidden late insulin edits and native Room reopen.
7+
- [x] Reject the newer collection revision before filtering insulin windows.
8+
- [x] Pass131focused checks/one existing skip and6793full checks/six existing
9+
skips;actual SDK TLS, zero lint errors, frozen source and APK retention pass.
10+
- [ ] Verify exact source CI and integrate the identical tested tree into main.
11+
- [ ] Publish and independently verify0.1.11/code12 over the existing update route.
12+
- Latest retained rows cannot prove earlier absence or full upstream/pump/clock
13+
coverage. Live meal recommendation, targets, doses and alarms remain unchanged.
14+
315
## Native Reported Basal Segments (2026-10-23)
416

517
- [x] Reproduce contradictory-rate/type and duplicate-identity/privacy defects.
@@ -8,7 +20,8 @@
820
- [x] Complete pure, Room/reopen/owner and actual pristine SDK TLS checks.
921
- [x] Frozen full quality:6790passed/six existing skips, actual SDK TLS, zero lint
1022
errors, unchanged1431source hashes and all7176app classes retained.
11-
- [ ] Verify exact-head CI and integrate the matching tested tree into main.
23+
- [x] Pass six exact-source checks, integrate6a0a7894 with matching tree and verify
24+
all three main CI39881365894 jobs.
1225
- Reported spans do not establish source/pump/clock completeness or authorize live
1326
meal advice. See AAPS4_REPORTED_BASAL.md for units and remaining admission.
1427

0 commit comments

Comments
 (0)