From ef6a231d986c33d2d8595f2d5ab53677bad72350 Mon Sep 17 00:00:00 2001 From: Nikola Petrov Date: Tue, 11 Aug 2026 23:39:17 +0200 Subject: [PATCH] Correct the docs against the code Four removals in a row left both files describing things that are no longer there, and one claim that was never true: - The rules screen mock-up still had the transfer column, two commits after that column went. The keys table listed 4 twice, once as a view switch and once as the tagging row that replaced t; tagging is now a sentence saying plainly that no key does it and why 4 is the answer. - The rule builder mock-up was missing the account field entirely while the prose below it described moving between four fields. - glob was described as linear time with no backtracking. It is the two-pointer wildcard match, which backtracks by design -- the branch is right there in glob.go -- and is O(n*m) in the worst case. What it actually rules out is exponential blowup on patterns like *a*a*a*. - r on the rules screen was undocumented. It recounts against the index, which is what an import makes stale; it does not re-read rules.toml, so an edit made elsewhere still needs a restart. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 2 +- README.md | 32 ++++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 3bf4fb0..14dcc75 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ This file covers what the code assumes and why. cmd/money/main.go subcommands; the TUI is the default internal/config rules.toml, account.toml, XDG config, data-root resolution internal/model Account, Transaction, amount formatting, description normalisation -internal/glob the `*` / `?` matcher used by rules (linear time, no backtracking) +internal/glob the `*` / `?` matcher used by rules (two-pointer, no exponential blowup) internal/parser Parser interface + registry; nlb, revolut, traderepublic internal/store SQLite index (modernc.org/sqlite, no cgo) internal/importer directory walk, dedupe, balance checks diff --git a/README.md b/README.md index ee5889a..2c4c994 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ tagged by glob rules you write. rules.toml # tag rules, in order index.db # SQLite index (rebuildable; safe to delete*) checking/ - account.toml # currency + how to parse this bank's exports + account.toml # currency + which parser reads this bank's exports 2026-01.csv 2026-02.csv savings/ @@ -63,7 +63,7 @@ money # open the TUI (default) money import # extract new transactions from every statement money import --force # re-parse statements even if unchanged money retag # re-apply rules.toml to everything already imported -money ls --untagged # what still needs a tag +money ls --untagged # what no rule has claimed yet money ls --wide # also show type and reported balance money ls --account checking --month 2026-01 money report --month 2026-01 # spending by tag @@ -82,12 +82,15 @@ imported — creating an `account.toml` is not enough on its own. Run | --- | --- | | `1` `2` `3` `4` `5` / `tab` | accounts · transactions · report · rule builder · rules | | `enter` | open the selected account (accounts view) | -| `4` | write a rule for what you are looking at — the only way to tag | | `/` | filter by description | | `u` | show only untagged transactions | | `a` | clear the account filter | | `i` | import · `r` re-apply rules · `q` quit | +There is no key that tags a transaction. Tags come from `rules.toml` and +nowhere else, so tagging what you are looking at means writing a rule for it on +`4` — which is why that screen shows you what a glob catches before you save. + ### Rule builder (`4`) Writing rules by hand means guessing what a glob will catch. This screen shows @@ -103,6 +106,12 @@ a `▸` against each one the glob currently matches and a running ╰────────────────────────────╯ ▸ LIDL SOFIA 4412 2 vs. the description ▸ LIDL VARNA 9911 1 ZARA MLADOST 1 + account +╭────────────────────────────╮ +│ blank = every account │ +╰────────────────────────────╯ + blank = all accounts + ▸ tag ╭────────────────────────────╮ │ groceries │ @@ -148,12 +157,12 @@ Rules that claim none are marked `✗`. ``` money · rules · 5 rules · 2 match nothing -# Pattern Account Tag T Txns Note -1 *LIDL* (all) groceries 3 the weekly shop -2 ✗ *LIDL SOFIA* (all) shadowed 0 -3 ✗ *OLD BANK NAME* (all) dead 0 closed in 2025 -4 *ZARA* (all) clothes 1 -5 *КАУФЛАНД* checking groceries 1 4412 is the branch +# Pattern Account Tag Txns Note +1 *LIDL* (all) groceries 3 the weekly shop +2 ✗ *LIDL SOFIA* (all) shadowed 0 +3 ✗ *OLD BANK NAME* (all) dead 0 closed in 2025 +4 *ZARA* (all) clothes 1 +5 *КАУФЛАНД* checking groceries 1 4412 is the branch ``` The count is how many transactions the rule *wins*, not how many its glob could @@ -163,7 +172,10 @@ 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 +both ask for a `y` first. `r` recounts against what is currently in the index, +which is what you want after an import has added rows; `rules.toml` itself is +read at startup and whenever you save a rule from the builder, so an edit made +in another window needs a restart. 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.