Skip to content

fix(amplitude-session) + feat: prerelease channels - recover lastEventTime & implement branch-specific releases#1198

Open
abueide wants to merge 8 commits intomasterfrom
fix/ios-zero-second-sessions
Open

fix(amplitude-session) + feat: prerelease channels - recover lastEventTime & implement branch-specific releases#1198
abueide wants to merge 8 commits intomasterfrom
fix/ios-zero-second-sessions

Conversation

@abueide
Copy link
Copy Markdown
Contributor

@abueide abueide commented Apr 7, 2026

Summary

This PR includes two sets of changes:

  1. Fix 0-second sessions in Amplitude Session plugin on iOS when Background Fetch is enabled
  2. Implement branch-specific prerelease channels for better semantic versioning

Part 1: Amplitude Session Fix

Changes

  • Add recovery logic in startNewSessionIfNecessary() for partial AsyncStorage persistence
  • Recover lastEventTime from sessionId when lastEventTime === -1 but sessionId >= 0
  • Remove lastEventTime === -1 from isSessionExpired check (now handled by recovery)
  • Remove incorrect 1-second timestamp guard from onForeground()
  • Add 8 hypothesis-driven tests for 0-second session reproduction

Why

Plugin persists sessionId and lastEventTime via independent fire-and-forget writes. If app is killed before all writes complete (common during iOS Background Fetch), sessionId may persist while lastEventTime doesn't. On next launch, lastEventTime === -1 with valid sessionId falsely triggers session expiration, ending the just-created session immediately.


Part 2: Branch-Specific Prerelease Channels

Changes

1. Updated release.config.js:

branches: [
  'master',
  { name: '+([0-9])?(.{+([0-9]),x}).x', prerelease: true },
  { name: 'beta', prerelease: 'beta' },      // explicit beta channel
  { name: 'fix/*', prerelease: 'fix' },      // bug fixes → x.x.x-fix.N
  { name: 'feat/*', prerelease: 'feat' },    // features → x.x.x-feat.N
]

Before: All non-master branches published as x.x.x-beta.N
After: Each branch type gets its own channel and dist-tag

Examples:

  • fix/ios-zero-second-sessions2.22.1-fix.1 (dist-tag: fix)
  • feat/new-analytics2.22.1-feat.1 (dist-tag: feat)
  • beta2.22.1-beta.1 (dist-tag: beta)

2. GitHub Environment:

  • Created new Publish-Prerelease environment
  • Updated workflow to use Publish-Prerelease instead of Publish-Beta

3. Workflow Input Clarity:

Renamed workflow input from beta to prerelease:

inputs:
  type:
    options:
      - dry-run
      - prerelease    # was: beta
      - production

4. Documentation:

Added PRERELEASE_SETUP.md with complete setup and troubleshooting guide.

Benefits

  1. Semantic Clarity: x.x.x-fix.1 is clearer than x.x.x-beta.1 for a bug fix
  2. Multiple Channels: Can distribute fixes and features independently
  3. Better Client Experience: Clients can install specific channels:
    npm install @segment/analytics-react-native@fix
    npm install @segment/analytics-react-native@feat
  4. No Breaking Changes: Existing beta channel still works

Testing

After merge, the workflow will show the new prerelease option. To test:

# Dry run
gh workflow run release.yml -f type=dry-run --ref fix/your-branch

# Publish
gh workflow run release.yml -f type=prerelease --ref fix/your-branch

No npm-side setup needed - we already use npm OIDC with provenance.


🤖 Generated with Claude Code

@abueide abueide changed the title fix(amplitude-session): prevent 0-second sessions from iOS Background Fetch fix(amplitude-session): recover lastEventTime on partial persist Apr 7, 2026
@abueide abueide added bug Bug fix review-needed needs-review Ready for review and removed review-needed labels Apr 9, 2026
@abueide abueide self-assigned this Apr 13, 2026
@abueide abueide force-pushed the fix/ios-zero-second-sessions branch from 6872c0c to 41a5d02 Compare April 15, 2026 19:41
abueide and others added 3 commits April 15, 2026 15:07
… Fetch

iOS Background Fetch can briefly trigger AppState 'active' without user
interaction, causing rapid session creation/destruction cycles. Add a
1-second timestamp guard in onForeground() to prevent new sessions from
starting within 1 second of the last session creation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace incorrect 1-second timestamp guard with proper root cause fix.

The 0-second session bug is caused by non-atomic AsyncStorage persistence:
when the app is killed (e.g. during iOS Background Fetch), sessionId may
persist while lastEventTime does not. On relaunch, lastEventTime === -1
with a valid sessionId falsely triggers session expiration, ending the
just-created session immediately.

The fix recovers lastEventTime from sessionId when partial persistence
is detected, preventing the false expiration. Also adds hypothesis-driven
reproduction tests that verify the fix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix CI formatting check failures.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
abueide and others added 4 commits April 15, 2026 21:43
Changed from a single "beta" prerelease channel to branch-specific
channels:
- fix/* → x.x.x-fix.N
- feat/* → x.x.x-feat.N
- chore/* → x.x.x-chore.N
- beta → x.x.x-beta.N (explicit)

This provides better semantic meaning for prerelease versions. Instead
of all non-master branches being "beta", each category gets its own
channel.

Examples:
- fix/ios-zero-second-sessions → 2.22.1-fix.1
- feat/new-feature → 2.22.1-feat.1
- beta → 2.22.1-beta.1

Updated workflow to use new "Publish-Prerelease" environment instead
of "Publish-Beta" to reflect the broader scope.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added comprehensive documentation for the new branch-specific prerelease
system including:
- GitHub environment setup instructions
- npm token vs OIDC setup options
- Testing and verification steps
- Troubleshooting guide
- Migration notes from old beta setup

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Removed chore/* branches from prerelease channels since they're for
internal changes not meant for client distribution. Only fix/* and
feat/* branches (plus explicit beta) will publish now.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed the workflow input from 'beta' to 'prerelease' to avoid
confusion. The input triggers prerelease publishing for any prerelease
channel (fix, feat, or beta), not just the beta channel.

Now you select:
- dry-run → test without publishing
- prerelease → publish fix/feat/beta channels
- production → production release from main

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@abueide abueide changed the title fix(amplitude-session): recover lastEventTime on partial persist fix(amplitude-session) + feat: prerelease channels - recover lastEventTime & implement branch-specific releases Apr 16, 2026
@abueide abueide deployed to Publish-Prerelease April 16, 2026 03:12 — with GitHub Actions Active
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Bug fix needs-review Ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant