## Outcome - Reviewed the clean worktree at exact base `9e08547043fbe667cb102c3d3fdae8cdef05245f`. - Read tracked source/tests/docs only; no private/runtime data accessed. - **No files created or modified.** - Focused verification: `56 passed` in `tests/unit/test_household_classification_v2_golden.py`. - Worktree remained clean; `git diff --check` passed. ## Architecture findings ### Classification taxonomy - Classification is deterministic and fail-closed, with this effective precedence: 1. Transfers/card payments/refunds 2. Explicit row-scoped user decisions 3. Bank-income semantics 4. Exact merchant/alias rules 5. Confirmed exact-merchant history 6. Public merchant families 7. Source rules 8. Recurring-payment rules 9. High-threshold similarity 10. `decision_needed` - There is **no fallback category**, which should remain invariant. - Public taxonomy resolves canonical category names only if matching active categories exist. - Ambiguous marketplaces/processors are deliberately excluded from automatic categorization. **Architecture gap:** `_account_role()` exists but is unused. Confirmed-history matching actually requires exact `source_type`, normalized merchant and semantics—not canonical account role as documented. It can therefore: - miss safe reuse across equivalent cash-account sources; - reuse history across two mappings of the same source type without distinguishing account role/account scope. This is the clearest safe extension point before adding more merchant names. ### Cluster construction Clusters are currently keyed by: `merchant/family identity × transaction semantics` They do **not** include source/account role. Behavior: - Stable public family → one broad family cluster. - Ambiguous marketplace → exact normalized merchant within the ambiguous family. - Generic TWINT → grouping visible, but bulk category forbidden. - Unknown merchants → exact normalized-counterparty cluster. - Only unresolved groups with at least two rows count as actionable merchant-review clusters. - Remaining unresolved rows count as individual reviews. Cluster decisions are appropriately bounded by: - HMAC-derived cluster/row tokens; - exact displayed membership; - category semantic compatibility; - explicit per-row exclusions; - preview/input/baseline fingerprints; - reconstruction under the confirm write lock. ### Readiness accounting `business_ready_for_confirm` requires all of: - technical integrity; - at least 95% ordinary-row coverage; - no more than 50 individual reviews; - no more than 3% individual-review ratio; - no more than 25 actionable merchant clusters; - transfer/card/Migros safety checks. Safe transfers, pending rows, duplicates, Migros details, and neutral card payments do not dilute the ordinary-row denominator. For the reported **56 clusters + 80 singleton reviews**, the current workflow exposes **136 user decision packages**, and fails all relevant readiness caps until decisions are bound into a new preview. One presentational caveat: the frontend renders all original actionable clusters with `count >= 2`, while readiness counts only clusters still containing at least two unresolved members. After exclusions/selections, displayed cluster totals can therefore diverge from the readiness workload. ## Recommended deterministic extensions Prioritize these in order: 1. **Implement canonical account-role-scoped history** - Key historical evidence by normalized counterparty, transaction semantics and validated canonical account role. - Require at least two consistent confirmations for learned classification. - Keep one confirmation as a non-learned proposal. - Any category conflict remains `decision_needed`. 2. **Add conservative structural merchant normalization** - Strip only independently meaningless provider decorations already recognized structurally: terminal/branch/store IDs, receipt/reference IDs, dates and card processor envelopes. - Never strip arbitrary trailing numbers, person-name parts, locality names or invoice text unless the token has an explicit public structural marker. - Version the normalization/classification contract. 3. **Separate clustering identity from automatic-category evidence** - Allow conservative variant clustering to reduce repeated decisions without automatically assigning a category. - Example: exact normalized root plus source/account role and semantics, where variants differ only by recognized terminal/branch decoration. - A wider cluster remains a user package unless conflict-free confirmed evidence independently supplies the category. 4. **Use within-preview bounded exact-counterparty grouping across files** - Same normalized counterparty, semantics and canonical account role may be reviewed once even when imported from multiple files. - Do not merge generic processors, cash withdrawals, personal counterparties or marketplace sub-merchants merely by processor family. 5. **Expand public taxonomy only with generic, auditable descriptors** - Suitable candidates: explicit service nouns such as pharmacy, veterinarian, tax authority, public transport, fuel station—only where category meaning is unambiguous. - Do not add private merchant names observed in runtime data. - Do not create “Other”, “Miscellaneous”, “Shopping” or processor-based fallback categories. 6. **Expose readiness decomposition** - Report unresolved rows covered by actionable clusters, forbidden-bulk groups, true singletons, conflicting-history rows and missing-category-taxonomy rows separately. - This will show whether the 56/80 burden is normalization, taxonomy coverage, conflict, or intentionally user-owned ambiguity. ## Privacy risks - The preview sends every cluster member’s normalized merchant, date and amount to the browser. This is necessary for informed exclusion, but it is a sensitive full-corpus payload; avoid logging, analytics, browser persistence and error serialization. - Merchant-normalization changes can accidentally encode private observed counterparties into tracked rules. Accept only generic/public rules with synthetic justification. - Broad stems, fuzzy clustering, locality stripping or legal-form stripping can merge different people/businesses and reveal inferred spending relationships. - Cross-source history must use opaque account roles—not account IDs, source references or account suffixes in API responses/audit summaries. - Do not persist cluster membership as a global learned rule from one bulk decision. Current `learned_rule=False` behavior for cluster decisions is correct. - Keep HMAC key separation and version binding; do not replace row/cluster tokens with unkeyed hashes. ## Synthetic tests to add 1. Same merchant and canonical role across two bank source types, two consistent confirmations → learned proposal. 2. Same text and source type but incompatible/different account role → no history reuse. 3. Two consistent confirmations plus one conflict → decision required. 4. Terminal/store/reference variants with recognized markers → one review cluster. 5. Arbitrary numeric suffix without a structural marker → separate clusters. 6. Same personal name on separate accounts → no cross-account bulk classification. 7. `TWINT Terminal ` variants → remain row-level and bulk decision forbidden. 8. Processor with extracted named merchant versus processor-only row → never merge. 9. Marketplace rows with distinct sub-merchants → no automatic category. 10. Broadened cluster with one semantically different member → split by semantics. 11. Category absent/inactive/wrong type → no fallback and no readiness credit. 12. Cluster decision with exclusions → exact coverage, individual and cluster counts after reconstruction. 13. Preview payload/log scan → no raw source references, descriptions, account IDs or internal counterparty hashes. 14. Rule/version change → different input/preview/cluster fingerprints and stale confirm rejection. 15. Readiness decomposition totals → unresolved rows partition exactly once across grouped, forbidden-bulk, singleton and conflict buckets. ## Must remain a user decision package - Generic TWINT or payment-processor rows without an extracted counterparty. - Marketplaces and multi-category retailers without item-level evidence. - Cash withdrawals. - Conflicting confirmed history. - Personal counterparties and opaque transfers. - Incoming bank payments without explicit salary, refund, interest or safely paired-transfer evidence. - Similarity ties or merchant variants not explained solely by structural decoration. - Any category requiring household intent rather than merchant identity. - Any bulk cluster containing exceptions the user has not explicitly reviewed/excluded. - Unmatched transfer classification, which must remain an explicit row-scoped user decision.