feat(infer): messages starting with "other:" are not monthly fees

When the bank message starts with "other:" (case-insensitive),
inference does not look for a month, neither in the text nor from the
payment date. The trimmed message is written to Purpose, so reconcile
books the payment as an "other" transaction for the person instead of
a monthly fee. Messages containing "other:" elsewhere are unchanged.

- matching.IsOtherPurpose / is_other_purpose shared by inference and
  reconcile
- reconcile applies the rule to rows not yet processed by inference
- no person found: Purpose is still written, row shows as unmatched
- implemented in Go and legacy Python; four new parity fixtures

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 12:37:03 +02:00
co-authored by Claude Opus 5.5
parent 294c40fa42
commit bbad19d822
15 changed files with 567 additions and 10 deletions
+9
View File
@@ -1,5 +1,14 @@
# Changelog
## 2026-10-08 12:37 CEST — feat(infer): messages starting with "other:" are not monthly fees
- When the bank message starts with `other:` (case-insensitive), inference no longer looks for a month. It copies the trimmed message into Purpose, so the payment is linked to the person as an "other" transaction and not counted as a monthly fee. Messages that contain `other:` elsewhere are inferred as before.
- If no person is found, Purpose is still written and the row shows under unmatched for a manual fix.
- Reconcile applies the same rule to rows not yet processed by inference.
- Existing rows are not re-inferred; clear Person and Purpose on a row to reprocess it.
- Go and Python: `matching.IsOtherPurpose` / `is_other_purpose`, `InferTransactionDetails` / `infer_transaction_details`, reconcile fallback; four new parity fixtures.
- Also fixed (Go): junior cell tooltip showed `Expected: 0` instead of `Expected: ?` when a month with unknown expected fee had a payment.
## 2026-10-08 12:16 CEST — feat(go): scheduled bank sync (Go only)
- The Go server now runs the bank sync (sync → infer → flush cache) by itself at the times in `SYNC_SCHEDULE` (comma-separated `HH:MM`, default `04:00`, `off` disables), read in `SYNC_TZ` (default `Europe/Prague`). Nothing runs at startup; an invalid value stops the server at startup with an error.