Problem
Automation conditions can reason about a torrent's group membership (GROUP_SIZE, IS_GROUPED, scoped per-condition via groupId), but tag conditions only see the torrent's own tags (FieldTags in internal/services/automations/evaluator.go). There is no way to express "any member of this torrent's group already carries tag X."
This matters for cross-seed workflows: state applied to one copy of a release (e.g. a processed/archived tag) is invisible to its group-mates. When the cross-seed engine later adds a new copy of that same release, the new torrent has no tags of its own, re-qualifies for the same rules, and gets re-processed — per-torrent tag state can never converge at the release level.
Proposal
New condition field GROUP_HAS_TAG:
- Semantics: true when any member of the torrent's resolved group (including itself) carries the given tag; supports the existing string operators where sensible (equals/contains against the member tag sets).
- Group resolution follows the existing pattern: honor the condition's
groupId, falling back to the rule's active/default group (resolveConditionGroupIndex).
- Implementation sketch: in the evaluator,
MembersForHash(hash) → look up each member in the run's torrentByHash → check tag membership. All the needed indexes already exist in the eval context; this is a small addition alongside FieldGroupSize/FieldIsGrouped (evaluator.go:517,606).
- Negation composes via the existing condition tree (
NOT GROUP_HAS_TAG = "no member of this group has been marked"), which is the primary use: run an action at most once per release group even as new members appear over time.
Example rule this unlocks
Tag torrents for archival review only when their release group hasn't been handled yet:
IS_GROUPED AND NOT GROUP_HAS_TAG("archived") → add tag review
Today the equivalent rule re-fires every time the cross-seed engine adds another copy of an already-handled release.
Notes
- Ambiguous-group safety (
verify_overlap on contentPath-keyed groups) should apply the same way it does for group-aware delete expansion, so a flat-layout false group can't leak tag state across unrelated torrents.
- Pairs naturally with group-scoped tag actions (separate issue) but is independently useful for read-only conditions.
Problem
Automation conditions can reason about a torrent's group membership (
GROUP_SIZE,IS_GROUPED, scoped per-condition viagroupId), but tag conditions only see the torrent's own tags (FieldTagsininternal/services/automations/evaluator.go). There is no way to express "any member of this torrent's group already carries tag X."This matters for cross-seed workflows: state applied to one copy of a release (e.g. a
processed/archivedtag) is invisible to its group-mates. When the cross-seed engine later adds a new copy of that same release, the new torrent has no tags of its own, re-qualifies for the same rules, and gets re-processed — per-torrent tag state can never converge at the release level.Proposal
New condition field
GROUP_HAS_TAG:groupId, falling back to the rule's active/default group (resolveConditionGroupIndex).MembersForHash(hash)→ look up each member in the run'storrentByHash→ check tag membership. All the needed indexes already exist in the eval context; this is a small addition alongsideFieldGroupSize/FieldIsGrouped(evaluator.go:517,606).NOT GROUP_HAS_TAG= "no member of this group has been marked"), which is the primary use: run an action at most once per release group even as new members appear over time.Example rule this unlocks
Today the equivalent rule re-fires every time the cross-seed engine adds another copy of an already-handled release.
Notes
verify_overlapon contentPath-keyed groups) should apply the same way it does for group-aware delete expansion, so a flat-layout false group can't leak tag state across unrelated torrents.