The apply flow resolves matching transaction IDs into a snapshot cached
for up to 15 minutes and keyed only by rule.updated_at. Both the sync
path and ApplySingleAutomationRuleJob then applied the rule's category to
every id in that snapshot without re-checking eligibility.
A transaction categorized after the snapshot was taken (by the user, a
sibling rule, or a concurrent AI backfill) was therefore silently
re-categorized to the rule's target and stamped category_source=Rule,
reverting a choice the user never asked the rule to touch.
Re-filter the set through shouldSkipForOnlyUncategorized() inside
applyRuleActionsToTransactions() when only_uncategorized was requested,
threading the flag through the job constructor. Skipped transactions are
no longer counted as changed.