Fixed — both moved into DAO @Transaction helpers (readModifyWrite, insertMakingFirstDefault)
All fixes follow the codebase's established pattern (AccountDao.insertAtEnd/SignatureDao.setDefault): read-modify-write / check-then-act wrapped in a DAO @Transaction default method. No Room entity/schema change — only DAO methods were added, so no migration is needed.
Notable decisions
Nit 2: observeSummaries was dead in main but still used by a debug-only cache probe and several instrumented tests. The #51 CursorWindow regression guard was re-pointed at the real production pagingUnifiedFolderSummaries query (strictly better coverage); the other callers moved to targeted getById reads.
Nit 6a: kept the domain-level transform in the repository and routed it through a lambda-taking DAO @Transaction, so the fast JVM setter tests (clamping, field preservation) stay intact and JVM coverage is preserved.
Tests
JVM unit tests updated for the repository delegations (SignatureRepositoryTest, AccountSettingsRepositoryTest) + a new chunk-split case in MailRepositoryImplTest.
Instrumented DAO tests cover the new @Transaction behaviour (SignatureDaoTest, AccountSettingsDaoTest) and the -journal sweep (DatabaseEncryptionTest).
Addresses every below-cut data-core review nit collected in #313.
## Per-nit disposition
| # | Nit | Disposition |
|---|-----|-------------|
| 1 | `SignatureRepository.delete` non-atomic delete+promote-default | **Fixed** — new `SignatureDao.deletePromotingDefault` @Transaction; repo delegates + logs the promotion (PII-free) |
| 2 | `MessageDao.observeSummaries` dead full-scan API | **Fixed** — removed; migrated test/debug-probe callers to `getById` / the paged query |
| 3 | Unchunked `IN(:ids)` in `MailRepositoryImpl` expunge/move | **Fixed** — `getRoutingByIds`/`deleteByIds` chunked at 500 like `MailPruner` |
| 4 | `AccountDataMigrator` stale KDoc (says v1/1.json) | **Fixed** — KDoc now v2/2.json + notes the `sortOrder` addition |
| 5 | `DatabaseEncryption.migrate` doesn't sweep `-journal` | **Fixed** — sweeps `-journal` too (the file is in `journal_mode = DELETE`) |
| 6 | `AccountSettingsRepository.update` / `SignatureRepository.create` non-atomic RMW / check-then-act | **Fixed** — both moved into DAO @Transaction helpers (`readModifyWrite`, `insertMakingFirstDefault`) |
All fixes follow the codebase's established pattern (`AccountDao.insertAtEnd`/`SignatureDao.setDefault`): read-modify-write / check-then-act wrapped in a DAO `@Transaction` default method. **No Room entity/schema change** — only DAO methods were added, so no migration is needed.
### Notable decisions
- **Nit 2**: `observeSummaries` was dead in `main` but still used by a debug-only cache probe and several instrumented tests. The `#51` CursorWindow regression guard was re-pointed at the real production `pagingUnifiedFolderSummaries` query (strictly better coverage); the other callers moved to targeted `getById` reads.
- **Nit 6a**: kept the domain-level transform in the repository and routed it through a lambda-taking DAO `@Transaction`, so the fast JVM setter tests (clamping, field preservation) stay intact and JVM coverage is preserved.
## Tests
- JVM unit tests updated for the repository delegations (`SignatureRepositoryTest`, `AccountSettingsRepositoryTest`) + a new chunk-split case in `MailRepositoryImplTest`.
- Instrumented DAO tests cover the new `@Transaction` behaviour (`SignatureDaoTest`, `AccountSettingsDaoTest`) and the `-journal` sweep (`DatabaseEncryptionTest`).
## Local fast gate (all green)
`assembleDebug` + `testDebugUnitTest` + `jacocoTestCoverageVerification` (floor 0.84) + `compileDebugAndroidTestKotlin` + `lintDebug` + `ktlintCheck` + `detekt`. Full multi-API E2E runs in CI.
Closes #313
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Addresses every below-cut data-core review nit collected in #313.
Per-nit disposition
SignatureRepository.deletenon-atomic delete+promote-defaultSignatureDao.deletePromotingDefault@Transaction; repo delegates + logs the promotion (PII-free)MessageDao.observeSummariesdead full-scan APIgetById/ the paged queryIN(:ids)inMailRepositoryImplexpunge/movegetRoutingByIds/deleteByIdschunked at 500 likeMailPrunerAccountDataMigratorstale KDoc (says v1/1.json)sortOrderadditionDatabaseEncryption.migratedoesn't sweep-journal-journaltoo (the file is injournal_mode = DELETE)AccountSettingsRepository.update/SignatureRepository.createnon-atomic RMW / check-then-actreadModifyWrite,insertMakingFirstDefault)All fixes follow the codebase's established pattern (
AccountDao.insertAtEnd/SignatureDao.setDefault): read-modify-write / check-then-act wrapped in a DAO@Transactiondefault method. No Room entity/schema change — only DAO methods were added, so no migration is needed.Notable decisions
observeSummarieswas dead inmainbut still used by a debug-only cache probe and several instrumented tests. The#51CursorWindow regression guard was re-pointed at the real productionpagingUnifiedFolderSummariesquery (strictly better coverage); the other callers moved to targetedgetByIdreads.@Transaction, so the fast JVM setter tests (clamping, field preservation) stay intact and JVM coverage is preserved.Tests
SignatureRepositoryTest,AccountSettingsRepositoryTest) + a new chunk-split case inMailRepositoryImplTest.@Transactionbehaviour (SignatureDaoTest,AccountSettingsDaoTest) and the-journalsweep (DatabaseEncryptionTest).Local fast gate (all green)
assembleDebug+testDebugUnitTest+jacocoTestCoverageVerification(floor 0.84) +compileDebugAndroidTestKotlin+lintDebug+ktlintCheck+detekt. Full multi-API E2E runs in CI.Closes #313
Merge Queue Status
2026-07-08 13:32 UTC· Rule:default· triggered by merge protections2026-07-08 13:58 UTC· on draft WIP: merge queue: checking main (6802b60) and [#439 + #435 + #438] together (#441)2026-07-08 16:42 UTC· atd0ed168fcb7b967ec74cd22c206aa23213c393c3· mergeThis pull request spent 3 hours 10 minutes 13 seconds in the queue, including 1 hour 22 minutes 14 seconds running CI.
Required conditions to merge
-conflict-draftbase = maincheck-success = CI passedgithub-review-approved[🛡 GitHub repository ruleset rulemain]label != brokencheck-success = Debug buildcheck-neutral = Debug buildcheck-skipped = Debug buildcheck-success = Unit testscheck-neutral = Unit testscheck-skipped = Unit testscheck-success = CI passedcheck-neutral = CI passedcheck-skipped = CI passedmain]:check-success = @github-actions/CI passedcheck-neutral = @github-actions/CI passedcheck-skipped = @github-actions/CI passed