Skip to content

feat(app): repair saved feed addresses after the update - #1183

Merged
ashwkun merged 16 commits into
masterfrom
feat/upgrade-address-repair
Oct 27, 2026
Merged

ashwkun merged 16 commits into
masterfrom
feat/upgrade-address-repair

Conversation

@ashwkun

@ashwkun ashwkun commented Oct 27, 2026

Copy link
Copy Markdown
Member

Title

feat(app): repair saved feed addresses after the update

Summary

  • After someone updates from an older build, boxlore checks the saved feed address of every followed Podcast Index show once. It switches to the confirmed new address, reads each show's feed again, and registers new-episode notifications again.
  • Built on top of feat(catalog): update feed addresses in one place and check them daily #1182 (FeedAddressUpdater, the daily address check and chunking). Review that PR first.

Motivation

  • Older builds kept feed addresses that may have moved or broken since. Without a one-time repair, those follows would stay on dead or frozen feeds and stop getting new episodes and notifications until the daily check reached them. Notification topics on a restored phone are not registered either.

What changed

  • UpgradeAddressRepair (:core:catalog) runs four steps for each show the v39 upgrade seeded into upgrade_repair_shows, and records each step as soon as it finishes:
    1. Address check (UpgradeAddressCheckStep): POST /v2/shows/feeds in chunks of up to 500. Only a confirmed move (the registry flags the show for repair and returns its own direct HTTPS address) is kept. A 503, 429, other 5xx, a network error or registryAvailable: false counts no try, and after 7 days the show continues without an answer. A refused or unreadable answer counts a try, and after 5 tries the show continues without an answer. An answer older than a day is asked for again, never applied.
    2. Swap the address through the one address writer (FeedAddressUpdater) with compare-and-set on the saved address. A follow changed on this phone and not yet pushed keeps its address.
    3. Read the feed again (rereadWith) without the foreground auto-download pass. The server's episode namespace is passed for comparison only and never changes an issued ID. After 5 failed tries while online, the show ends as gave-up and the daily check takes over.
    4. Register notifications again (UpgradeNotificationStep). A show is recorded only after WorkManager has saved its request (PodcastNotificationRegistrationWorker.request). The record lives in noBackupFilesDir, so a restored phone registers again.
  • Once no show has steps 1–3 left, UserSyncCoordinator.requestIdentityCatchUp() runs once. It lowers the sync metadata version from 3 to 2, so the next sync's identity catch-up sends the identity of episodes the reads settled. It never runs on a fresh install.
  • UpgradeRepairWorker (permanent unique work feed-address-upgrade-repair, KEEP, needs a network connection, backoff from 30 s, at most 10 runs per launch) is enqueued at launch while work is left. needsWork() settles a fresh install without using the network.
  • The existing upgrade-repair-off kill switch pauses the repair without marking anything done.
  • feed_fetch_result (background pass) gains namespace_mismatch_count, sent only when greater than 0. feed_url_corrected reports swaps with step upgrade_repair.
  • UpgradeRepairDao.hasShows(): a DAO query only, with no schema change.

Behavior & compatibility

  • No UI change, so no phone, tablet, foldable or resizable-window states are affected.
  • Room schema unchanged (v39). Episode IDs, rss: and negative IDs, deep links and cache keys are unchanged. The new permanent names are added to the ARCHITECTURE.md table.
  • Uses the existing /v2/shows/feeds route, with no server change.

Impact (required)

  • user-impact-critical
  • user-impact-high
  • user-impact-medium
  • user-impact-low
  • no-user-impact

What changes in the user's life:

  • After updating, shows whose feed moved start getting new episodes and notifications again, with nothing for the listener to do.

  • backend-change

Release copy (verbatim — highest priority)

CHANGELOG.md (required developer copy)

Added

  • One-time feed address repair after the update (UpgradeAddressRepair, UpgradeRepairWorker with work name feed-address-upgrade-repair): checks saved addresses through /v2/shows/feeds, swaps confirmed moves through FeedAddressUpdater, re-reads each followed show and re-registers notifications, then reruns the cloud sync identity catch-up once.
  • namespace_mismatch_count on background feed_fetch_result events.

README What's New / Upcoming (required for user-impact changes)

Fixes

  • After updating, boxlore checks the shows you follow and switches any whose feed has moved, so new episodes and notifications keep arriving.

