Flag transfers that only touch one Ledgr account - #156
Merged
Conversation
The existing pairing-based detector can only match a transfer across two of the household's own linked accounts, so a credit-card payoff to an unconnected card, a savings transfer to an unconnected bank, or a P2P payment never gets caught — it just sits in spending/income forever. Adds a single-leg pattern pass to applyTransferDetection: known card-payoff memos and named self-transfers (transfer + savings/brokerage/ira) are trusted immediately (transferSource="pattern"); bare P2P processor names (Zelle, Venmo, Cash App, PayPal) are too ambiguous to auto-exclude, so they go to a new review queue (transferSource="suggested") instead — a dashboard nudge and a confirm/reject card dialog at /transactions?mode=review-transfers. Also exposes mark_transaction_transfer over MCP, closing the gap where an assistant session had no tool to fix a misclassified transfer at all.
5 tasks
KenTaniguchi-R
added a commit
that referenced
this pull request
Sep 5, 2026
…/income (#157) Alpaca (and other Plaid-linked brokerage) fills and clearing fees were landing in the Transactions tab miscategorized as "Investment Income" and inflating spending/income totals across Transactions, Reports, Budgets, and the Dashboard. Reuses the existing isTransfer/transferSource mechanism from the transfer-detection feature (#156): any transaction on an account.type === "investment" account is deterministically tagged transferSource="investment_account" at sync time, which every spend/income aggregator already excludes via isTransfer=false. Rows still appear in the Transactions list, labeled "Investment" instead of the wrong category. A backfill job retags already-synced history (pnpm backfill-investment-activity) and, like the transfer tiers, never overwrites a manual/manual_rejected user correction.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
transferSource="pattern"); bare P2P processor names (Zelle, Venmo, Cash App, PayPal) go to a new review queue instead of auto-excluding (transferSource="suggested").TransferReviewNudge) and a confirm/reject card dialog at/transactions?mode=review-transfers, modeled on the existing categorization review dialog but purpose-built (binary confirm/reject vs. picking a category).mark_transaction_transfer— closes a gap where an assistant session had no tool available to fix a misclassified transfer at all.transferSourceis atextcolumn with a TS-level enum, so widening it is additive only (confirmed viadrizzle-kit generate— no schema diff).Test plan
pnpm typecheck— cleanpnpm lint— cleanpnpm test— 1118/1119 pass (1 pre-existing unrelatedinvestment-queriesdate-rot failure onmain)src/lib/transfer-patterns.test.ts(pattern matcher, incl. property test)tests/integration/transfer-detection.test.ts(single-leg pass: pattern/suggested/manual_rejected/idempotency/pair-preferred-over-pattern),tests/integration/transaction-detail.test.ts(confirm/reject actions + household isolation),tests/integration/transaction-queries.test.ts(getSuggestedTransfers/getSuggestedTransferCount)applyTransferDetectionagainst transactions shaped like this week's real ones — "Apple GS Savings Transfer" and "Applecard Gsbank Payment" auto-excluded immediately; "Zelle" landed in the suggested queue and correctly confirmed viaconfirmTransferSuggestionScoped; a bare personal name ("Bahar Rabiei", no processor keyword) correctly left untouched — documented as an intentional scope limit, not a bug.🤖 Generated with Claude Code