Six recurring, non-obvious learnings: Gradle config-cache corruption fix,
Room NOT NULL-column migrations needing @ColumnInfo(defaultValue), the
scrypt wf=15 rationale (do not bump to 18), Compose dialogs not being
adb/uiautomator-tappable (verify via instrumented tests), backticks
breaking git commit -m, and wireless adb port rotation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per request: re-enable allowBackup but scope it to ONE file via
include-rules — files/gbackup/latest.json.age, an age-encrypted export
written only while a backup passphrase is set (never plaintext to
Google; DB/prefs stay excluded). On a new device the OS restores the
blob, the Today screen detects an empty DB + present blob and offers
'Gjenopprett' — which demands the passphrase typed, since the Keystore
key never migrates. Clearing the passphrase deletes the blob.
scrypt work factor dropped 18→15: age's desktop default needs a 256 MiB
working set and OOM-crashed on-device (found the hard way); 15 = 32 MiB,
still real brute-force cost, and largeHeap covers decrypting foreign
files made at 18. Verified by instrumented round-trip tests (write →
empty DB → restore; wrong passphrase keeps DB empty; cleared passphrase
removes blob) — UI automation couldn't drive the multi-field dialog
reliably, so the proof lives in the test instead.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The daily digest splits in two: low stock stays an auto-cancel
notification re-posted each morning while below the per-item limit;
prescription renewal becomes a separate ONGOING notification starting
7 days before rx expiry — survives 'Clear all', swipe-dismissable on
Android 14+, returns each morning until the rx date is updated, and
cancels itself once renewed (post-or-cancel in SupplyCheckReceiver).
Check time is now configurable (Innstillinger → Varsler, M3 TimePicker,
default 10:00); same PendingIntent so re-arming replaces. 'Slå opp i
Felleskatalogen' buttons on the item editor and the med editor's
summary card open the browser — decision #8 clarified: the ban covers
Felleskatalogen as a data source, not human-facing links.
Emulator-verified: both notifications post with correct flags
(ONGOING_EVENT vs AUTO_CANCEL), auto-clear after renewal/restock,
alarm follows the configured time (10:00 → 07:30), FK button opens
Chrome.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Post-incident: an unscoped connectedDebugAndroidTest fanned out to every
adb device including the personal phone, where the debug test APK's
signature mismatch was resolved by UNINSTALLING the release app — wiping
its data. The v1->v2 Room migration was initially blamed but is innocent
(three emulator replays preserved data; dumpsys firstInstallTime ==
lastUpdateTime proved the phone got a fresh install, not an upgrade).
connected* tasks now fail fast unless ANDROID_SERIAL names an emulator.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Written for the repo's future reader (mostly me): why each reliability
mechanism exists, how to decrypt a backup off-device with age -d, the
FEST pipeline, and the keystore.properties signing convention. CLAUDE.md
now points at it for architecture detail, per its own placeholder.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Amends decision #8: the producer now lives in tools/fest_flatten.py
(stdlib Python, streaming iterparse over the 115 MB M30 XML) instead of
an out-of-repo server job. It pulls fest251.zip from dmp.no, flattens
8934 active human-use brand entries (name/strength/unit/form/ATC +
modal package size from pakningsinfo), and writes the asset checked in
at app/src/main/assets/fest/slim.json — so autocomplete works offline
out of the box. preReleaseBuild depends on refreshFestData: fast-exits
under 30 days, keeps the old file on download failure (offline release
builds never break). FestRepository: downloaded cache wins over the
bundled asset.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Captures what cost time this session: AGP 9 built-in Kotlin (KGP-bundled
version pinning), KSP's standalone versioning blocking Kotlin 2.4,
JAVA_HOME requirement, release signing flow, emulator verification
recipes, and the new code contracts (DoseActions single-path, backup
DTO/enum names as file-format contract, CCTV gate on kage bumps).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Milestone 1 of the build brief. Version catalog pins verified against
Maven Central / Google Maven on 2026-06-10; Kotlin held at 2.3.10 to
match AGP 9.2's bundled KGP (built-in Kotlin) because KSP has no
Kotlin 2.4 release yet. compileSdk 37 (forced by core-ktx 1.19),
targetSdk 35 per brief. allowBackup=false + full dataExtractionRules
opt-out; own encrypted backup comes in milestone 5.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>