Skip to content

fix(storage): preserve v26 legacy user input - #1550

Draft
Jeremy1844 wants to merge 1 commit into
Adventech:mainfrom
Jeremy1844:fix/adv-2026-0003-v26-migration
Draft

fix(storage): preserve v26 legacy user input#1550
Jeremy1844 wants to merge 1 commit into
Adventech:mainfrom
Jeremy1844:fix/adv-2026-0003-v26-migration

Conversation

@Jeremy1844

@Jeremy1844 Jeremy1844 commented Jul 29, 2026

Copy link
Copy Markdown

Draft PR packet: ADV-2026-0003

Proposed PR

  • Suggested title: fix(storage): preserve v26 legacy user input
  • Upstream target: Adventech/sabbath-school-android / main
  • Audited and last revalidated public base: 55405f66a8c555047dc0035747acdcaa371d59fa
  • Published fork branch: fix/adv-2026-0003-v26-migration
  • Published fork head: 420ecbb013c957c99b73b6916163056ae2362361
  • Shape: one commit, sole parent is the base above; one root only (RC-0003)
  • State: published as draft PR #1550 from the authorized personal fork; not merged or deployed.

Publication privacy note: the branch commit metadata was recreated with the account's GitHub noreply identity before review. Its source tree, message, parent, and stable patch ID are unchanged, so the recorded source-tree validation remains applicable to the published head.

Why

The production v26-to-v27 Room migration deleted the durable annotations, comments, and highlights tables. A global destructive fallback could erase the complete database on unsupported paths. The old identifiers do not prove a safe semantic mapping into current block-level input, so the minimal data-preserving remedy quarantines the original rows byte-for-byte rather than guessing. This is a confirmed P0 slice of Android issue #1545.

Failing-before reproduction

.\gradlew.bat :services:storage:impl:testReleaseUnitTest --tests 'ss.services.storage.impl.migration.LegacyUserInputMigrationTest' --stacktrace --no-daemon

With a populated v26 database, the initial migration test fails because legacy_annotations_v26 does not exist after migration. A second deliberate red privacy phase observes one retained legacy row after the real UserInputDao.clear(), proving recovery tables also need account-deletion/logout semantics.

Minimal fix

  • Replace the destructive 26-to-27 auto-migration with a transaction that renames all three tables to managed legacy_*_v26 recovery tables.
  • Declare exact Room entities matching the v26 columns, types, defaults, nullability, and keys.
  • Add the recovery tables to version 33, remove destructive fallback, and fail closed on missing migration paths.
  • Clear modern and quarantined input together in the real DAO transaction.
  • Defer semantic import until maintainers provide a verified ID/payload corpus.

Recorded local checks

  • Expected RED: populated v26 migration loses the recovery table; privacy red leaves a legacy row after clear().
  • PASS: focused real Room/Robolectric migration and privacy test.
  • PASS: :services:storage:impl:check :services:storage:impl:assembleRelease :common:auth:testReleaseUnitTest (297 tasks).
  • PASS: :libraries:storage:api:check :libraries:storage:test:check :common:auth:check (368 tasks).
  • PASS: :app:assembleRelease (1,200 tasks).
  • PASS: exact v26 source/recovery schema comparison, diff check, clean tree, and base/merge-base comparison.
  • PASS in the verification-only RC-0001/0003/0002 stack: both real migration suites and combined 37/37 tests.

These are local Windows-hosted Robolectric/SQLite/Gradle results. No hosted Actions, production database, emulator, physical-device, signed, store, or production result is claimed.

The 2026-07-28 delivery refresh reconfirmed the unchanged public target and zero-overlap PR set. The exact clean head passed the real migration fixture (1/1), the 297-task storage/auth release gate (5/5 emitted tests), the storage compatibility gate (4/4 emitted tests), and a restarted fresh :app:assembleRelease --rerun-tasks. This refresh adds local delivery confidence only; it does not satisfy the production-signed copied-database, device, low-storage/interruption, privacy, hosted, or rollback gates below.

Overlap and disposition

Android PR #1548 at 8523d93c0f05376b30113a2b24c1f7bbccc30aa0 has zero overlap and remains separate.

RC-0003 conflicts semantically with RC-0002 only because both isolated roots declare different version-33 schemas. Review this preservation/privacy root before choosing RC-0002's final migration number. The composed verification head is evidence only, never a multi-root PR.

Migration, recovery, and rollback

  • Still-v26 installs retain exact rows through atomic table renames.
  • v27-through-v32 installs get empty managed recovery tables; data already deleted by historical releases cannot be reconstructed.
  • Recovery must operate on a database copy, inventory/hash raw rows, retain the archive, and use a separately reviewed semantic mapper. Never guess a block/PDF mapping or mutate the only copy.
  • Logout/account deletion intentionally clears current and quarantined private input together.
  • There is no safe in-place downgrade. Rollback is a forward fix; an emergency binary rollback requires a verified matching pre-upgrade database snapshot. Reverting this root restores a confirmed destructive path.

Security, privacy, and content rights

Recovery rows may contain private notes and annotations. They must not appear in public artifacts, telemetry, or implicit uploads. This root adds no content, translation, lesson, PDF/video asset, Bible/EGW material, credential, signing, or deployment change.

Dependency order and draft blockers

This schema/privacy root precedes RC-0002. Keep the PR draft until maintainers identify the actual shipped database lineage, production-signed upgrades pass on copied representative v26 databases under low-storage/interruption/process-death conditions, logout/account-deletion privacy is verified on-device, support approves treatment for already-affected users, and required hosted checks pass.

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