Skip to content

fix(session-monitor): stop unmonitoring seasons other users still need#1186

Merged
jamcalli merged 1 commit into
developfrom
fix/progressive-cleanup-multi-user-safety
May 25, 2026
Merged

fix(session-monitor): stop unmonitoring seasons other users still need#1186
jamcalli merged 1 commit into
developfrom
fix/progressive-cleanup-multi-user-safety

Conversation

@jamcalli
Copy link
Copy Markdown
Owner

@jamcalli jamcalli commented May 24, 2026

Description

Related Issues

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Performance improvement
  • Code refactoring
  • Documentation update
  • Dependency update

Testing Performed

Screenshots

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • My changes work with existing functionality

Summary by CodeRabbit

  • Bug Fixes

    • Playback notifications with transient "buffering" are normalized to "playing" so downstream events never report buffering.
  • Improvements

    • Smarter multi-user progressive cleanup: skips redundant work when a session hasn't progressed, respects other users' watched positions, gates cleanup to enabled/allowed cases, and adds safer Season‑1 pilot‑reset handling and expanded debug context.
  • Tests

    • New integration and unit tests covering progressive‑cleanup workflows and playback‑notification normalization.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 24, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 6959dd84-d91c-46bf-b620-8ff55ccca7c3

📥 Commits

Reviewing files that changed from the base of the PR and between 3c51f11 and 2bde318.

📒 Files selected for processing (6)
  • src/services/plex-server/sse/plex-event-source.ts
  • src/services/plex-session-monitor.service.ts
  • src/services/plex-session-monitor/cleanup-predicates.ts
  • test/integration/services/plex-session-monitor/progressive-cleanup-workflow.test.ts
  • test/unit/services/plex-server/sse/plex-event-source.test.ts
  • test/unit/services/plex-session-monitor/cleanup-predicates.test.ts

Walkthrough

Adds season-eligibility predicates and integrates them into Plex session monitoring to gate progressive cleanup; normalizes Plex SSE playing notifications by rewriting buffering to playing; and adds unit and integration tests validating multi-user cleanup safety and gating.

Changes

Progressive Cleanup & Buffering Normalization

Layer / File(s) Summary
Cleanup Eligibility Predicates
src/services/plex-session-monitor/cleanup-predicates.ts, test/unit/services/plex-session-monitor/cleanup-predicates.test.ts
New module exports userNeedsSeason and collectSeasonsEligibleForCleanup to determine which seasons must be retained based on each user's last_watched_season as a high-water mark. Tests cover season protection rules, multi-user scenarios, monitoring-type-specific boundaries, and pilotRolling S1 reset semantics.
SSE Buffering State Normalization
src/services/plex-server/sse/plex-event-source.ts, test/unit/services/plex-server/sse/plex-event-source.test.ts
Adds normalizePlayingNotification helper to rewrite Plex PlaySessionStateNotification from state: 'buffering' to state: 'playing'. Integrates normalization into both handlePlaying and notification-container dispatch paths. Unit tests verify state rewriting, field preservation, immutability, and passthrough behavior.
Session Monitor Gating & Integration
src/services/plex-session-monitor.service.ts
Imports cleanup predicates and adds rolling-monitor progress detection to skip expansion/cleanup when playback position is unchanged. Refines updateRollingShowProgress to read prior season and gate cleanup execution on season advancement. Wires imported predicate functions into cleanup orchestration and S1 pilot safety checks; updates progressive-cleanup logging context.
Progressive Cleanup Workflow Tests
test/integration/services/plex-session-monitor/progressive-cleanup-workflow.test.ts
End-to-end integration test suite validating multi-user cleanup safety across three monitoring types, season/episode protection when other users are active, cleanup progression at inactivity thresholds, pilot reset safety, and cleanup gating to prevent redundant execution without progress.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • jamcalli/Pulsarr#269: Related progressive auto-cleanup work touching plex-session-monitor.service.ts.
  • jamcalli/Pulsarr#1052: Related changes to Plex SSE playback handling and normalization in the same plex-event-source area.
  • jamcalli/Pulsarr#1012: Overlapping edits to progressive cleanup and season-eligibility logic in session monitoring.

Suggested labels

