Skip to content

EPIC-015: Processing Account Integration

Status: โœ… Complete (TDD Aligned) Vision Anchor: decision-5-processing-account Phase: 3 Duration: 2 weeks Dependencies: EPIC-002, EPIC-004


๐ŸŽฏ Objective

Implement Processing virtual account for tracking in-transit transfers between accounts, achieving zero-balance pairing validation and automatic transfer detection, maintaining accounting equation integrity at all times.

Core Rules:

sum(all accounts) + Processing = constant
Balance = 0  โ†’ Auto-Accept Transfer Pair โœ…
Balance โ‰  0  โ†’ Pending Review โš ๏ธ


๐Ÿ‘ฅ Multi-Role Review

Role Focus Review Opinion
๐Ÿ”— Reconciler Transfer detection Keyword-based pattern matching with confidence scoring (โ‰ฅ85 auto-accept), handles unpaired transfers
๐Ÿ—๏ธ Architect System design Processing account as system account (is_system=true), 3-phase reconciliation flow integration
๐Ÿ“Š Accountant Business logic Double-entry compliance (DEBIT Processing on OUT, CREDIT Processing on IN), equation holds at all times
๐Ÿ’ป Developer Performance requirements Single-query transfer pairing with confidence scoring, O(nยฒ) pairing acceptable for MVP
๐Ÿงช Tester Coverage verification 97% line coverage (processing_account.py), 40 tests (33 unit + 7 integration), all pass
๐Ÿ“‹ PM User experience Unpaired transfers visible via Processing balance โ‰  0, supports manual confirmation

โœ… Task Checklist

Task 1.1: Documentation

  • [x] Create docs/ssot/processing_account.md (485 lines)
  • [x] ยง1: Concept & Purpose
  • [x] ยง2: Accounting Rules
  • [x] ยง3: Data Model Design
  • [x] ยง4: Transfer Detection SOP-001
  • [x] ยง5: Service API
  • [x] ยง6: Test Requirements
  • [x] ยง7: Integration Points (3-phase flow spec)

Task 1.2: Data Model Design

  • [x] Add is_system column to accounts table
  • [x] Alembic migration c955c65dcc1f_add_is_system_to_accounts.py
  • [x] Update Account model and schema
  • [x] Update account_service.py to handle system accounts

Task 1.3: Backend Logic

  • [x] services/processing_account.py (487 lines) - Core service
  • [x] get_or_create_processing_account() - Idempotent account creation
  • [x] detect_transfer_pattern() - Keyword matching (SOP-001)
  • [x] create_transfer_out_entry() - DEBIT Processing, CREDIT source
  • [x] create_transfer_in_entry() - DEBIT destination, CREDIT Processing
  • [x] find_transfer_pairs() - Confidence scoring (amount 40%, description 30%, date 20%)
  • [x] get_processing_balance() - Current balance query
  • [x] get_unpaired_transfers() - List unmatched transfers
  • [x] Scoring functions implementation
  • [x] _score_amount_match() - Amount similarity (exact โ‰ค0.01, close โ‰ค0.10, moderate โ‰ค1.00)
  • [x] _score_description_match() - SequenceMatcher (60%) + token overlap (40%)
  • [x] _score_date_proximity() - Same day=100%, 7-day window
  • [x] _calculate_pair_confidence() - Weighted formula application
  • [x] Test coverage: 33 tests, 97% line coverage

Task 1.4: Reconciliation Integration

  • [x] Modified services/reconciliation.py (128 lines added)
  • [x] Phase 1: Transfer Detection (lines 766-866) - BEFORE normal matching
  • [x] Phase 2: Normal Matching (lines 867-989) - Existing logic preserved
  • [x] Phase 3: Auto-Pairing (lines 990-1020) - AFTER all matching
  • [x] Integration test coverage: 7 tests in test_transfer_integration.py
  • [x] Bug fixes:
  • [x] Lazy loading issue (added selectinload(JournalEntry.lines))
  • [x] Status filter expansion (POSTED โ†’ [POSTED, RECONCILED] in 2 queries)
  • [x] Duplicate join clause removal
  • [x] All 171 tests passing (33 processing + 138 reconciliation)

๐Ÿงช Test Cases

Test Organization: Tests organized by feature blocks using ACx.y.z numbering. Coverage: See apps/backend/tests/accounting/test_processing_account.py and apps/backend/tests/reconciliation/test_transfer_integration.py

AC15.1: Processing Account Creation

ID Test Case Test Function File Priority
AC15.1.1 Processing Account Created test_create_processing_account_once accounting/test_processing_account.py P0
AC15.1.2 Idempotent Creation test_processing_account_idempotent accounting/test_processing_account.py P0
AC15.1.3 Hidden from User Accounts test_processing_account_hidden_from_list accounting/test_processing_account.py P0
AC15.1.4 Per-User Isolation test_processing_account_per_user accounting/test_processing_account.py P0

AC15.2: Transfer Entry Creation

