New go/internal/domain/matching package porting three tightly coupled helpers from scripts/match_payments.py.
BuildNameVariants — extracts normalized ASCII search variants (full name, nickname, last/first); filters variants <3 chars; variants[0] is always the full base (load-bearing invariant for MatchMembers).
MatchMembers — auto/review confidence matching with an exact-name short-circuit that prevents nickname substrings (e.g. tov) from firing inside longer surnames (e.g. ottova); common-surname filter for the review tier (novak, novakova, prach).
FormatDate — nil/empty/serial int/float64 (since 1899-12-30, fractional days supported)/YYYY-MM-DD passthrough/garbage → never errors. Fractional serials computed via time.Duration to preserve Python timedelta(days=float) sub-day precision.
InferTransactionDetails — composes name + month matching over sender/message/user_id; falls back to sender-only member match and date-derived month when text carries no signal. SearchText key matches what the Python code actually returns (not the misleading matched_text docstring).
21 table-driven tests; all expected values verified against live Python on 2026-05-06. go-build, go-test, go-lint all clean.
Done together per plan since the three functions form a tight dependency chain: InferTransactionDetails → MatchMembers → BuildNameVariants + FormatDate.
Ticks M2.7, M2.8, M2.9 in the progress tracker. Next up: M2.10 domain/reconcile.Reconcile.
## Summary
- New `go/internal/domain/matching` package porting three tightly coupled helpers from `scripts/match_payments.py`.
- **`BuildNameVariants`** — extracts normalized ASCII search variants (full name, nickname, last/first); filters variants <3 chars; `variants[0]` is always the full base (load-bearing invariant for `MatchMembers`).
- **`MatchMembers`** — auto/review confidence matching with an exact-name short-circuit that prevents nickname substrings (e.g. `tov`) from firing inside longer surnames (e.g. `ottova`); common-surname filter for the review tier (`novak`, `novakova`, `prach`).
- **`FormatDate`** — nil/empty/serial int/float64 (since 1899-12-30, fractional days supported)/YYYY-MM-DD passthrough/garbage → never errors. Fractional serials computed via `time.Duration` to preserve Python `timedelta(days=float)` sub-day precision.
- **`InferTransactionDetails`** — composes name + month matching over sender/message/user_id; falls back to sender-only member match and date-derived month when text carries no signal. `SearchText` key matches what the Python code actually returns (not the misleading `matched_text` docstring).
- 21 table-driven tests; all expected values verified against live Python on 2026-05-06. `go-build`, `go-test`, `go-lint` all clean.
Done together per plan since the three functions form a tight dependency chain: `InferTransactionDetails` → `MatchMembers` → `BuildNameVariants` + `FormatDate`.
Ticks M2.7, M2.8, M2.9 in the progress tracker. Next up: M2.10 `domain/reconcile.Reconcile`.
New go/internal/domain/matching package porting three helpers from
scripts/match_payments.py:
- BuildNameVariants: normalized ASCII variants from a member name (nickname
in parens, last/first split, len<3 filtered); variants[0] is always the
full base name — MatchMembers relies on this invariant.
- MatchMembers: auto/review confidence matching with an exact-name
short-circuit pass that prevents nickname substrings (tov) from firing
inside longer surnames (ottova); common-surname filter for review tier.
- FormatDate: nil/empty/""/serial int/float64 (since 1899-12-30, fractional
days supported)/YYYY-MM-DD passthrough/garbage → never errors.
- InferTransactionDetails: composes BuildNameVariants+MatchMembers+
ParseMonthReferences; falls back to sender-only member match and
date-derived month when text carries no signal.
21 table-driven tests; all expected values verified against live Python
on 2026-05-06. go-build, go-test, go-lint all clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
go/internal/domain/matchingpackage porting three tightly coupled helpers fromscripts/match_payments.py.BuildNameVariants— extracts normalized ASCII search variants (full name, nickname, last/first); filters variants <3 chars;variants[0]is always the full base (load-bearing invariant forMatchMembers).MatchMembers— auto/review confidence matching with an exact-name short-circuit that prevents nickname substrings (e.g.tov) from firing inside longer surnames (e.g.ottova); common-surname filter for the review tier (novak,novakova,prach).FormatDate— nil/empty/serial int/float64 (since 1899-12-30, fractional days supported)/YYYY-MM-DD passthrough/garbage → never errors. Fractional serials computed viatime.Durationto preserve Pythontimedelta(days=float)sub-day precision.InferTransactionDetails— composes name + month matching over sender/message/user_id; falls back to sender-only member match and date-derived month when text carries no signal.SearchTextkey matches what the Python code actually returns (not the misleadingmatched_textdocstring).go-build,go-test,go-lintall clean.Done together per plan since the three functions form a tight dependency chain:
InferTransactionDetails→MatchMembers→BuildNameVariants+FormatDate.Ticks M2.7, M2.8, M2.9 in the progress tracker. Next up: M2.10
domain/reconcile.Reconcile.