* fix(rules): validate Rule::Condition type registry + normalize legacy 'name' values
Closes#1229.
/rules crashes with `ActionView::Template::Error (Unsupported condition
type: name)` when a Rule::Condition row has a condition_type the
registry doesn't know about. Reporter found two cases in the wild:
- "name" — invalid, crashes the rules index because the view path
(`_rule.html.erb` → `displayed_condition.filter.label`) ends up
in `Rule::Registry#get_filter!` which raises.
- "transaction_details" — actually a valid filter that searches the
`transactions.extra` JSONB metadata field (see existing tests in
test/models/rule/condition_test.rb). Reporter assumed it was a
transaction-name synonym; it isn't. This PR leaves it alone.
Changes:
- Rule::Condition gains a SUPPORTED_CONDITION_TYPES registry constant
matching Rule::Registry::TransactionResource#condition_filters plus
"compound", an inclusion validation against it, and a
before_validation callback that maps the one known legacy alias
("name" -> "transaction_name") so saving an existing rule fixes
itself.
- Rule::Condition#filter now rescues UnsupportedConditionError and
returns a Rule::ConditionFilter::Unsupported placeholder. The
placeholder labels itself "Unsupported (<key>)" (i18n) and its
#apply returns `scope.none`, so any stale row that survives the
migration stops matching rather than silently matching everything.
- A one-shot migration normalizes existing "name" rows. Single UPDATE
statement — rule_conditions is a small per-family table.
Tests added in test/models/rule/condition_test.rb cover the inclusion
validation, the normalization callback, and the graceful-render path
(uses update_columns to simulate a row written before the validation
existed — that's the exact codepath that crashes /rules today).
* test(rules): add system test for unsupported condition_type render + raise on migration down
- test/system/rules_test.rb: visit /rules with a row whose condition_type
has been update_columns'd to "name" — assert page renders and shows
the "Unsupported (name)" label instead of raising.
- db/migrate/...normalize_rule_condition_types.rb: replace the empty
#down with `raise ActiveRecord::IrreversibleMigration` to match the
repo's data-migration convention (see e.g. 20260219190000_scope_*).
* chore(rules): log unsupported condition + cross-check supported types
Address maintainer review on #1908:
- Log a Rails.logger.warn (with rule_id and condition_type) from
Rule::ConditionFilter::Unsupported#apply so silent zero-match rules
are traceable when debugging.
- Add a comment above Rule::Condition::SUPPORTED_CONDITION_TYPES and a
test that cross-checks it against the registry's filter keys, so
drift between the two surfaces as a failing test rather than a
confusing validation error.
* refactor(rules): derive supported condition types from registry
---------
Co-authored-by: John Baillie <johnbaillie2007@gmail.com>
Co-authored-by: Khaostica <256858950+Khaostica@users.noreply.github.com>
Co-authored-by: sure-admin <sure-admin@splashblot.com>
* Add blocked count to rule run summary
* test(rules): cover rule run blocked counts
* fix(rules): derive blocked count from modified rows
Blocked rule transactions are the processed rows that were not modified. This keeps the displayed queued / processed / modified / blocked summary aligned when a run has already processed all matching rows but some were skipped by enrichment locks.
* fix(rules): count processed rows for rule jobs
Synchronous rule actions return the number of rows they modified, but rule-run processed counts should represent the number of matched transactions the job attempted to process. Using queued matches for processed preserves the distinction between processed and modified rows, which lets locked manual edits appear as blocked instead of making processed collapse to modified.
This changes RuleJob counter semantics, so it was committed separately from the derived blocked-count display change.