ID Test Case Test Function File Priority
AC15.2.1 Transfer OUT Entry test_transfer_out_debits_processing accounting/test_processing_account.py P0
AC15.2.2 Transfer IN Entry test_transfer_in_credits_processing accounting/test_processing_account.py P0
AC15.2.3 Paired Transfers Zero Balance test_paired_transfers_zero_processing_balance accounting/test_processing_account.py P0

AC15.3: Accounting Integrity

ID Test Case Test Function File Priority
AC15.3.1 Unpaired Transfer Visible test_unpaired_transfer_shows_in_balance accounting/test_processing_account.py P0
AC15.3.2 Accounting Equation Holds test_processing_account_maintains_equation accounting/test_processing_account.py P0

AC15.4: Transfer Detection

ID Test Case Test Function File Priority
AC15.4.1 Keyword Detection test_detect_transfer_keywords accounting/test_processing_account.py P0
AC15.4.2 Non-Transfer Detection test_detect_no_description accounting/test_processing_account.py P0
AC15.4.3 Auto-Pairing Above Threshold test_find_transfer_pairs_above_threshold accounting/test_processing_account.py P0

AC15.5: Scoring Functions

ID Test Case Test Function File Priority
AC15.5.1 Amount Scoring (Exact) test_score_amount_exact_match accounting/test_processing_account.py P0
AC15.5.2 Amount Scoring (Tiers) test_score_amount_* (9 tests) accounting/test_processing_account.py P0
AC15.5.3 Description Scoring test_score_description_* (4 tests) accounting/test_processing_account.py P1
AC15.5.4 Date Scoring test_score_date_* (5 tests) accounting/test_processing_account.py P1

AC15.6: Reconciliation Integration

ID Test Case Test Function File Priority
AC15.6.1 Transfer Detection During Reconciliation test_transfer_out_detected_creates_processing_entry reconciliation/test_transfer_integration.py P0
AC15.6.2 Transfer Detection Skips (No Account) test_transfer_detection_skips_when_no_account_linked reconciliation/test_transfer_integration.py P0
AC15.6.3 Transfer IN Detection test_transfer_in_detected_creates_processing_entry reconciliation/test_transfer_integration.py P0
AC15.6.4 Auto-Pairing Phase test_auto_pair_matching_transfer_same_amount reconciliation/test_transfer_integration.py P0
AC15.6.5 Unpaired Transfer Balance test_unpaired_transfer_leaves_nonzero_balance reconciliation/test_transfer_integration.py P0
AC15.6.6 Normal Matching Preserved test_non_transfer_proceeds_to_normal_matching reconciliation/test_transfer_integration.py P0

Traceability Result: - Total AC IDs: 24 - Requirements converted to AC IDs: 100% (EPIC-015 checklist + must-have standards) - Requirements with test references: 100% - Test files: 2


๐Ÿ“ Acceptance Criteria

๐ŸŸข Must Have

Standard Verification Weight
Double-entry compliance All transfers create balanced entries (DEBIT = CREDIT) ๐Ÿ”ด Critical
Accounting equation holds test_processing_account_maintains_equation ๐Ÿ”ด Critical
Transfer detection accuracy Keyword matching per SOP-001 Required
Auto-pair threshold โ‰ฅ85 test_find_transfer_pairs_above_threshold Required
Zero-balance validation Processing balance = 0 for matched pairs ๐Ÿ”ด Critical
Line coverage โ‰ฅ97% processing_account.py coverage report Required

๐ŸŒŸ Nice to Have

Standard Verification Status
ML-based pattern learning History score (currently 0.0) โณ Future
Multi-currency transfer support After EPIC-005 (Multi-Currency) โณ Future
Real-time transfer monitoring WebSocket alerts for unpaired transfers โณ Future

๐Ÿšซ Not Acceptable Signals

  • Float usage for monetary amounts (MUST use Decimal)
  • Unbalanced entries (debit โ‰  credit)
  • Accounting equation violations (sum โ‰  constant)
  • Processing balance โ‰  0 for confirmed pairs
  • Coverage < 95%

๐Ÿ“š SSOT References


๐Ÿ”— Deliverables

  • [x] docs/ssot/processing_account.md (485 lines) - SSOT specification
  • [x] apps/backend/migrations/versions/c955c65dcc1f_add_is_system_to_accounts.py - Migration
  • [x] apps/backend/src/models/account.py - is_system flag added
  • [x] apps/backend/src/schemas/account.py - is_system schema field
  • [x] apps/backend/src/services/account_service.py - System account handling (31 lines)
  • [x] apps/backend/src/services/processing_account.py (487 lines) - Core service
  • [x] apps/backend/src/services/reconciliation.py - 3-phase flow integration (128 lines added)
  • [x] apps/backend/src/services/accounting.py - Import/export updates (9 lines)
  • [x] apps/backend/tests/accounting/test_processing_account.py (811 lines) - Unit tests (33 tests)
  • [x] apps/backend/tests/reconciliation/test_transfer_integration.py (569 lines) - Integration tests (7 tests)

Git Commit: SHA 16ee6e9 - "feat: integrate Processing account with reconciliation engine (Task 1.4)"


๐Ÿ“ Technical Debt

Item Priority Planned Resolution
Over-matching risk P1 Track matched IN entries to prevent multiple OUT entries pairing with same IN
Input validation P2 Add positive amount, valid UUID checks to public functions
Zero-amount transfers P2 Add test coverage for zero-amount edge case
Concurrent operations P2 Add transaction isolation tests (DB integrity risk)
History score placeholder P3 ML-based pattern learning (v2.0)

Issues & Gaps

Code Review Findings (from background agents)

Architecture โœ…: - 3-phase flow correctly follows SSOT ยง7 - Phase 1 runs BEFORE Phase 2, Phase 3 runs AFTER - Existing reconciliation logic unchanged (backward compatible) - Error handling prevents reconciliation breakdown

Code Quality โš ๏ธ: 1. Over-matching risk: Multiple OUT entries could pair with same IN entry (low probability) - Impact: Medium (rare edge case) - Fix: Track matched IN entries in find_transfer_pairs() 2. Missing input validation: No checks for positive amounts, valid UUIDs - Impact: Low (caught by DB constraints) - Fix: Add validation to public functions 3. History score: Hardcoded to 0.0 (acceptable, noted in comments)

Test Coverage โš ๏ธ: 1. Zero-amount transfers: Not tested (source handles it, but no test) - Impact: Medium (edge case) - Fix: Add test in test_processing_account.py 2. Concurrent operations: Not tested - Impact: High (DB integrity risk) - Fix: Add transaction isolation tests 3. Empty string descriptions: Partially tested - Impact: Low (code handles it) - Fix: Add explicit test

Conclusion: Code is production-ready with 97% coverage, 40 passing tests. Issues are non-blocking for MVP (all tests pass, accounting equation holds). Address technical debt before scaling to production volume.


โ“ Q&A (Clarification Required)

Q1: What happens to unpaired transfers?

Decision: Visible via get_unpaired_transfers() and Processing balance โ‰  0. User confirms manually, creating regular journal entry to close Processing account.

Q2: Auto-pairing threshold rationale?

Decision: Use 85 (same as reconciliation auto-accept) to maintain consistent confidence bar across system.

Q3: Multi-currency transfer support?

Decision: Out of scope for EPIC-015. Process transfers in base currency only. Multi-currency handled in EPIC-005 (Reporting).

Q4: History score implementation?

Decision: Hardcoded to 0.0 in MVP. ML-based pattern learning deferred to v2.0 (requires transaction history dataset).

Q5: Processing account visibility?

Decision: Hidden from list_accounts() (is_system=true), but balance and transfers visible via dedicated endpoints (get_processing_balance(), get_unpaired_transfers()).


๐Ÿ“… Timeline

Phase Content Status
Week 1 Task 1.1-1.2 (Documentation + Data Model) โœ… Done
Week 1-2 Task 1.3 (Backend Logic + Tests) โœ… Done
Week 2 Task 1.4 (Reconciliation Integration + Bug Fixes) โœ… Done

Total Duration: 2 weeks (Jan 2026 - Feb 2026)


  • EPIC-002 (Double-Entry Core) - Foundation for Processing account entries
  • EPIC-004 (Reconciliation Engine) - Extended with 3-phase transfer detection
  • EPIC-005 (Reporting) - Multi-currency support for future transfer handling

๐Ÿ“Š Test Evidence

Coverage Report

processing_account.py:  97% coverage (472/487 statements)
reconciliation.py:      90% coverage (925/1028 statements)
Total:                  171 tests passing (33 + 138)

Integration Test Results

test_transfer_integration.py::TestTransferDetectionDuringReconciliation   PASSED (3 tests)
test_transfer_integration.py::TestTransferAutoPairingPhase                PASSED (2 tests)
test_transfer_integration.py::TestNormalMatchingPhaseIntegration          PASSED (2 tests)

Accounting Equation Validation

# From test_processing_account_maintains_equation
assets = db_assets + processing_balance
liabilities_equity = db_liabilities + db_equity
assert abs(assets - liabilities_equity) < Decimal("0.01")  # โœ… PASSED

Completed: February 2026 Agent: Sisyphus (primary development agent) Review: Code review completed by 3 background explore agents


๐Ÿ†• UI Gap Audit (April 2026) โ€” Processing Account Visibility

Origin: UI gap audit against vision.md (in-flight transfers must be visible). Backend processing-account flow is complete but the dashboard does not show pending in-transit balance, so users cannot see "money on the road".

Acceptance Criteria

  • [x] AC15.7.1 API endpoint GET /api/accounts/processing/summary returns {pending_count, pending_total, currency, oldest_pending_date}
  • [x] AC15.7.2 Dashboard "Processing / In-Transit" card renders the four fields with currency code
  • [x] AC15.7.3 Card click-through navigates to /processing listing pending transfers (existing or new page) with line items {from_account, to_account, amount, initiated_date, days_outstanding}
  • [x] AC15.7.4 Pending entries older than 7 days render a warning badge on the listing row
  • [x] AC15.7.5 Frontend test mounts ProcessingSummaryCard and asserts pending_count + pending_total labels render

Priority: P0-quick-win โ€” small UI surface; backend already exposes processing-account state. Estimated effort: 1-2 days backend (summary endpoint) + 2-3 days frontend (card + listing).