Skip to content

fix(pdf): journal annotation changes durably - #1551

Draft
Jeremy1844 wants to merge 1 commit into
Adventech:mainfrom
Jeremy1844:fix/adv-2026-0004-pdf-annotation-journal
Draft

fix(pdf): journal annotation changes durably#1551
Jeremy1844 wants to merge 1 commit into
Adventech:mainfrom
Jeremy1844:fix/adv-2026-0004-pdf-annotation-journal

Conversation

@Jeremy1844

@Jeremy1844 Jeremy1844 commented Jul 29, 2026

Copy link
Copy Markdown

Draft PR packet: ADV-2026-0004

Proposed PR

  • Suggested title: fix(pdf): journal annotation changes durably
  • Upstream target: Adventech/sabbath-school-android / main
  • Audited and last revalidated public base: 55405f66a8c555047dc0035747acdcaa371d59fa
  • Published fork branch: fix/adv-2026-0004-pdf-annotation-journal
  • Published fork head: d405036605dd2d45a82d8ae0a796049a09154f8b
  • Shape: one commit, sole parent is the base above; one isolated root only (RC-0004)
  • State: published as draft PR #1551 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.

The canonical worklog proves this is an published, complete head with zero changed-file overlap against RC-0001, RC-0002, and RC-0003, so it qualifies for a separate packet.

Why

PDF annotation persistence occurred only in onStop(), leaving edits vulnerable to process death or native failure. Restore removed current annotations before validating incoming Instant JSON, serialization silently dropped values equal to null, absent and explicitly empty states were conflated, and compacted descriptor indexes could save under the wrong PDF ID. This is a confirmed P0 PDF slice of Android issue #1545.

Failing-before reproduction

The audited module has no unit tests (:features:pdf:testReleaseUnitTest reports NO-SOURCE). Regression-first additions initially fail to compile because journal/session/restore boundaries do not exist. Deterministic tests then model:

  1. Persist a mutation to the journal but withhold the debounced repository save.
  2. Destroy and recreate the session over the same private directory.
  3. Require the dirty generation to restore and replay.

They also seed a valid current snapshot plus a partially malformed candidate; the base clear-then-decode path leaves a partial/empty document, while the fixed path must retain or reconstruct the last-known-good state.

Minimal fix

  • Listen to PDF SDK create/update/remove/z-order mutations and capture complete snapshots.
  • Synchronously write a bounded, checksummed, versioned primary/backup sidecar before the existing debounced repository save.
  • Use one debounce queue per PDF and preserve descriptor identity/index.
  • Restore a dirty generation before the first repository emission and mark it clean only on equivalent acknowledgement.
  • Validate complete current and candidate snapshots before destructive replacement; roll back a partial candidate.
  • Distinguish absent input from explicit empty input and clean private sidecars on logout/account deletion.
  • Preserve Room schema, wire models, stable IDs, and API paths.

Recorded local checks

  • PASS: PDF regression suite, 18/18, covering restart, stale emissions, failed/interrupted writes, backup recovery, corrupt evidence, per-PDF debounce, safe replacement, absent-versus-empty, and index preservation.
  • PASS: auth cleanup suite, 5/5.
  • PASS: :features:pdf:check :common:auth:check spotlessCheck.
  • PASS: :app:assembleRelease (1,200 tasks).
  • PASS: clean merge trees against RC-0001/0002/0003.
  • PASS: combined RC-0002 + RC-0004 focused integration, 18 PDF + 5 auth + 5 sync tests.

These are local Windows-hosted JVM/fake/Gradle and unsigned assembly results. No licensed runtime, hosted Actions, emulator, physical-device, power-loss, signed, store, server, or production result is claimed.

The 2026-07-28 delivery refresh reconfirmed the unchanged target and zero-overlap PR set. The exact clean head passed 349/349 focused tasks with 18/18 PDF tests, the combined PDF/auth/format gate with 23/23 emitted tests, and a fresh unsigned app release assembly. This is local regression/build evidence only; the licensed-device, process-kill, low/disk-full storage, power-loss, server-conflict, privacy, rollback, and hosted gates below remain open.

Overlap and disposition

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

RC-0004 is file-disjoint from RC-0001/0002/0003 and should remain its own PR. RC-0002 is still needed to make replay durable through Room/network conflict and retry. Do not combine this root with the verification stack.

Migration, recovery, and rollback

  • No Room migration; the additive sidecar is created only after a future annotation mutation.
  • A valid backup recovers an interrupted/corrupt primary; corrupt generations are retained as evidence and never treated as content.
  • An explicit empty snapshot clears its addressed PDF; absence performs no clear.
  • Existing lost annotations cannot be reconstructed without a trusted backup/server copy.
  • An old binary ignores dirty sidecars. Safe rollback first replays every dirty generation into the existing repository and proves equivalence; never delete sidecars to make rollback pass.

Security, privacy, and content rights

Sidecars remain in the app sandbox under noBackupFilesDir, use hashed filenames, bound decoding, and do not log payloads/raw IDs. They are checksummed but not newly encrypted; device-compromise encryption is a separate design. No content, translation, lesson, PDF/video asset, Bible/EGW material, credential, signing, or deployment file changes.

Dependency order and draft blockers

Review independently after the higher-readiness Android roots, then retest in the final RC-0002 composition. Keep the PR draft until production-licensed devices cover annotation create/update/remove/z-order, final deletion, multiple/unloaded PDFs, lifecycle/process kill, offline relaunch, low/disk-full storage, corruption/rollback, logout/account deletion, vendor filesystem/power-loss behavior, and required hosted checks. Confirm server conflict semantics with an authorized nonproduction account.

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