# Privacy-safe root-cause aggregation for financial review backlogs

Use this workflow when a technically confirmable financial-import preview still contains too many review cases for row-by-row handling.

## Safety boundary

- Open the production database through a read-only connection such as SQLite `mode=ro`; never call confirm/import routes.
- Read private source files locally and keep row-level material in memory only.
- Emit only aggregate counts, active category names, explicitly allowlisted public merchant families, and opaque cluster IDs.
- Never emit raw rows, descriptions, account references, filenames, fingerprints, or private counterparties.
- Reproduce the existing preview first and assert its headline counts before trusting any root-cause analysis.

## Reproduction pattern

1. Use the same deployed code revision and classification/pairing versions as the baseline preview.
2. Resolve account mappings by opaque mapping IDs. Use stable source references internally only where the preview contract requires them.
3. Invoke the internal preview path in memory against the read-only database and private inputs.
4. Assert rows, candidates, review count, proposals, special cases, expected writes, confirmability, and zero errors against the saved baseline.
5. Filter the reproduced rows to `requires_review=true`; all subsequent analysis operates on that exact set.

## Aggregate dimensions

Compute at minimum:

- source/profile;
- original classification;
- classifier `origin` and `internal_reason`;
- user state;
- transaction semantics crossed with amount sign;
- current active-category proposal and rule origin;
- structured detail-field availability by source;
- source-scoped normalized merchant/description clusters;
- cluster frequency buckets and cumulative coverage thresholds.

Opaque cluster IDs should be deterministic for the current snapshot (for example, rank by descending count with a hash tie-breaker). Treat them as snapshot-local labels unless a durable keyed identity scheme is explicitly designed.

## Disjoint root-cause partition

Order conditions so cases do not overlap:

1. safe transfer already established but review flag remains;
2. unmatched card-settlement semantics;
3. possible logical/legacy duplicate;
4. receipt-linkage decision;
5. conflicting confirmed-category history;
6. usable category proposal still review-flagged;
7. unresolved repeated source-scoped pattern (missing-rule candidate);
8. unresolved singleton/one-off (insufficient evidence).

This separates genuine ambiguity from rule-coverage gaps and workflow-counter contamination. Report both counts and percentages, and verify the partition sums exactly to the review total.

## Coverage thresholds

For a review total `N`, compute target case counts as `ceil(N × 0.80)`, `ceil(N × 0.90)`, and `ceil(N × 0.95)`. Rank exact source-scoped clusters by frequency and report the minimum number required to reach each threshold.

A large long tail is evidence against creating hundreds of literal rules. Prefer source-qualified family normalization plus learning from confirmed decisions.

## Rule-family recommendation gates

- A repeated consistent sign/semantic pattern is evidence for a family, not evidence for a category.
- Public, semantically unambiguous families may be named only through an explicit allowlist and mapped only to an existing active category.
- Opaque clusters require one private family-level category decision before a rule is learned.
- Keep medium-confidence families manual when the active taxonomy lacks a clearly fitting category.
- Receipt-detail rows are enrichment/linkage records, never a second expense.
- Transfer/payment/duplicate clusters must not become expense-category rules.
- Bind rules to source, normalized family, sign, and compatible semantics; preview their impact before any confirm.

## High-value diagnostics

- Compare hard-coded category-name lookups to actual active category names, including punctuation and separators. A display-name mismatch can disable an otherwise valid family rule at scale; prefer category IDs or normalized aliases over exact display-name literals.
- Count available source fields separately from fields exposed by the redacted preview. Identity/detail fields may exist in source rows but be intentionally removed from public preview structures.
- Identify fields ignored by the classifier (for example place/country, payment type, original currency, bank narrative structure). Use them for conservative family extraction only when privacy and semantics remain clear.
- Separate true review work from flags left on already-safe transfers or actionable proposals; otherwise the headline review count overstates manual effort.

## Verification before reporting

- Baseline preview reproduced exactly.
- Root-cause buckets sum to the review total.
- Coverage arithmetic is tool-computed.
- No raw/private values appear in output.
- Database and sources were opened read-only and no confirm/import path ran.
- No report or temporary artifact was written unless explicitly requested; if written, it must be private and aggregate-only.
