Add a rules screen that finds and removes dead rules

Nothing showed whether a rule was still earning its place. The new screen, on
5, lists every rule in file order with the number of transactions it claims,
marking those that claim none.

The count comes from Engine.Usage, which counts by first match, so a rule
shadowed by an earlier one reports zero even though its glob matches. That is
the case worth catching: such a rule looks correct in isolation and can never
fire.

d removes the selected rule and p removes every unused one, each behind a y/n
confirmation since this rewrites a hand-maintained file. config.DeleteRules
edits rules.toml textually rather than re-serialising the parsed rules, so
comments and layout survive; a comment directly above a rule goes with it,
while one separated by a blank line is left as a heading. The result is
re-parsed before it replaces the file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-09 02:02:01 +02:00
co-authored by Claude Opus 5
parent aeca203855
commit c2eba53fd4
8 changed files with 831 additions and 9 deletions
+29 -1
View File
@@ -69,7 +69,7 @@ imported — creating an `account.toml` is not enough on its own. Run
| Key | Action |
| --- | --- |
| `1` `2` `3` `4` / `tab` | accounts · transactions · report · rule builder |
| `1` `2` `3` `4` `5` / `tab` | accounts · transactions · report · rule builder · rules |
| `enter` | open the selected account (accounts view) |
| `t` | set the tag on the selected transaction |
| `x` | toggle transfer on the selected transaction |
@@ -106,6 +106,34 @@ narrows the preview to that account. Rules are appended, so anything already in
`rules.toml` keeps precedence — the preview accounts for that automatically,
since it only ever lists transactions no existing rule has already tagged.
### Rules (`5`)
Every rule in file order, with the number of transactions it actually claims.
Rules that claim none are marked `✗`.
```
money · rules · 5 rules · 2 match nothing
# Pattern Account Tag T Txns
1 *LIDL* (all) groceries 3
2 ✗ *LIDL SOFIA* (all) shadowed 0
3 ✗ *OLD BANK NAME* (all) dead 0
4 *ZARA* (all) clothes 1
5 *КАУФЛАНД* checking groceries 1
```
The count is how many transactions the rule *wins*, not how many its glob could
match. Rule 2 above matches `LIDL SOFIA 4412` perfectly well, but rule 1 claims
it first, so rule 2 is dead weight — which is the point of the screen. A rule
can therefore reach zero either by matching nothing or by being shadowed, and
both are worth deleting.
`d` deletes the selected rule, `p` deletes every rule marked `✗` at once, and
both ask for a `y` first. Deleting edits `rules.toml` textually, so your
comments, ordering and formatting survive; a comment sitting directly above a
deleted rule goes with it, while one separated by a blank line is treated as a
section heading and left alone.
## rules.toml
Rules are evaluated in file order and the **first match wins**, so put transfer