fix

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: preventing the session monitor from unmonitoring seasons that other users still need, which aligns with the multi-user safety enhancements throughout the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 fix/progressive-cleanup-multi-user-safety

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/unit/services/plex-session-monitor/cleanup-predicates.test.ts`:
- Around line 80-82: The test title is misleading: update the spec name for the
test in cleanup-predicates.test.ts so it matches the assertion for
collectSeasonsEligibleForCleanup(2, 5, []); change the description from "returns
empty when there are no active users" to something like "returns all seasons in
range when there are no active users" so the test name accurately reflects that
it expects [2, 3, 4].
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: f9454809-be2d-4acd-a348-aa04c720e166

📥 Commits

Reviewing files that changed from the base of the PR and between c08ed60 and 56a7811.

📒 Files selected for processing (6)
  • src/services/plex-server/sse/plex-event-source.ts
  • src/services/plex-session-monitor.service.ts
  • src/services/plex-session-monitor/cleanup-predicates.ts
  • test/integration/services/plex-session-monitor/progressive-cleanup-workflow.test.ts
  • test/unit/services/plex-server/sse/plex-event-source.test.ts
  • test/unit/services/plex-session-monitor/cleanup-predicates.test.ts

Comment thread test/unit/services/plex-session-monitor/cleanup-predicates.test.ts Outdated
@jamcalli jamcalli force-pushed the fix/progressive-cleanup-multi-user-safety branch from 56a7811 to ee3cf8e Compare May 24, 2026 07:44
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
test/unit/services/plex-session-monitor/cleanup-predicates.test.ts (1)

9-12: ⚡ Quick win

Allow nullable last_watched_season in makeUser overrides.

The helper currently forces number, which requires an unsafe cast at Line 67 (null as unknown as number). Making the override nullable keeps fixture construction type-safe.

♻️ Proposed fix
 function makeUser(
   overrides: Partial<RollingMonitoredShow> & {
     plex_username: string
-    last_watched_season: number
+    last_watched_season: number | null
   },
 ): RollingMonitoredShow {
@@
   it('treats null last_watched_season as 0 - fresh entry protects S1', () => {
     const user = makeUser({
       plex_username: 'a',
-      last_watched_season: null as unknown as number,
+      last_watched_season: null,
     })

Also applies to: 64-68

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/unit/services/plex-session-monitor/cleanup-predicates.test.ts` around
lines 9 - 12, The overrides type for the test helper forces last_watched_season
to be a non-null number, causing unsafe casts in makeUser; change the overrides
definition to allow last_watched_season to be number | null (i.e.,
Partial<RollingMonitoredShow> & { plex_username: string; last_watched_season?:
number | null }) so makeUser and related fixtures can accept null without
casting; update any call sites (e.g., the test at Lines ~64-68) if they rely on
the previous non-null type to pass a nullable value or omit the field.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@test/integration/services/plex-session-monitor/progressive-cleanup-workflow.test.ts`:
- Around line 265-271: The current assertions using expect(...).toContain(...)
only check that specific seasons were touched but allow extra removals; update
the tests around mockUpdateSeasonMonitoring to assert the exact set of
unmonitored seasons/files instead of subset checks: collect the
unmonitoredSeasons from mockUpdateSeasonMonitoring.mock.calls (as done) then
assert equality to the exact expected array (e.g.,
expect(unmonitoredSeasons.sort()).toEqual([2,3]) or equivalent) so the test
fails if any extra seasons are removed; apply the same change to the other two
occurrences that mirror this pattern.
- Around line 58-71: The test currently relies on a hardcoded sessionKey and
uses subset assertions which can miss extra/unexpected deletions; update the
setup so the in-memory SessionTracker/sessionKey is not treated as affecting
monitorSessions() (remove or stop asserting based on session.sessionKey or
ensure SessionTracker is cleared) and change all subset checks (toContain /
not.toContain) that verify unmonitored seasons and deleted file IDs into exact
set assertions by comparing sorted arrays with toEqual, thereby asserting
precise expected sets; when modifying, look for references to monitorSessions(),
processSession(), handlePlayingEvent(), and SessionTracker in the test to locate
and adjust the assertions and any sessionKey usage.

---

Nitpick comments:
In `@test/unit/services/plex-session-monitor/cleanup-predicates.test.ts`:
- Around line 9-12: The overrides type for the test helper forces
last_watched_season to be a non-null number, causing unsafe casts in makeUser;
change the overrides definition to allow last_watched_season to be number | null
(i.e., Partial<RollingMonitoredShow> & { plex_username: string;
last_watched_season?: number | null }) so makeUser and related fixtures can
accept null without casting; update any call sites (e.g., the test at Lines
~64-68) if they rely on the previous non-null type to pass a nullable value or
omit the field.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 7aacee50-6f35-4624-a1f4-d5cfd1c27815

📥 Commits

Reviewing files that changed from the base of the PR and between 56a7811 and ee3cf8e.

📒 Files selected for processing (6)
  • src/services/plex-server/sse/plex-event-source.ts
  • src/services/plex-session-monitor.service.ts
  • src/services/plex-session-monitor/cleanup-predicates.ts
  • test/integration/services/plex-session-monitor/progressive-cleanup-workflow.test.ts
  • test/unit/services/plex-server/sse/plex-event-source.test.ts
  • test/unit/services/plex-session-monitor/cleanup-predicates.test.ts

@jamcalli jamcalli force-pushed the fix/progressive-cleanup-multi-user-safety branch from ee3cf8e to 02f7865 Compare May 24, 2026 08:09
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/plex-session-monitor.service.ts`:
- Around line 262-266: The early return when positionUnchanged (computed from
rollingShow.last_watched_season, rollingShow.last_watched_episode,
currentSeason, currentEpisode) prevents retrying pilot-expansion logic for
repeated SxE1 events; change the guard so we only return early if the position
is unchanged AND it is not a season pilot retry candidate—i.e., allow continued
processing when currentEpisode === 1 and rollingShow.allSeasonPilotRolling (or
other pilot-expansion flag) is set so the pilot/all-season-pilot expansion
branches still run on repeated E01 events; leave the original unchanged-return
behavior for all other episodes/conditions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 1cd76cfc-0b7e-41dc-8b2c-bab1398239d0

📥 Commits

Reviewing files that changed from the base of the PR and between ee3cf8e and 02f7865.

📒 Files selected for processing (6)
  • src/services/plex-server/sse/plex-event-source.ts
  • src/services/plex-session-monitor.service.ts
  • src/services/plex-session-monitor/cleanup-predicates.ts
  • test/integration/services/plex-session-monitor/progressive-cleanup-workflow.test.ts
  • test/unit/services/plex-server/sse/plex-event-source.test.ts
  • test/unit/services/plex-session-monitor/cleanup-predicates.test.ts

Comment thread src/services/plex-session-monitor.service.ts
@jamcalli jamcalli force-pushed the fix/progressive-cleanup-multi-user-safety branch from 02f7865 to 3c51f11 Compare May 24, 2026 08:27
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@test/integration/services/plex-session-monitor/progressive-cleanup-workflow.test.ts`:
- Around line 166-170: The test currently sorts season numbers using
Array.prototype.sort() which performs lexicographic ordering; update the sort
calls that operate on unmonitoredSeasons (and any similar arrays produced from
mockUpdateSeasonMonitoring.mock.calls) to use a numeric comparator sort((a, b)
=> a - b). Locate occurrences where unmonitoredSeasons is created via
mockUpdateSeasonMonitoring.mock.calls (the sites around the checks in
progressive-cleanup-workflow.test.ts) and replace .sort() with .sort((a, b) => a
- b) at each listed call site.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 5a7dfb73-52ad-4790-9458-42b9ef7e7024

📥 Commits

Reviewing files that changed from the base of the PR and between 02f7865 and 3c51f11.

📒 Files selected for processing (6)
  • src/services/plex-server/sse/plex-event-source.ts
  • src/services/plex-session-monitor.service.ts
  • src/services/plex-session-monitor/cleanup-predicates.ts
  • test/integration/services/plex-session-monitor/progressive-cleanup-workflow.test.ts
  • test/unit/services/plex-server/sse/plex-event-source.test.ts
  • test/unit/services/plex-session-monitor/cleanup-predicates.test.ts

@jamcalli jamcalli force-pushed the fix/progressive-cleanup-multi-user-safety branch from 3c51f11 to 2bde318 Compare May 25, 2026 01:22
@jamcalli jamcalli merged commit 4ecc01c into develop May 25, 2026
4 checks passed
@jamcalli jamcalli deleted the fix/progressive-cleanup-multi-user-safety branch May 25, 2026 06:11
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