Skip to content

fix: classify notification reply send failures#1378

Draft
agent-p1p wants to merge 2 commits into
masterfrom
pip/whitenoise-android-1276
Draft

fix: classify notification reply send failures#1378
agent-p1p wants to merge 2 commits into
masterfrom
pip/whitenoise-android-1276

Conversation

@agent-p1p

@agent-p1p agent-p1p commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Return a typed notification-reply send outcome instead of collapsing every failure to false.
  • Classify only proven pre-send relay connection failures as transient; invalid, terminal, and ambiguous post-send failures fail fast.
  • Preserve the existing three-attempt WorkManager bound for transient failures and cancellation propagation.

Test plan

  • ./gradlew :app:testDebugUnitTest --tests dev.ipf.whitenoise.android.state.TransientRelaySendErrorTest --tests dev.ipf.whitenoise.android.notifications.NotificationTargetTest
  • ./gradlew :app:testDevDebugUnitTest :app:lintDevDebug --no-daemon --stacktrace
  • ./gradlew :app:verifyRoborazziDevDebug --no-daemon --stacktrace
  • ./gradlew :app:ktlintCheck --no-daemon --stacktrace

Fixes #1276


Open in Stage

Summary by CodeRabbit

  • Bug Fixes

    • Improved notification reply delivery handling by distinguishing successful, temporary, and permanent failures.
    • Temporary delivery issues are retried automatically, while permanent failures stop without unnecessary retries.
    • Successfully sent replies now consistently mark messages as read, dismiss related notifications, and record the action as completed.
    • Invalid reply details are handled safely without triggering retries.
  • Tests

    • Added coverage for retry limits and failure classification.

Return a typed send outcome so the notification worker fails terminal errors immediately and only retries safe connect-phase relay failures within its existing bound.

Fixes #1276
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4c4388d6-fd4b-41c8-97e9-2c390f46673d

📥 Commits

Reviewing files that changed from the base of the PR and between 58fb054 and d1d8ce2.

📒 Files selected for processing (4)
  • app/src/main/java/dev/ipf/whitenoise/android/notifications/NotificationReplyWorker.kt
  • app/src/main/java/dev/ipf/whitenoise/android/state/AppState.kt
  • app/src/test/java/dev/ipf/whitenoise/android/notifications/NotificationTargetTest.kt
  • app/src/test/java/dev/ipf/whitenoise/android/state/TransientRelaySendErrorTest.kt
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pip/whitenoise-android-1276

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.

@stage-review

stage-review Bot commented Jul 14, 2026

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 4 individual chapters for you:

Title
1 Define notification reply send outcomes
2 Update AppState to return typed outcomes
3 Integrate typed outcomes into NotificationReplyWorker
4 Verify worker retry and result logic
Open in Stage

Chapters generated by Stage for commit d1d8ce2 on Jul 14, 2026 6:11pm UTC.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

Preview APK for PR #1378

Home-screen label: 1378 White Noise with the blueprint launcher icon — installs side-by-side with the production and staging apps.

Install directly — one tap, no GitHub sign-in (public, content-addressed .apk). ARM64 only.

Every push to this PR rebuilds and updates this comment.

@agent-p1p agent-p1p left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pip adversarial review for #1276 at 85d7b0d6.

BLOCKING:

  • none

SUGGESTION:

  • app/src/main/java/dev/ipf/whitenoise/android/state/AppState.kt:288-304PERMANENT_FAILURE is broader than its name: the classifier intentionally puts both truly permanent errors and retry-unsafe/ambiguous failures into this bucket. For example, MarmotKitException.StorageBusy is typed as transient by the FFI but can surface after publication during local projection/persistence, where an automatic resend could duplicate the message. The current fail-fast behavior is correct; renaming this outcome to NON_RETRYABLE_FAILURE or FAIL_FAST would encode the actual invariant and discourage unsafe broadening later.
  • app/src/main/java/dev/ipf/whitenoise/android/notifications/NotificationReplyWorker.kt:64-79 — focused tests cover the pure retry predicate, but not the doWork() outcome-to-Result wiring. A worker-level test for SENT, permanent/non-retryable, and transient outcomes would guard the cross-layer mapping this issue adds. Non-blocking because the mapping is small and the existing test style uses pure seams.

NITPICK:

  • none

SUMMARY: The typed outcome fixes the Boolean collapse. Cancellation still propagates, permanent and retry-unsafe failures fail immediately, and only the existing narrow connect-phase classifier enters the bounded three-attempt WorkManager retry path. The raw notification send does not pass through the foreground controller retry loop, so there is no double retry. Focused verification passed 43/43 tests; all GitHub checks are green. No sensitive paths were touched.

VERDICT: APPROVE
SENSITIVE_PATHS: none

Rename the broad fail-fast outcome to reflect its non-retryable invariant and test the worker's exact success, retry, and failure mapping.

Fixes #1276
@agent-p1p

Copy link
Copy Markdown
Contributor Author

Addressed both adversarial-review suggestions in d1d8ce2: renamed the fail-fast bucket to NON_RETRYABLE_FAILURE and added direct worker result-mapping coverage for sent, non-retryable, retryable, and exhausted-retry outcomes. Local full gates and fresh GitHub CI pass.

@agent-p1p

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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.

NotificationReplyWorker cannot distinguish permanent from transient send failures

1 participant