Skip to content

fix(db): v1.5.2 hotfix #2 — bump DB version after entity annotation changes#143

Merged
RaheemJnr merged 2 commits intomainfrom
fix/release-1.5.2-db-version-bump
Apr 30, 2026
Merged

fix(db): v1.5.2 hotfix #2 — bump DB version after entity annotation changes#143
RaheemJnr merged 2 commits intomainfrom
fix/release-1.5.2-db-version-bump

Conversation

@RaheemJnr
Copy link
Copy Markdown
Owner

Summary

Smoke install of the v1.5.2 build (PR #141) on a real device crashed with a different Room error than the original v1.5.1 crash:

```
Room cannot verify the data integrity. Looks like you've changed schema
but forgot to update the version number.
Expected identity hash: 5c3585c27257d8b0a1a3119c4e50e1ac
Found: 821e95d07068b708ea3b07e0d3311b0a
```

Root cause

Room computes its stored identity hash from the @Entity/@ColumnInfo/@Index declarations, not from the on-disk schema. The previous hotfix (#141) added `@Index(idx_tx_pending)` + `@ColumnInfo(defaultValue = "''")` to align the entity declarations with what migrations 1→8 already produced on disk. The on-disk schema didn't change at all, but the entity declarations did, so the identity hash changed.

Room enforces: any DB whose stored identity hash differs from the current entity-derived hash refuses to open, even when the schemas are byte-for-byte identical and the version number is the same.

Fix

  • Bump `@Database` version 8 → 9.
  • Add a no-op `MIGRATION_8_9` and register it in `AppModule`.
  • Update `MigrationTest` to register the new migration so the existing test still compiles.

The migration body is intentionally empty: the on-disk shape is already correct from migrations 1→8. The version bump alone is the mechanism Room provides for refreshing the stored identity hash.

Why this wasn't caught

Same root cause as #142 already tracks: `MigrationTest` uses `inMemoryDatabaseBuilder` which creates a fresh schema and never runs migrations or interacts with on-disk identity hashes. A real-device smoke install is currently the only way to catch identity-hash drift.

Test plan

  • `assembleDebug` succeeds.
  • `testDebugUnitTest` passes.
  • Re-smoke install the v1.5.2 build on the same device that crashed. Confirm app launches and reaches Home.
  • Smoke install v1.5.2 over a clean v1.5.0 install on a different device. Confirm migrations 5→9 run cleanly.

Follow-up

#142 still tracks the permanent fix (real migration test using `MigrationTestHelper` with exported schemas). This identity-hash mismatch is exactly the regression that test would catch, so it strengthens the case for prioritising it.

Smoke install of the previous hotfix on a real device crashed with:

  Room cannot verify the data integrity. Looks like you've changed
  schema but forgot to update the version number.
  Expected identity hash: 5c3585c27257d8b0a1a3119c4e50e1ac
  Found: 821e95d07068b708ea3b07e0d3311b0a

Cause: Room computes its stored identity hash from entity definitions,
not from the on-disk schema. The previous hotfix added @Index and
@ColumnInfo annotations whose effect on the on-disk shape is zero (the
migrations 1->8 already produced exactly that shape), but the entity
definitions themselves changed, which means a new identity hash. Room
refuses to open a v8 DB whose stored hash doesn't match the current v8
hash, even when the schema is byte-for-byte identical.

Fix: bump @database version 8 -> 9 and add a no-op MIGRATION_8_9. This
forces Room to refresh its bookkeeping (re-record the new identity
hash) on the first open after upgrade. Fresh installs at v9 use the
@entity declarations directly, no migrations run.

For users who briefly opened v1.5.1 (and got the old hash written to
disk), v1.5.2 will run MIGRATION_8_9, validate against the entity
declarations (which now match the on-disk shape), pass validation, and
record the new identity hash. No data loss.
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pocket-node Ready Ready Preview, Comment Apr 30, 2026 10:53am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

Warning

Rate limit exceeded

@RaheemJnr has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 28 minutes and 43 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2289e9c4-4339-4cb7-ab54-c0705a5804da

📥 Commits

Reviewing files that changed from the base of the PR and between 79fa614 and 9756bba.

📒 Files selected for processing (4)
  • android/app/src/main/java/com/rjnr/pocketnode/data/database/AppDatabase.kt
  • android/app/src/main/java/com/rjnr/pocketnode/data/database/Migrations.kt
  • android/app/src/main/java/com/rjnr/pocketnode/di/AppModule.kt
  • android/app/src/test/java/com/rjnr/pocketnode/data/database/MigrationTest.kt
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/release-1.5.2-db-version-bump

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 28 minutes and 43 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Smoke install of the previous patch on the same device crashed with
the same TableInfo mismatch as the original v1.5.1 crash, just from
the opposite direction. The on-disk DB has neither idx_tx_pending nor
walletId DEFAULT '', because the user installed v1.5.1 fresh — Room
created v8 directly from v1.5.1's broken entity declarations, which
declared neither.

Two distinct v8 shapes exist in the wild:
  Path A — upgrade from v1.5.0: ran MIGRATION_2_3 (walletId DEFAULT '')
           and MIGRATION_5_6 (idx_tx_pending). Both present.
  Path B — fresh install on v1.5.1: schema came straight from broken
           entities. Neither present.

The previous no-op MIGRATION_8_9 was sufficient for path A but left
path B mismatched against the v1.5.2 entity declarations.

This rewrite recreates transactions, balance_cache, and dao_cells with
the canonical column DEFAULT '' on walletId, and (re)creates
idx_tx_pending as a regular index (matching what the entity declares).
Idempotent against both paths: path A users get the same shape back,
path B users get the missing pieces.
@RaheemJnr
Copy link
Copy Markdown
Owner Author

Smoke #2 on same device: still crashed, this time with a TableInfo mismatch where the on-disk DB lacks idx_tx_pending and walletId DEFAULT '' — i.e. the previous no-op migration was insufficient for users who fresh-installed v1.5.1 (Room created v8 directly from v1.5.1's broken entity declarations, which themselves declared neither, so the DB was missing both pieces).

Two divergent v8 shapes exist now:

  • Path A — upgrade from v1.5.0: idx_tx_pending + DEFAULT '' are on disk.
  • Path B — fresh install on v1.5.1: neither is on disk.

Pushed 9756bba to rewrite MIGRATION_8_9 from a no-op into a real migration that recreates transactions, balance_cache, and dao_cells with the canonical DEFAULT '' on walletId and (re)creates idx_tx_pending. Idempotent against both paths.

Smoke install one more time after this lands. Sorry for the back-and-forth — this is the exact failure shape that #142 (real MigrationTestHelper test) would catch in CI.

@RaheemJnr RaheemJnr merged commit ac2ba6b into main Apr 30, 2026
5 checks passed
@RaheemJnr RaheemJnr deleted the fix/release-1.5.2-db-version-bump branch April 30, 2026 11:15
RaheemJnr added a commit that referenced this pull request Apr 30, 2026
…) (#147)

* test(db): walking-migration regression guard + Room schema export (#142)

The pre-existing MigrationTest used Room.inMemoryDatabaseBuilder which
creates the schema directly from the current entity declarations and
never exercises Migration.migrate code paths. So when v1.5.1's entity
declarations drifted from what the migrations produced, the in-memory
test passed but real upgraders crashed at launch (#141, #143).

Adds:

1. Room schema export (exportSchema = true + ksp arg pointing at
   app/schemas/). Generates a versioned JSON dump per @database
   version. v9 committed in this PR. Future schema drift becomes
   visible in PR diffs.

2. WalkingMigrationTest: bootstraps a SQLite file at v8 with a known
   historical shape, opens it via Room.databaseBuilder, and lets Room
   run MIGRATION_8_9 + validate the result against entity declarations.
   Two test methods cover the divergent v8 shapes that existed in the
   wild after v1.5.1:
     - Path A (upgrade-from-v1.5.0): walletId DEFAULT '' + partial
       idx_tx_pending already on disk.
     - Path B (fresh-install-on-v1.5.1): neither.
   Both must converge to v9 successfully.

3. Regression-guard test that registers a no-op MIGRATION_8_9 (what
   the first cut of #143 shipped) and asserts path B fails with the
   exact 'Migration didn't properly handle' exception that surfaced
   in production. Permanent in-codebase guard against the test losing
   its detection power.

Note on scope: the JVM/Robolectric harness here covers the v8→v9
upgrade path because that is where the historical fork lives.
Walking from v1 forward is harder without an exported schema for v1
and is tracked in #144 Phase 2 (instrumented MigrationTestHelper).

* fix(ci): don't commit Room schema JSONs (kotlinx-serialization conflict)

CI's clean build hit AbstractMethodError in Room's
SchemaBundle.$serializer because Room 2.8.4's bundled
kotlinx-serialization-core is binary-incompatible with the project's
kotlinx-serialization-json:1.8.0 on a fresh classpath. Local builds
didn't repro because of cached classloaders.

When a schema JSON exists at the target version, Room's processor
deserializes it to diff against the new export. With no JSON present,
Room only writes a new one, no deserialize path, no crash.

Workaround: don't commit the JSONs. They're still generated on every
build (locally and in CI), they just don't get persisted. The
walking-migration test doesn't depend on them — it validates against
entity declarations directly.

Trade-off lost: schema diffs aren't visible in PR review. We get them
back when we either upgrade Room to a version compiled against
kotlinx-serialization 1.8.x, or downgrade kotlinx-serialization-json to
1.7.x. Tracked alongside #142.

* fix(ci): turn Room exportSchema off; track re-enable in #149

Same AbstractMethodError surfaced even after .gitignore'ing the JSONs:
Room's deserialize path runs on every KSP cycle, not only when an
existing schema file is present. The dep conflict between Room 2.8.4
and kotlinx-serialization 1.8.0 needs a real fix before exportSchema
can be on.

Reverts the @database exportSchema flag and the room.schemaLocation
KSP arg. The walking-migration test under src/test/ still validates
schema-vs-entity drift via Room's onMigrate path, so #142's
regression-guard value is unaffected.

Re-enabling tracked in #149.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant