🧠 Enrichment
Enrichment turns raw payee/memo text into canonical entities and tags using YAML pattern registries, executed through dagpipe pipelines.
🏢 Entity Resolution
Lives under domain/enrichment/entity/:
identity.py— normalizes and fingerprints payee strings for matching.resolver.py—EntityResolver: resolves a raw payee to anentity_idvia name lookup + fingerprint + account linkage.pipeline.py— the enrichment pipeline node that uses the resolver on expense records.utils.py— helpers for entity display names and brand collapsing.
The pipeline is expressed as a dagpipe.Pipeline; the stub pipeline.pyi type-checks against dagpipe directly (see domain/enrichment/entity/pipeline.pyi).
🏷 Tag Assignment
Lives under domain/enrichment/tags/:
flags.py— tag candidate flags (priority/confidence hints) computed from memo and MCC.pipeline.py— adagpipe.Pipelinethat assigns atag_idto expenses based on matched rules.- Both are seeded with YAML pattern registries (regex + literal patterns per tag) under the enrichment rules data.
🔄 How Rules Are Wired
- The extraction stage yields expenses with raw
memo/payee fields. - The orchestrator (
PipelineOrchestratorindomain/fetch_pipeline/) chains extraction → enrichment. - Enrichment nodes receive entity/tag services and the http cache store for external lookups.
- Resolved
entity_id/tag_idare written back onto the expense and persisted.
🧪 Testing
- Unit tests in
tests/domain/enrichment/cover fingerprint/identity edge cases, tag flag computation, and pipeline wiring. - Golden fixtures for memo→entity and memo→tag mappings keep the registries honest.
- Run them:
.venv\Scripts\pytest.exe tests\domain\enrichment