Test plan

  • JVM: UpgradeAddressRepairTest (24), UpgradeAddressRepairApiTest (3, real BoxLoreApiV2 over MockWebServer with /v2/shows/feeds fixtures), CloudSyncIdentityTest (20), UpgradeRepairWorkerTest (6), PodcastNotificationRegistrationWorkerTest (5), AppContainerSmokeTest (6), FeedAnalyticsTracksTest
  • :core:catalog, :core:database, :core:analytics, :core:network, :core:model and :app unit tests, plus :app:compileDebugKotlin and detekt
  • ktlint on touched modules. :app:ktlintTestSourceSetCheck reports violations only in files this PR doesn't touch (FeedFirstSwitchTest, FeedFixSwitchesTest, SavedKillSwitchTest), which predate it.
  • Device: upgrade install on a phone from the previous release build, then check that the repair finishes and follows, history, episode IDs and notifications are unchanged (not done yet)
  • Required checks are green before merge

Notes (optional)

  • Source inspection and JVM tests only. No device evidence yet.
  • The /v2/shows/feeds fixtures follow the route's code and tests field for field. They were not recorded from the live route.
  • Known risk: a show whose notification registration job uses up all 8 of its tries stays unregistered until its address changes again or the listener turns its notifications off and on.

@ashwkun ashwkun added the user-impact-medium Noticeable but not headline — include in README when space allows label Oct 27, 2026
@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 12 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between da7cde7 and 0e63a98.

Files ignored due to path filters: 1
  • docs/analytics/event_glossary.csv is excluded by !**/*.csv
Files selected for processing: 29
  • ARCHITECTURE.md
  • app/README.md
  • app/src/main/java/cx/aswin/boxlore/AppContainer.kt
  • app/src/main/java/cx/aswin/boxlore/BoxLoreApplication.kt
  • app/src/main/java/cx/aswin/boxlore/fcm/PodcastNotificationRegistrationWorker.kt
  • app/src/main/java/cx/aswin/boxlore/sync/UpgradeRepairWorker.kt
  • app/src/test/java/cx/aswin/boxlore/AppContainerSmokeTest.kt
  • app/src/test/java/cx/aswin/boxlore/fcm/PodcastNotificationRegistrationWorkerTest.kt
  • app/src/test/java/cx/aswin/boxlore/sync/UpgradeRepairWorkerTest.kt
  • core/analytics/README.md
  • core/analytics/src/main/java/cx/aswin/boxlore/core/analytics/FeedAnalyticsTracks.kt
  • core/analytics/src/test/java/cx/aswin/boxlore/core/analytics/FeedAnalyticsTracksTest.kt
  • core/catalog/README.md
  • core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/SharedAppDependencies.kt
  • core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/UpgradeAddressCheck.kt
  • core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/UpgradeAddressRepair.kt
  • core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/UpgradeNotificationMarker.kt
  • core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/UpgradeNotificationStep.kt
  • core/catalog/src/main/java/cx/aswin/boxlore/core/catalog/sync/UserSyncCoordinator.kt
  • core/catalog/src/test/java/cx/aswin/boxlore/core/catalog/UpgradeAddressRepairApiTest.kt
  • core/catalog/src/test/java/cx/aswin/boxlore/core/catalog/UpgradeAddressRepairTest.kt
  • core/catalog/src/test/java/cx/aswin/boxlore/core/catalog/sync/CloudSyncIdentityTest.kt
  • core/catalog/src/test/resources/fixtures/v2/README.md
  • core/catalog/src/test/resources/fixtures/v2/shows-feeds-registry-down.json
  • core/catalog/src/test/resources/fixtures/v2/shows-feeds-upgrade-cases.json
  • core/database/README.md
  • core/database/src/main/java/cx/aswin/boxlore/core/database/UpgradeRepairDao.kt
  • core/model/README.md
  • core/model/src/main/java/cx/aswin/boxlore/core/model/FeedTelemetry.kt
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

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

Base automatically changed from feat/feed-address-updates to master October 27, 2026 18:56
…s-repair

# Conflicts:
#	ARCHITECTURE.md
#	app/README.md
#	app/src/main/java/cx/aswin/boxlore/AppContainer.kt
#	app/src/main/java/cx/aswin/boxlore/fcm/PodcastNotificationRegistrationWorker.kt
#	app/src/test/java/cx/aswin/boxlore/fcm/PodcastNotificationRegistrationWorkerTest.kt
#	core/catalog/README.md
#	core/catalog/src/test/resources/fixtures/v2/README.md
#	core/database/README.md
@ashwkun
ashwkun enabled auto-merge (squash) October 27, 2026 18:58
…s-repair

# Conflicts:
#	app/README.md
#	app/src/main/java/cx/aswin/boxlore/AppContainer.kt
#	core/catalog/README.md
#	core/catalog/src/test/resources/fixtures/v2/README.md
@sonarqubecloud

Copy link
Copy Markdown

@ashwkun
ashwkun merged commit 683de45 into master Oct 27, 2026
9 checks passed
@ashwkun
ashwkun deleted the feat/upgrade-address-repair branch October 27, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

user-impact-medium Noticeable but not headline — include in README when space allows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant