Skip to content

fix(collections): suppress rule re-add of items the handler just processed#2837

Merged
enoch85 merged 8 commits into
developmentfrom
fix/suppress-rule-readd-after-handle
May 6, 2026
Merged

fix(collections): suppress rule re-add of items the handler just processed#2837
enoch85 merged 8 commits into
developmentfrom
fix/suppress-rule-readd-after-handle

Conversation

@enoch85

@enoch85 enoch85 commented May 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

The collection handler runs an arr/Plex/Jellyfin action and removes the item from the collection. Seconds later the rule executor re-evaluates the same conditions; rule inputs like Jellyfin.isWatched and Jellyfin.lastViewedAt stay true after the action, so the item is re-added — and the user gets a Media Removed notification immediately followed by Media Added for the same title.

This adds a small per-collection RecentlyHandledMediaService that CollectionHandler.handleMedia() writes to on success and RuleExecutorService.handleCollection() consults before adding. Both code paths into the handler (the cron CollectionWorkerService and the manual POST /media/handle endpoint) feed the same set, so there is one writer, one reader, and no per-call-site bookkeeping.

The rule executor consumes the marks: it reads them while building its add list, then clears the per-collection set in the same pass. The suppression therefore blocks exactly the immediate echo — a later legitimate re-match (e.g. an unmonitored file becoming watched again months later) gets re-added normally and the user sees the expected notification cycle. Marks are also cleared on Collection_Deleted.

No upstream data is touched (Plex/Jellyfin playstate is left alone), no schema changes, no migrations.

enoch85 and others added 8 commits May 3, 2026 18:05
…essed

Track the mediaServerIds CollectionHandler.handleMedia processes per
collection in a small in-memory service. RuleExecutorService.handleCollection
consults it before computing mediaToAdd so the comparator pass that runs
seconds after the handler doesn't re-add the same item — which produced a
confusing "Media Removed" + "Media Added" notification pair for any rule
keyed on conditions (watched / lastViewedAt) that don't change after the
arr action. State clears via the existing Collection_Deleted event.
The suppression set was only cleared on Collection_Deleted, so once an
item was handled it stayed suppressed for the lifetime of the process.
For unmonitor / quality-change actions where the file remains on disk,
that meant a legitimate later re-match would never re-add the item.

Clear the per-collection set right after the rule executor consults it
so the suppression blocks exactly the immediate echo. Update JSDoc and
inline comments to match. Add a regression test that runs two passes:
the first suppresses, the second re-adds.
@enoch85 enoch85 merged commit 952f451 into development May 6, 2026
13 checks passed
@enoch85 enoch85 deleted the fix/suppress-rule-readd-after-handle branch May 6, 2026 16:48
maintainerr-automation Bot added a commit that referenced this pull request May 6, 2026
* fix(app): correct version comparison for multi-digit segments (#2838)

* fix(app): correct version comparison for multi-digit segments

Closes #2835

* refactor(app): drop regex prefix trim per AGENTS.md string-handling rule

* build(deps-dev): bump postcss from 8.5.10 to 8.5.11 (#2839)

Bumps [postcss](https://github.com/postcss/postcss) from 8.5.10 to 8.5.11.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](postcss/postcss@8.5.10...8.5.11)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.11
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump yaml from 2.8.3 to 2.8.4 (#2840)

Bumps [yaml](https://github.com/eemeli/yaml) from 2.8.3 to 2.8.4.
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](eemeli/yaml@v2.8.3...v2.8.4)

---
updated-dependencies:
- dependency-name: yaml
  dependency-version: 2.8.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @typescript-eslint/eslint-plugin (#2843)

Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.59.0 to 8.59.2.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.2/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.59.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump react-hook-form from 7.74.0 to 7.75.0 (#2844)

Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.74.0 to 7.75.0.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](react-hook-form/react-hook-form@v7.74.0...v7.75.0)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-version: 7.75.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @typescript-eslint/parser from 8.59.1 to 8.59.2 (#2845)

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.59.1 to 8.59.2.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.2/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.59.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump axios from 1.15.2 to 1.16.0 (#2842)

Bumps [axios](https://github.com/axios/axios) from 1.15.2 to 1.16.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](axios/axios@v1.15.2...v1.16.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump postcss from 8.5.13 to 8.5.14 (#2849)

Bumps [postcss](https://github.com/postcss/postcss) from 8.5.13 to 8.5.14.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](postcss/postcss@8.5.13...8.5.14)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.14
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump react-router-dom from 7.14.2 to 7.15.0 (#2847)

Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 7.14.2 to 7.15.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.15.0/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-version: 7.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(storage-metrics): deduplicate reclaimable bytes; add cleanup byte counters (#2833)

* fix(collections): suppress rule re-add of items the handler just processed (#2837)

* fix(collections): suppress rule re-add of items the handler just processed

Track the mediaServerIds CollectionHandler.handleMedia processes per
collection in a small in-memory service. RuleExecutorService.handleCollection
consults it before computing mediaToAdd so the comparator pass that runs
seconds after the handler doesn't re-add the same item — which produced a
confusing "Media Removed" + "Media Added" notification pair for any rule
keyed on conditions (watched / lastViewedAt) that don't change after the
arr action. State clears via the existing Collection_Deleted event.

* fix(collections): consume recently-handled marks each rule pass

The suppression set was only cleared on Collection_Deleted, so once an
item was handled it stayed suppressed for the lifetime of the process.
For unmonitor / quality-change actions where the file remains on disk,
that meant a legitimate later re-match would never re-add the item.

Clear the per-collection set right after the rule executor consults it
so the suppression blocks exactly the immediate echo. Update JSDoc and
inline comments to match. Add a regression test that runs two passes:
the first suppresses, the second re-adds.

---------

Co-authored-by: Kristian Matthews-Kennington <kristian@matthews-kennington.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: maintainerr-automation[bot] <261505141+maintainerr-automation[bot]@users.noreply.github.com>
Co-authored-by: enoch85 <mailto@danielhansson.nu>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kristian Matthews-Kennington <kristian@matthews-kennington.com>
@maintainerr-automation

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.10.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@enoch85 enoch85 added this to the 3.10.2 milestone May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants