From 25102269d9468dc3f5328f6c41d61cafab389775 Mon Sep 17 00:00:00 2001 From: null Date: Wed, 19 Aug 2026 22:17:42 -0500 Subject: [PATCH] docs: log Batch 06 closing, four new guards, and an emulator that was not mine Step 6 of WORK_CYCLE. Next action is filing Batch 07's issues: Monetization is an open milestone with zero issues, so the largest remaining body of code is described nowhere and is missing from the denominator the project screen reports. Co-Authored-By: Claude Opus 5 (1M context) --- docs/history/DEVELOPMENT_LOG.md | 89 +++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/docs/history/DEVELOPMENT_LOG.md b/docs/history/DEVELOPMENT_LOG.md index b6e9505..a8e8397 100644 --- a/docs/history/DEVELOPMENT_LOG.md +++ b/docs/history/DEVELOPMENT_LOG.md @@ -32,6 +32,95 @@ written and stay true. It is exempt from review for the same reason a receipt is ## Entries +### 2026-08-19 (later) — Batch 06 closed, and four guards that can now fail + +Export, the privacy promise, the themed-drawable guard and the notification icon +all landed, and **Batch 06 is closed** with seven issues in it. The tracker has +three issues left and none of them is code: two need artwork, and the third +(#31, the incognito launcher) says in its own body that the alias must land with +§32's toggle rather than ahead of it. + +**#35, export.** One pretty-printed JSON file, plaintext, written straight into +a document the user picked through the Storage Access Framework. No copy in +`cacheDir`, no `FileProvider`, no path handed to another app — and a test walks +`cacheDir` afterwards and requires it empty, which fails the moment anybody +reintroduces write-then-share. + +The format is pinned **byte-for-byte** against a committed golden file, because +the issue is right that it outlives the batch: whatever ships first is what +people's archives are in. It also renders identically in UTC, +14 and −12, +because `Converters.kt` stores a `LocalDate` as its epoch day precisely so it +"cannot carry a timezone by accident" and a zone-aware formatter here would be +off by one day for everybody east or west of whoever wrote it. + +**Plaintext was the decision, and it reverses an earlier note in this file.** +The entry above records the next action as "export with the file encrypted". +That is wrong, and `SECURITY.md` now says why: the export is the copy that makes +a lost Keystore key survivable rather than final — the exact condition written +down for ever revisiting database encryption. A passphrase would reproduce the +failure that decision avoided, and nothing, including this app, could open the +result. + +"Only the user's own data" is enforced structurally rather than by review: +`:core:export` is pure JVM and depends on `:domain:cycle` alone, so `Prediction`, +`FertilityEstimate` and `android.os.Build` are not on its classpath. Adding a +forecast does not compile. + +**Four guards exist now that did not, and each was watched failing.** + + - `checkThemedDrawables` (#42) — every drawable has a night twin, both + directions. `prove-guard.sh` cannot drive it, because it replaces a string + in a file and this guard's failure mode is a file that is *not there*, in a + set that is all `.webp`. GUARDS.md §9 records that class. + - `checkNoSharedStorageWrites` — §45's shared-storage ban was enforced by + nobody having typed it. `checkPermissions` structurally cannot see it: it + matches ``, and a `` declaring `FileProvider` + merges green. + - `checkNoHealthLogging` completeness — a module missing from + `modulesSeeingHealthData` was silently exempt with a green build. Both + `:core:security` and `:core:export` would have gone through that hole. + - `checkPermissions` narrowed — it was reading `merged_manifest/debugUnitTest` + and failed on `REORDER_TASKS`, a test-runner permission that does not ship. + The tempting fix was to allowlist it, which would have permitted it in the + real manifest too and quietly undone the guard. + +**Three defects found that nobody was looking for.** + + 1. `NotificationPrivacyTest` could never run on `PeriodMinSdk26`. + `GrantPermissionRule` asked for `POST_NOTIFICATIONS` unconditionally, and + that permission arrived in API 33 — so every test in the class errored + before its first assertion, on the one emulator where it mattered. The class + guards what a locked screen shows. + 2. No Robolectric test in `:app` could read a string resource. + `unitTests.isIncludeAndroidResources` was never set there, so the module + owning nearly all the user-facing copy was the one whose copy could not be + tested. + 3. `prove-guard.sh`, a third time: a `PROVE_GUARD_FAIL_PATTERN` matching + **nothing** gives the same "caught it, and only it" verdict as one matching + once. The empty `--- what failed ---` block is the tell, and GUARDS.md §8 + now says to read it. + +**A mistake worth recording.** Looking for a device to verify the export on, I +installed the debug APK onto whatever `adb` reported and drove it — and it was +the **FruitFall** emulator, running another project's app. My package is +uninstalled and their app was left running, but the lesson is that a device on +`adb devices` is not evidence of a device that is mine. The export's on-device +checks are three new rows in `SECURITY_CHECKLIST.md` rather than a claim. + +**What this proved:** 261 JVM tests, none skipped. Five guards green, four of +them proved able to fail today. + +**Next action:** file Batch 07's issues. Monetization is an open milestone with +**zero issues**, closed or open, so the largest remaining body of code in this +project is described nowhere — which also means the 84% figure on the project +screen is measured against a denominator that excludes it. Ads and billing need +scoping before they need writing, and §34's advertising boundary is the part +that most needs stating before anybody starts. + +**Blockers:** none for code. #31 waits on §32's toggle by its own instruction, +#32 and #44 need artwork, and the public privacy page — which #37's Privacy +Policy row waits on — is site-side work no agent here can do. + ### 2026-08-19 — The app lock, and three defects only testing found #34 is closed. The app asks for a PIN before it opens, and a forgotten PIN