Commit graph

6 commits

Author SHA1 Message Date
4f1e76eca2 Release signing from gitignored keystore.properties
Keystore at ~/.keystores/meddetsamme-release.jks (4096-bit RSA, 30 yr),
credentials in keystore.properties — both outside version control. A
clone without the file still builds (unsigned release) instead of
failing, so nothing breaks for CI or a fresh checkout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 14:27:40 +02:00
c66bee5cf0 age crypto via kage, verified against the CCTV scrypt vectors
Milestone 6. kage 0.4.0 over Jagged: Android-first (explicitly supports
API 26, matching minSdk), Kotlin, ships its own primitives through
BouncyCastle instead of relying on JCA ChaCha20-Poly1305 which Android
only provides from API 28. AgeBackupCrypto sits behind the same
BackupCrypto interface as the JCE baseline; age is now first in all()
so new encrypted backups are written as binary age v1 files,
decryptable anywhere with 'age -d' (decision #7). Old MDS1/JCE backups
keep decrypting via format auto-detection. The C2SP/CCTV scrypt vector
subset (19 files) is vendored into test resources: both success
vectors decrypt with matching payload SHA-256, all 17 failure vectors
are rejected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 14:00:34 +02:00
8f5b18cf68 Backup: versioned JSON serializer, SigV4 + S3 client, JCE crypto, daily worker
Milestone 5. One BackupManager entry point so export, import and
auto-backup share the same serializer and crypto by construction.
Explicit DTOs decouple the backup contract from the Room schema.
JCE baseline (PBKDF2-HMAC-SHA256 600k → AES-256-GCM) behind the
BackupCrypto interface with format auto-detection on decrypt; age
lands behind the same interface in milestone 6. SigV4 signer verified
against AWS's published documentation example signature. Settings in
SharedPreferences encrypted under a non-exportable AndroidKeyStore key
— replaces the now fully deprecated androidx security-crypto with the
same construction (~70 lines, zero deps); threat-model comments state
plainly that the stored auto-backup passphrase only protects against
bucket compromise. WorkManager daily periodic job, inexact by design.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 13:54:13 +02:00
46a5d7e98e Reminder subsystem: exact alarms, escalation, boot re-arm — verified on emulator
Milestone 4. AlarmScheduler is the only AlarmManager writer; one stable
PendingIntent requestCode per dose-time means re-arming replaces and can
never stack (the no-drift invariant is OS-enforced). DoseAlarmReceiver
handles both occurrence and escalation alarms idempotently and always
re-arms the next occurrence before anything else so the chain can't
break. nagCount lives in dose_log so the ~6-nag cap survives reboot.
SCHEDULE_EXACT_ALARM added maxSdk 32 (USE_EXACT_ALARM is 33+ only).

Emulator-verified (API 35): exact alarm armed (window=0,
policy_permission), fired on time, HIGH notification with Tatt/Utsett,
escalation armed +10 min, next day re-armed, Tatt → TAKEN + inventory
10→9 + escalation cancelled, reboot → BootReceiver re-armed everything.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 13:48:39 +02:00
b884885e40 Data layer: Room entities, DAOs, database with exported schema
Milestone 2. Medication / DoseTime / DoseLog per the brief's model.
DoseLog.doseTimeId is SET_NULL (schedule edits must not erase adherence
history) while medId CASCADEs; DoseLog.amount is snapshotted at logging
time so later dose changes don't rewrite the record. Inventory decrement
is a single SQL UPDATE clamped at 0 to stay race-free under escalating
notifications. Enums stored as TEXT; schema exported to app/schemas as
the migration baseline.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 13:34:41 +02:00
7256c49112 Project skeleton: Gradle 9.4.1 wrapper, AGP 9.2.1, Compose, manifest with reminder permission set
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>
2026-06-10 13:31:39 +02:00