AC-to-Test Traceability Audit¶
Generated: 2026-05-06 (mechanically by
scripts/build_ac_traceability.py) Purpose: Complete mapping of every Acceptance Criterion (ACx.y.z) declared indocs/ac_registry.yaml+docs/infra_registry.yamlto the test file(s) that reference it. Scope: All EPICs indocs/project/. Test scan:apps/backend/tests,apps/frontend/src,scripts/tests.⚙️ Do not edit this file by hand. It is regenerated by
scripts/build_ac_traceability.pyand verified in CI viascripts/build_ac_traceability.py --check. Update the registries or add anACx.y.zreference inside a test file, then re-run the builder.
📊 Executive Summary¶
| Metric | Count | Percentage |
|---|---|---|
| Total EPICs | 18 | 100% |
| Total ACs (registries) | 918 | 100% |
| Mandatory ACs | 757 | 82.5% |
| Deprecated ACs | 3 | 0.3% |
| Mandatory ACs with test reference | 757 | 100.0% |
| Mandatory ACs without test reference | 0 | 0.0% |
| Test files referenced | 171 | - |
| ACs flagged as manual verification (heuristic) | 0 | 0.0% |
Coverage by EPIC¶
| EPIC | Name | Total ACs | Deprecated | Mandatory | With Test Ref | Coverage |
|---|---|---|---|---|---|---|
| EPIC-001 | phase0-setup | 29 | 0 | 27 | 27 | 100.0% |
| EPIC-002 | double-entry-core | 59 | 0 | 44 | 44 | 100.0% |
| EPIC-003 | statement-parsing | 39 | 0 | 19 | 19 | 100.0% |
| EPIC-004 | reconciliation-engine | 39 | 0 | 18 | 18 | 100.0% |
| EPIC-005 | reporting-visualization | 36 | 0 | 25 | 25 | 100.0% |
| EPIC-006 | ai-advisor | 63 | 0 | 55 | 55 | 100.0% |
| EPIC-007 | deployment | 39 | 0 | 39 | 39 | 100.0% |
| EPIC-008 | testing-strategy | 61 | 0 | 55 | 55 | 100.0% |
| EPIC-009 | pdf-fixture-generation | 37 | 0 | 36 | 36 | 100.0% |
| EPIC-010 | signoz-logging | 21 | 0 | 21 | 21 | 100.0% |
| EPIC-011 | asset-lifecycle | 34 | 0 | 34 | 34 | 100.0% |
| EPIC-012 | foundation-libs | 62 | 3 | 55 | 55 | 100.0% |
| EPIC-013 | statement-parsing-v2 | 60 | 0 | 58 | 58 | 100.0% |
| EPIC-014 | ttd-transformation | 6 | 0 | 6 | 6 | 100.0% |
| EPIC-015 | processing-account | 27 | 0 | 27 | 27 | 100.0% |
| EPIC-016 | two-stage-review-ui | 210 | 0 | 186 | 186 | 100.0% |
| EPIC-017 | portfolio-management | 73 | 0 | 29 | 29 | 100.0% |
| EPIC-018 | ai-driven-pipeline | 23 | 0 | 23 | 23 | 100.0% |
📋 EPIC-001: phase0-setup¶
- Total ACs: 29
- Mandatory ACs: 27
- Mandatory ACs with test reference: 27 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC1.1.1 | yes | Root moon.yml exists | apps/backend/tests/auth/test_auth_edge_cases.pyapps/backend/tests/infra/test_epic_001_contracts.pyapps/backend/tests/review/test_statement_validation.pyscripts/tests/test_audit_ac_epic_mismatches.pyscripts/tests/test_build_ac_traceability.pyscripts/tests/test_check_ac_traceability.pyscripts/tests/test_generate_ac_registry.pyscripts/tests/test_lint_doc_consistency.py |
✅ |
| AC1.1.2 | yes | apps/backend/moon.yml exists | apps/backend/tests/review/test_statement_validation.pyscripts/tests/test_audit_ac_epic_mismatches.pyscripts/tests/test_build_ac_traceability.pyscripts/tests/test_check_ac_traceability.pyscripts/tests/test_lint_doc_consistency.py |
✅ |
| AC1.1.3 | yes | apps/frontend/moon.yml exists | apps/backend/tests/review/test_statement_validation.pyscripts/tests/test_check_ac_traceability.py |
✅ |
| AC1.1.4 | yes | infra/moon.yml exists | apps/backend/tests/review/test_statement_validation.py |
✅ |
| AC1.2.1 | yes | FastAPI project structure exists | apps/backend/tests/infra/test_epic_001_contracts.pyapps/backend/tests/review/test_statement_validation.py |
✅ |
| AC1.2.2 | yes | Auth integration works (register/login/JWT) | apps/backend/tests/review/test_statement_validation.py |
✅ |
| AC1.2.3 | yes | SQLAlchemy + Alembic config valid | apps/backend/tests/_ac_stubs/test_epic_01_stubs.pyscripts/tests/test_generate_ac_registry.py |
✅ |
| AC1.2.4 | yes | Health endpoint returns success | apps/backend/tests/_ac_stubs/test_epic_01_stubs.py |
✅ |
| AC1.2.5 | yes | structlog logging configured | apps/backend/tests/_ac_stubs/test_epic_01_stubs.py |
✅ |
| AC1.3.1 | yes | Next.js App Router files exist | apps/backend/tests/infra/test_epic_001_contracts.pyapps/backend/tests/review/test_statement_validation.py |
✅ |
| AC1.3.2 | yes | TailwindCSS configuration exists | apps/backend/tests/_ac_stubs/test_epic_01_stubs.py |
✅ |
| AC1.3.3 | yes | Ping-pong page exists | apps/backend/tests/_ac_stubs/test_epic_01_stubs.py |
✅ |
| AC1.3.4 | yes | TanStack Query dependency configured | apps/backend/tests/infra/test_epic_001_contracts.py |
✅ |
| AC1.4.1 | yes | docker-compose.yml integrity valid | apps/backend/tests/review/test_statement_validation.py |
✅ |
| AC1.4.2 | yes | PostgreSQL 15 container defined | apps/backend/tests/infra/test_epic_001_contracts.py |
✅ |
| AC1.4.3 | yes | Redis 7 container defined | apps/backend/tests/_ac_stubs/test_epic_01_stubs.py |
✅ |
| AC1.4.4 | yes | Data volumes configured | apps/backend/tests/_ac_stubs/test_epic_01_stubs.py |
✅ |
| AC1.5.1 | yes | Backend startup command path is valid | apps/backend/tests/review/test_statement_validation.py |
✅ |
| AC1.5.2 | yes | Frontend startup command path is valid | apps/backend/tests/infra/test_epic_001_contracts.py |
✅ |
| AC1.5.3 | yes | Health endpoint returns 200 | apps/backend/tests/_ac_stubs/test_epic_01_stubs.py |
✅ |
| AC1.5.4 | yes | Backend ping-pong endpoint toggles state correctly | apps/backend/tests/_ac_stubs/test_epic_01_stubs.py |
✅ |
| AC1.5.5 | yes | User registration/login API available | apps/backend/tests/_ac_stubs/test_epic_01_stubs.py |
✅ |
| AC1.6.1 | yes | Pre-commit hooks configuration present | apps/backend/tests/infra/test_epic_001_contracts.pyapps/backend/tests/review/test_statement_validation.py |
✅ |
| AC1.6.2 | no | apps/backend/tests/review/test_statement_validation.py |
✅ (optional) | |
| AC1.7.1 | yes | Register endpoint accepts valid user payload | apps/backend/tests/auth/test_auth.pyapps/backend/tests/auth/test_auth_router.py |
✅ |
| AC1.7.2 | yes | Register endpoint rejects duplicate email | apps/backend/tests/auth/test_auth_router.py |
✅ |
| AC1.7.3 | yes | Login endpoint accepts valid credentials | apps/backend/tests/auth/test_auth_router.py |
✅ |
| AC1.7.4 | no | apps/backend/tests/auth/test_auth_router.py |
✅ (optional) | |
| AC1.8.1 | yes | User Management Endpoint Tests | apps/backend/tests/auth/test_users_router.py |
✅ |
📋 EPIC-002: double-entry-core¶
- Total ACs: 59
- Mandatory ACs: 44
- Mandatory ACs with test reference: 44 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC2.1.1 | yes | Create account with valid data | apps/backend/tests/accounting/test_account_service_unit.pyapps/backend/tests/accounting/test_accounts_service.pyapps/backend/tests/review/test_consistency_checks.pyscripts/tests/test_audit_ac_epic_mismatches.pyscripts/tests/test_build_ac_traceability.pyscripts/tests/test_check_ac_traceability.pyscripts/tests/test_generate_ac_registry.pyscripts/tests/test_lint_doc_consistency.py |
✅ |
| AC2.1.2 | yes | Get account by ID | apps/backend/tests/accounting/test_accounts_service.pyscripts/tests/test_audit_ac_epic_mismatches.py |
✅ |
| AC2.1.3 | yes | Get non-existent account fails | apps/backend/tests/accounting/test_accounts_service.py |
✅ |
| AC2.1.4 | yes | Update account successfully | apps/backend/tests/accounting/test_accounts_service.py |
✅ |
| AC2.1.5 | yes | Update non-existent account fails | apps/backend/tests/accounting/test_accounts_service.py |
✅ |
| AC2.1.6 | yes | List accounts with filters | apps/backend/tests/accounting/test_accounts_service.py |
✅ |
| AC2.2.1 | yes | Balanced entry passes validation | apps/backend/tests/accounting/test_accounting.pyapps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC2.2.2 | yes | Unbalanced entry fails validation | apps/backend/tests/accounting/test_accounting.py |
✅ |
| AC2.2.3 | yes | Single-line entry fails (minimum 2 lines) | apps/backend/tests/accounting/test_accounting.pyapps/backend/tests/accounting/test_accounting_service_errors.py |
✅ |
| AC2.2.4 | yes | Decimal precision maintained | apps/backend/tests/accounting/test_accounting.py |
✅ |
| AC2.2.5 | yes | FX rate required for non-base currency | apps/backend/tests/accounting/test_accounting.py |
✅ |
| AC2.2.6 | yes | Unbalanced post attempt fails | apps/backend/tests/_ac_stubs/test_epic_02_stubs.py |
✅ |
| AC2.3.1 | yes | Post draft entry successfully | apps/backend/tests/accounting/test_journal_service.pyapps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC2.3.2 | yes | Post already-posted entry fails | apps/backend/tests/accounting/test_journal_service.py |
✅ |
| AC2.3.3 | yes | Posted entry cannot be reposted | apps/backend/tests/accounting/test_journal_service.py |
✅ |
| AC2.3.4 | yes | Posted entry status immutable | apps/backend/tests/accounting/test_journal_service.py |
✅ |
| AC2.3.5 | yes | Void entry creates reversal | apps/backend/tests/accounting/test_accounting_equation.pyapps/backend/tests/accounting/test_journal_service.py |
✅ |
| AC2.3.6 | no | apps/backend/tests/accounting/test_accounting_equation.pyapps/backend/tests/accounting/test_journal_service.py |
✅ (optional) | |
| AC2.3.7 | no | apps/backend/tests/accounting/test_journal_delete_and_validation.py |
✅ (optional) | |
| AC2.3.8 | no | apps/backend/tests/accounting/test_accounting_service_errors.py |
✅ (optional) | |
| AC2.3.9 | no | apps/backend/tests/accounting/test_accounting_service_errors.py |
✅ (optional) | |
| AC2.3.10 | no | apps/backend/tests/accounting/test_accounting_service_errors.py |
✅ (optional) | |
| AC2.3.11 | no | apps/backend/tests/accounting/test_accounting_service_errors.py |
✅ (optional) | |
| AC2.4.1 | yes | Calculate balance for asset account | apps/backend/tests/accounting/test_accounting_balances.pyapps/backend/tests/accounting/test_accounting_service_errors.pyapps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC2.4.2 | yes | Calculate balance for income account | apps/backend/tests/accounting/test_accounting_service_errors.py |
✅ |
| AC2.4.3 | yes | Draft entries excluded from balance | apps/backend/tests/_ac_stubs/test_epic_02_stubs.py |
✅ |
| AC2.4.4 | yes | Calculate balances by account type | apps/backend/tests/_ac_stubs/test_epic_02_stubs.py |
✅ |
| AC2.4.5 | yes | Empty account list returns empty balances | apps/backend/tests/_ac_stubs/test_epic_02_stubs.py |
✅ |
| AC2.4.6 | no | apps/backend/tests/accounting/test_accounting_balances.py |
✅ (optional) | |
| AC2.5.1 | yes | Accounting equation holds with all types | apps/backend/tests/accounting/test_accounting_equation.pyapps/backend/tests/accounting/test_accounting_service_errors.pyapps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC2.5.2 | yes | Equation violation detected | apps/backend/tests/accounting/test_accounting_equation.pyapps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC2.5.3 | yes | Accounting equation holds after transactions | apps/backend/tests/_ac_stubs/test_epic_02_stubs.py |
✅ |
| AC2.6.1 | yes | Maximum amount (999,999,999.99) | apps/backend/tests/accounting/test_accounting_equation.pyapps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC2.6.2 | yes | Minimum amount (0.01) | apps/backend/tests/accounting/test_accounting_equation.pyapps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC2.6.3 | yes | Decimal precision loss detection | apps/backend/tests/accounting/test_accounting_equation.pyapps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC2.6.4 | yes | Many-line complex entry (salary breakdown) | apps/backend/tests/accounting/test_accounting_equation.py |
✅ |
| AC2.7.1 | yes | Router uses flush not commit | apps/backend/tests/accounting/test_accounting_integration.pyapps/backend/tests/accounting/test_journal_router_additional.pyapps/backend/tests/api/test_journal_router.py |
✅ |
| AC2.7.2 | yes | Journal router error paths | apps/backend/tests/accounting/test_journal_router_additional.pyapps/backend/tests/accounting/test_journal_router_errors.pyapps/backend/tests/api/test_journal_router.py |
✅ |
| AC2.7.3 | yes | Journal router additional scenarios | apps/backend/tests/accounting/test_journal_router_additional.pyapps/backend/tests/api/test_journal_router.py |
✅ |
| AC2.7.4 | no | apps/backend/tests/accounting/test_journal_router_additional.pyapps/backend/tests/api/test_journal_router.py |
✅ (optional) | |
| AC2.7.5 | no | apps/backend/tests/accounting/test_journal_delete_and_validation.pyapps/backend/tests/accounting/test_journal_router_additional.pyapps/backend/tests/api/test_journal_router.py |
✅ (optional) | |
| AC2.7.6 | no | apps/backend/tests/api/test_journal_router.py |
✅ (optional) | |
| AC2.7.7 | no | apps/backend/tests/api/test_journal_router.py |
✅ (optional) | |
| AC2.8.1 | yes | Never use float for monetary amounts | apps/backend/tests/accounting/test_decimal_safety.py |
✅ |
| AC2.8.2 | yes | Decimal precision maintained in arithmetic | apps/backend/tests/accounting/test_decimal_safety.py |
✅ |
| AC2.8.3 | no | apps/backend/tests/accounting/test_decimal_safety.py |
✅ (optional) | |
| AC2.9.1 | yes | Account model supports required fields and types | apps/backend/tests/accounting/test_schemas.py |
✅ |
| AC2.9.2 | yes | JournalEntry model supports required fields and status flow | apps/backend/tests/_ac_stubs/test_epic_02_stubs.py |
✅ |
| AC2.9.3 | yes | JournalLine enforces debit/credit + amount rules | apps/backend/tests/accounting/test_schemas.py |
✅ |
| AC2.9.4 | yes | Pydantic account/journal schemas validated | apps/backend/tests/_ac_stubs/test_epic_02_stubs.py |
✅ |
| AC2.10.1 | yes | POST /accounts, GET /accounts, GET /accounts/{id}, PUT /accounts/{id} | apps/backend/tests/accounting/test_accounts_endpoints.pyapps/backend/tests/accounting/test_delete_endpoints.pyapps/backend/tests/accounting/test_journal_endpoints.pyapps/backend/tests/reconciliation/test_reconciliation_endpoints.py |
✅ |
| AC2.10.2 | yes | POST /journal-entries, GET /journal-entries, GET /journal-entries/{id} | apps/backend/tests/accounting/test_accounts_edge_cases.pyapps/backend/tests/accounting/test_delete_endpoints.py |
✅ |
| AC2.10.3 | yes | POST /journal-entries/{id}/post, POST /journal-entries/{id}/void | apps/backend/tests/accounting/test_delete_endpoints.py |
✅ |
| AC2.10.4 | yes | API error behavior for missing/invalid resources | apps/backend/tests/accounting/test_delete_endpoints.py |
✅ |
| AC2.10.5 | no | apps/backend/tests/accounting/test_delete_endpoints.py |
✅ (optional) | |
| AC2.11.4 | yes | Multi-currency requires fx_rate | apps/backend/tests/infra/test_infra_edge_cases.py |
✅ |
| AC2.12.1 | no | apps/backend/tests/accounting/test_validation.py |
✅ (optional) | |
| AC2.12.5 | no | apps/backend/tests/infra/test_infra_edge_cases.py |
✅ (optional) | |
| AC2.12.6 | yes | Statement Validation Logic Tests | apps/backend/tests/accounting/test_validation.py |
✅ |
📋 EPIC-003: statement-parsing¶
- Total ACs: 39
- Mandatory ACs: 19
- Mandatory ACs with test reference: 19 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC3.1.1 | yes | Parse DBS PDF | apps/backend/tests/extraction/test_pdf_parsing.pyscripts/tests/test_audit_ac_epic_mismatches.pyscripts/tests/test_lint_doc_consistency.py |
✅ |
| AC3.1.2 | yes | Parse CSV (DBS) | apps/backend/tests/extraction/test_csv_parsing.py |
✅ |
| AC3.1.3 | yes | Parse CSV (Wise) | apps/backend/tests/extraction/test_csv_parsing.py |
✅ |
| AC3.1.4 | yes | Parse CSV (Generic) | apps/backend/tests/extraction/test_csv_parsing.py |
✅ |
| AC3.1.5 | yes | Parse CSV with BOM | apps/backend/tests/extraction/test_csv_parsing.py |
✅ |
| AC3.2.1 | yes | Balance Validation (Pass) | apps/backend/tests/_ac_stubs/test_epic_03_stubs.py |
✅ |
| AC3.2.2 | yes | Balance Validation (Fail) | apps/backend/tests/_ac_stubs/test_epic_03_stubs.py |
✅ |
| AC3.2.3 | yes | Completeness Validation | apps/backend/tests/extraction/test_pdf_parsing.py |
✅ |
| AC3.3.1 | yes | High Confidence (Auto-Accept) | apps/backend/tests/_ac_stubs/test_epic_03_stubs.py |
✅ |
| AC3.3.2 | yes | Medium Confidence (Review) | apps/backend/tests/_ac_stubs/test_epic_03_stubs.py |
✅ |
| AC3.3.3 | yes | Low Confidence (Manual) | apps/backend/tests/_ac_stubs/test_epic_03_stubs.py |
✅ |
| AC3.4.1 | yes | Invalid Parse Not Persisted | apps/backend/tests/extraction/test_pdf_parsing.py |
✅ |
| AC3.4.2 | yes | Unsupported File Type | apps/backend/tests/extraction/test_extraction_flow.py |
✅ |
| AC3.4.3 | yes | Extraction Timeout | apps/backend/tests/extraction/test_pdf_parsing.py |
✅ |
| AC3.5.1 | yes | Full Upload Flow | apps/backend/tests/extraction/test_extraction_flow.pyapps/backend/tests/extraction/test_pii_redaction_edge_cases.py |
✅ |
| AC3.5.2 | yes | File Size Limit | apps/backend/tests/extraction/test_pdf_parsing.py |
✅ |
| AC3.5.3 | yes | Model Selection Flow | apps/backend/tests/_ac_stubs/test_epic_03_stubs.py |
✅ |
| AC3.5.4 | yes | Extraction Flow Tests | apps/backend/tests/api/test_statements_router.pyapps/backend/tests/extraction/test_extraction_flow.py |
✅ |
| AC3.5.5 | yes | Statement Parsing Supervisor | apps/backend/tests/api/test_statements_router.pyapps/backend/tests/extraction/test_statements_error_paths.py |
✅ |
| AC3.5.6 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.7 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.8 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.9 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.10 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.11 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.12 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.13 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.14 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.15 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.16 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.17 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.18 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.19 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.20 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.21 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.22 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.23 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.24 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) | |
| AC3.5.25 | no | apps/backend/tests/api/test_statements_router.py |
✅ (optional) |
📋 EPIC-004: reconciliation-engine¶
- Total ACs: 39
- Mandatory ACs: 18
- Mandatory ACs with test reference: 18 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC4.1.1 | yes | Exact Matching | apps/backend/tests/api/test_reconciliation_router.pyapps/backend/tests/reconciliation/test_reconciliation_matching_unit.pyapps/backend/tests/reconciliation/test_reconciliation_scoring.pyscripts/tests/test_generate_ac_registry.py |
✅ |
| AC4.1.2 | yes | Fuzzy Date Matching | apps/backend/tests/api/test_reconciliation_router.pyapps/backend/tests/reconciliation/test_reconciliation_scoring.py |
✅ |
| AC4.1.3 | yes | Amount Tolerance | apps/backend/tests/api/test_reconciliation_router.pyapps/backend/tests/reconciliation/test_reconciliation_matching_unit.pyapps/backend/tests/reconciliation/test_reconciliation_scoring.py |
✅ |
| AC4.1.4 | yes | Description Similarity | apps/backend/tests/reconciliation/test_reconciliation_matching_unit.pyapps/backend/tests/reconciliation/test_reconciliation_scoring.py |
✅ |
| AC4.2.1 | yes | Many-to-One (Batch Payment) | apps/backend/tests/api/test_reconciliation_router.pyapps/backend/tests/reconciliation/test_reconciliation_engine.py |
✅ |
| AC4.2.2 | yes | Many-to-One Bonus | apps/backend/tests/api/test_reconciliation_router.py |
✅ |
| AC4.2.3 | yes | One-to-Many (Split) | apps/backend/tests/reconciliation/test_reconciliation_engine.py |
✅ |
| AC4.3.1 | yes | Auto-Accept Logic | apps/backend/tests/api/test_reconciliation_router.pyapps/backend/tests/reconciliation/test_reconciliation_dual_read.pyapps/backend/tests/reconciliation/test_reconciliation_engine.pyapps/backend/tests/reconciliation/test_review_queue.py |
✅ |
| AC4.3.2 | yes | Review Queue Logic | apps/backend/tests/api/test_reconciliation_router.pyapps/backend/tests/reconciliation/test_reconciliation_engine.py |
✅ |
| AC4.3.3 | yes | Batch Accept | apps/backend/tests/api/test_reconciliation_router.pyapps/backend/tests/reconciliation/test_reconciliation_router_additional.py |
✅ |
| AC4.3.4 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.5 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.6 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.7 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.8 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.9 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.10 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.11 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.12 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.13 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.14 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.3.15 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.4.1 | yes | Large Batch Performance (1,000 txns) | apps/backend/tests/reconciliation/test_performance.pyapps/backend/tests/reconciliation/test_reconciliation_layer4_read.py |
✅ |
| AC4.4.2 | yes | Cross-Period Matching | apps/backend/tests/reconciliation/test_performance.py |
✅ |
| AC4.5.1 | yes | Anomaly Detection Core | apps/backend/tests/api/test_reconciliation_router.pyapps/backend/tests/reconciliation/test_anomaly_detection.pyapps/backend/tests/reconciliation/test_reconciliation_engine.py |
✅ |
| AC4.5.2 | no | apps/backend/tests/api/test_reconciliation_router.py |
✅ (optional) | |
| AC4.6.1 | yes | 0.1 USD boundary: amount delta = 0.10 USD passes, 0.11 USD fails | apps/backend/tests/_ac_stubs/test_epic_04_stubs.py |
✅ |
| AC4.6.2 | yes | Transfer detection: matching OUT/IN within ±3 days not mis-reconciled | apps/backend/tests/_ac_stubs/test_epic_04_stubs.py |
✅ |
| AC4.6.3 | yes | source_type=manual wins over auto_matched in conflict | apps/backend/tests/_ac_stubs/test_epic_04_stubs.py |
✅ |
| AC4.6.4 | yes | Stage 2 batch approve blocked when duplicate flags unresolved | apps/backend/tests/_ac_stubs/test_epic_04_stubs.py |
✅ |
| AC4.6.5 | yes | Reconciliation score considers source_type weight (manual > auto) | apps/backend/tests/_ac_stubs/test_epic_04_stubs.py |
✅ |
| AC4.6.6 | no | apps/backend/tests/reconciliation/test_reconciliation_engine.py |
✅ (optional) | |
| AC4.6.7 | no | apps/backend/tests/reconciliation/test_reconciliation_engine.py |
✅ (optional) | |
| AC4.6.8 | no | apps/backend/tests/reconciliation/test_reconciliation_engine.py |
✅ (optional) | |
| AC4.6.9 | no | apps/backend/tests/reconciliation/test_reconciliation_engine.py |
✅ (optional) | |
| AC4.7.1 | no | apps/backend/tests/api/test_corrections_router.py |
✅ (optional) | |
| AC4.7.2 | no | apps/backend/tests/extraction/test_correction_service_cache.py |
✅ (optional) | |
| AC4.7.3 | no | apps/backend/tests/reconciliation/test_reconciliation_engine.py |
✅ (optional) | |
| AC4.7.4 | no | apps/backend/tests/reconciliation/test_reconciliation_engine.py |
✅ (optional) |
📋 EPIC-005: reporting-visualization¶
- Total ACs: 36
- Mandatory ACs: 25
- Mandatory ACs with test reference: 25 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC5.1.1 | yes | Accounting Equation | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reporting.pyscripts/tests/test_build_ac_traceability.pyscripts/tests/test_lint_doc_consistency.py |
✅ |
| AC5.1.2 | yes | FX Unrealized Gain | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reporting_fx.pyscripts/tests/test_lint_doc_consistency.py |
✅ |
| AC5.1.3 | yes | Multi-Currency Aggregation | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reporting_fx.py |
✅ |
| AC5.1.4 | yes | Endpoint Response | apps/backend/tests/reporting/test_reports_router.py |
✅ |
| AC5.2.1 | yes | Net Income Calculation | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reporting.py |
✅ |
| AC5.2.2 | yes | Comprehensive Income | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reporting_fx.py |
✅ |
| AC5.2.3 | yes | Date Range Filtering | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reporting.py |
✅ |
| AC5.3.1 | yes | Statement Generation | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reporting.py |
✅ |
| AC5.3.2 | yes | Empty Period Handling | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reporting.py |
✅ |
| AC5.3.3 | no | apps/backend/tests/api/test_reports_router.py |
✅ (optional) | |
| AC5.3.4 | no | apps/backend/tests/api/test_reports_router.py |
✅ (optional) | |
| AC5.3.5 | no | apps/backend/tests/api/test_reports_router.py |
✅ (optional) | |
| AC5.4.1 | yes | FX Fallbacks | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reporting_fx.py |
✅ |
| AC5.4.2 | yes | Balance Sheet Net Income FX Fallback | apps/backend/tests/reporting/test_reporting_fx.py |
✅ |
| AC5.5.1 | yes | Report Generation Error | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reports_router.pyapps/backend/tests/reporting/test_reports_router_errors.py |
✅ |
| AC5.5.2 | yes | Router Error Handling | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reports_errors.py |
✅ |
| AC5.5.3 | no | apps/backend/tests/api/test_reports_router.py |
✅ (optional) | |
| AC5.5.4 | no | apps/backend/tests/api/test_reports_router.pyapps/backend/tests/reporting/test_reports_router.py |
✅ (optional) | |
| AC5.5.5 | no | apps/backend/tests/api/test_reports_router.py |
✅ (optional) | |
| AC5.6.1 | yes | XIRR calculation accuracy ≤ 0.01% error vs Excel XIRR | apps/backend/tests/_ac_stubs/test_epic_05_stubs.py |
✅ |
| AC5.6.2 | yes | Annualized return (TWR) computed correctly | apps/backend/tests/_ac_stubs/test_epic_05_stubs.py |
✅ |
| AC5.6.3 | yes | Dividend yield = annual dividends / current value | apps/backend/tests/_ac_stubs/test_epic_05_stubs.py |
✅ |
| AC5.6.4 | yes | Annualized income in income statement KPI block | apps/backend/tests/_ac_stubs/test_epic_05_stubs.py |
✅ |
| AC5.6.5 | yes | Unrealized P&L reflected in balance sheet equity | apps/backend/tests/_ac_stubs/test_epic_05_stubs.py |
✅ |
| AC5.6.6 | yes | MWR (money-weighted return) matches XIRR for single cashflow | apps/backend/tests/_ac_stubs/test_epic_05_stubs.py |
✅ |
| AC5.6.7 | no | apps/backend/tests/reporting/test_reporting_extreme_fallbacks.py |
✅ (optional) | |
| AC5.6.8 | no | apps/backend/tests/reporting/test_reporting_extreme_fallbacks.py |
✅ (optional) | |
| AC5.6.9 | no | apps/backend/tests/reporting/test_reporting_extreme_fallbacks.py |
✅ (optional) | |
| AC5.6.10 | no | apps/backend/tests/reporting/test_reporting_extreme_fallbacks.py |
✅ (optional) | |
| AC5.6.11 | no | apps/backend/tests/reporting/test_reporting_extreme_fallbacks.py |
✅ (optional) | |
| AC5.7.1 | yes | Net worth time-series API endpoint GET /api/reports/net-worth/timeseries?from=YYYY-MM-DD&to=YYYY-MM-DD&granularity=month | apps/backend/tests/market_data/test_fx_service.pyapps/frontend/src/__tests__/uiGapAudit.netWorthTimeSeries.test.ts |
✅ |
| AC5.7.2 | yes | Net worth chart component on dashboard renders ECharts line chart with date X-axis and net-worth Y-axis | apps/backend/tests/market_data/test_fx_service.pyapps/frontend/src/__tests__/uiGapAudit.netWorthTimeSeries.test.ts |
✅ |
| AC5.7.3 | yes | Net worth time-series respects multi-currency: each point converted to base currency using historical FX rate per transaction-date rate rule |
apps/backend/tests/_ac_stubs/test_epic_05_stubs.pyapps/frontend/src/__tests__/uiGapAudit.netWorthTimeSeries.test.ts |
✅ |
| AC5.7.4 | yes | Time range selector (1M / 3M / 6M / 1Y / All) on dashboard toggles from parameter for chart | apps/backend/tests/_ac_stubs/test_epic_05_stubs.pyapps/frontend/src/__tests__/uiGapAudit.netWorthTimeSeries.test.ts |
✅ |
| AC5.7.5 | yes | Empty-state placeholder rendered when fewer than 2 data points exist (cannot draw line) | apps/backend/tests/_ac_stubs/test_epic_05_stubs.pyapps/frontend/src/__tests__/uiGapAudit.netWorthTimeSeries.test.ts |
✅ |
| AC5.7.6 | yes | Frontend unit test mounts NetWorthTimeSeries component and asserts chart container exists | apps/backend/tests/_ac_stubs/test_epic_05_stubs.pyapps/frontend/src/__tests__/uiGapAudit.netWorthTimeSeries.test.ts |
✅ |
📋 EPIC-006: ai-advisor¶
- Total ACs: 63
- Mandatory ACs: 55
- Mandatory ACs with test reference: 55 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC6.1.1 | yes | Prompt injection detection | apps/backend/tests/ai/test_ai_advisor_service.pyapps/backend/tests/ai/test_ai_models_edge_cases.py |
✅ |
| AC6.1.2 | yes | Sensitive information detection | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.1.3 | yes | Write request detection | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.1.4 | yes | Non-financial query detection | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.1.5 | yes | Prompt injection negative cases | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.2.1 | yes | Chinese language detection | apps/backend/tests/ai/test_ai_advisor_service.pyapps/backend/tests/ai/test_chat_edge_cases.pyapps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.2.2 | yes | English language detection | apps/backend/tests/ai/test_chat_edge_cases.pyapps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.2.3 | yes | Chinese suggestions | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.2.4 | yes | English suggestions | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.2.5 | yes | Auto-detect Chinese | apps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.2.6 | yes | Auto-detect English | apps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.3.1 | yes | Disclaimer appended once | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.3.2 | yes | Disclaimer respects existing | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.4.1 | yes | Get or create existing session | apps/backend/tests/ai/test_ai_advisor_service.pyapps/backend/tests/ai/test_models_repr.py |
✅ |
| AC6.4.2 | yes | Session not found raises error | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.4.3 | yes | Load history skips system messages | apps/backend/tests/ai/test_ai_advisor_service.pyapps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.4.4 | yes | Record message sets title | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.4.5 | yes | Delete session success | apps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.4.6 | yes | Delete session not found | apps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.5.1 | yes | Chat suggestions endpoint (EN) | apps/backend/tests/ai/test_ai_models_router.pyapps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.5.2 | yes | Chat suggestions endpoint (ZH) | apps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.5.3 | yes | Chat error handling - API unavailable | apps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.5.4 | yes | Chat error handling - session not found | apps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.5.5 | yes | Chat error handling - bad request | apps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.5.6 | yes | Chat with model name header | apps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.5.7 | yes | Chat without model name header | apps/backend/tests/ai/test_chat_router.py |
✅ |
| AC6.6.1 | yes | Response cache TTL | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.6.2 | yes | Response cache prune | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.6.3 | yes | Chat stream uses cached response | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.7.1 | yes | Stream API key fallback | apps/backend/tests/ai/test_ai_advisor_service.pyapps/backend/tests/ai/test_openrouter_streaming.py |
✅ |
| AC6.7.2 | yes | Stream raises when all fail | apps/backend/tests/ai/test_ai_advisor_service.pyapps/backend/tests/ai/test_openrouter_streaming.py |
✅ |
| AC6.7.3 | yes | Chat stream requires API key | apps/backend/tests/ai/test_ai_advisor_service.pyapps/backend/tests/ai/test_openrouter_streaming.py |
✅ |
| AC6.7.4 | yes | Stream redactor masks sensitive sequences | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.7.5 | yes | Stream redactor flushes tail | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.7.6 | yes | Stream redactor flush empty | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.7.7 | yes | Chat stream refusal branches | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.8.1 | yes | Financial context handles report errors | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.8.2 | yes | Financial context filters by user | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.8.3 | yes | Build refusal defaults to non-financial | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.8.4 | yes | Stream and store records response | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.9.1 | yes | Stream and store raises on stream error | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.9.2 | yes | Chat stream success path uses stream | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.10.1 | yes | Question normalization | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.10.2 | yes | Token estimation | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.10.3 | yes | Redact sensitive information | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.10.4 | yes | Chunk text splits text | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ |
| AC6.11.1 | yes | Model catalog integration | apps/backend/tests/ai/test_ai_models_integration.pyapps/backend/tests/ai/test_ai_models_router.pyapps/backend/tests/ai/test_models_repr.pyapps/backend/tests/ai/test_openrouter_models.pyapps/backend/tests/api/test_ai_models_router.py |
✅ |
| AC6.11.2 | yes | Model validation integration | apps/backend/tests/ai/test_ai_models_integration.pyapps/backend/tests/api/test_ai_models_router.py |
✅ |
| AC6.11.3 | yes | Model catalog caching | apps/backend/tests/ai/test_ai_models_integration.pyapps/backend/tests/ai/test_openrouter_models.pyapps/backend/tests/api/test_ai_models_router.py |
✅ |
| AC6.11.4 | no | apps/backend/tests/api/test_ai_models_router.py |
✅ (optional) | |
| AC6.11.5 | no | apps/backend/tests/api/test_ai_models_router.py |
✅ (optional) | |
| AC6.11.6 | no | apps/backend/tests/api/test_ai_models_router.py |
✅ (optional) | |
| AC6.12.1 | yes | AI cannot modify ledger | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.12.2 | yes | Answers based on real data | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.12.3 | yes | Clear disclaimer | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.12.4 | yes | Support Chinese & English | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.12.5 | yes | OpenRouter API error handling | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.12.6 | yes | Session isolation | apps/backend/tests/_ac_stubs/test_epic_06_stubs.py |
✅ |
| AC6.13.1 | no | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ (optional) | |
| AC6.13.2 | no | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ (optional) | |
| AC6.13.3 | no | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ (optional) | |
| AC6.13.4 | no | apps/backend/tests/ai/test_ai_advisor_service.py |
✅ (optional) | |
| AC6.13.6 | no | apps/backend/tests/ai/test_pii_redaction.py |
✅ (optional) |
📋 EPIC-007: deployment¶
- Total ACs: 39
- Mandatory ACs: 39
- Mandatory ACs with test reference: 39 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC7.1.1 | yes | Infra2 submodule exists | apps/backend/tests/_ac_stubs/test_epic_07_stubs.pyscripts/tests/test_generate_ac_registry.py |
✅ |
| AC7.1.2 | yes | Finance_report directory structure | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.1.3 | yes | README documentation exists | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.2.1 | yes | PostgreSQL container configured | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.2.2 | yes | Vault-agent sidecar present | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.2.3 | yes | Vault policy for postgres | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.2.4 | yes | Secrets template for postgres | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.2.5 | yes | PostgresDeployer class exists | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.3.1 | yes | Redis container configured | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.3.2 | yes | Vault-agent sidecar present | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.3.3 | yes | Vault policy for redis | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.3.4 | yes | Secrets template for redis | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.3.5 | yes | RedisDeployer class exists | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.4.1 | yes | App container configured | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.4.2 | yes | Vault-agent sidecar present | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.4.3 | yes | Vault policy for app | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.4.4 | yes | Secrets template for app | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.4.5 | yes | Traefik labels for domain | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.4.6 | yes | AppDeployer class exists | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.5.1 | yes | DATABASE_URL in Vault | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.5.2 | yes | REDIS_URL in Vault | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.5.3 | yes | S3_* keys in Vault | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.5.4 | yes | OPENROUTER_API_KEY in Vault | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.5.5 | yes | Vault tokens generated | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.6.1 | yes | Config syncs with .env.example | apps/backend/tests/infra/test_main.py |
✅ |
| AC7.6.2 | yes | Required secrets documented | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.7.1 | yes | Health endpoint returns 200 | apps/backend/tests/infra/test_main.py |
✅ |
| AC7.7.2 | yes | Health check with services down | apps/backend/tests/infra/test_main.py |
✅ |
| AC7.8.1 | yes | Moon CLI available | apps/backend/tests/infra/test_ci_config.py |
✅ |
| AC7.8.2 | yes | Docker compose integrity | apps/backend/tests/infra/test_ci_config.py |
✅ |
| AC7.8.3 | yes | Moon project graph valid | apps/backend/tests/infra/test_ci_config.py |
✅ |
| AC7.9.1 | yes | PostgreSQL healthy (manual) | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.9.2 | yes | Redis healthy (manual) | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.9.3 | yes | App healthy (manual) | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.9.4 | yes | Domain accessible (manual) | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.9.5 | yes | API functional (manual) | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.9.6 | yes | Secrets in Vault (manual) | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.9.7 | yes | Backend health endpoint | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
| AC7.9.8 | yes | Config contract validation | apps/backend/tests/_ac_stubs/test_epic_07_stubs.py |
✅ |
📋 EPIC-008: testing-strategy¶
- Total ACs: 61
- Mandatory ACs: 55
- Mandatory ACs with test reference: 55 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC8.1.1 | yes | API health check | apps/backend/tests/e2e/test_core_journeys.pyapps/backend/tests/unit/infra/test_test_lifecycle.py |
✅ |
| AC8.1.2 | yes | Backend service reachable | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.1.3 | yes | Frontend service reachable | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.1.4 | yes | Database connectivity | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.2.1 | yes | New User Registration | apps/backend/tests/e2e/test_auth_flows.pyapps/backend/tests/e2e/test_e2e_flows.pyapps/backend/tests/unit/infra/test_test_lifecycle.py |
✅ |
| AC8.2.2 | yes | Create Cash Account | apps/backend/tests/e2e/test_core_journeys.pyapps/backend/tests/unit/infra/test_test_lifecycle.py |
✅ |
| AC8.2.3 | yes | Create Bank Account | apps/backend/tests/e2e/test_auth_flows.pyapps/backend/tests/e2e/test_core_journeys.pyapps/backend/tests/unit/utils/test_security.py |
✅ |
| AC8.2.4 | yes | Update account | apps/backend/tests/auth/test_auth.pyapps/backend/tests/e2e/test_auth_flows.pyapps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.2.5 | yes | Delete account | apps/backend/tests/e2e/test_auth_flows.pyapps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.2.6 | no | apps/backend/tests/e2e/test_auth_flows.py |
✅ (optional) | |
| AC8.3.1 | yes | Simple Expense Entry | apps/backend/tests/e2e/test_core_journeys.pyapps/backend/tests/unit/infra/test_test_lifecycle.py |
✅ |
| AC8.3.2 | yes | Void Entry | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.3.3 | yes | Post Draft Entry | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.3.4 | yes | Unbalanced Entry Rejected | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.3.5 | yes | Journal Entry CRUD | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.4.1 | yes | Statement upload (CSV) | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.4.2 | yes | Statement list and get | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.4.3 | yes | Statement full flow | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.5.1 | yes | Reconciliation engine runs | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.5.2 | yes | Reconciliation stats endpoint | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.5.3 | yes | Match acceptance | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.6.1 | yes | View Balance Sheet | apps/backend/tests/e2e/test_core_journeys.pyapps/backend/tests/e2e/test_e2e_flows.py |
✅ |
| AC8.6.2 | yes | View Income Statement | apps/backend/tests/e2e/test_core_journeys.pyapps/backend/tests/e2e/test_e2e_flows.py |
✅ |
| AC8.6.3 | yes | View Cash Flow Report | apps/backend/tests/e2e/test_core_journeys.pyapps/backend/tests/e2e/test_e2e_flows.py |
✅ |
| AC8.6.4 | yes | Report navigation (all endpoints) | apps/backend/tests/e2e/test_core_journeys.pyapps/backend/tests/e2e/test_e2e_flows.py |
✅ |
| AC8.7.1 | yes | API authentication failures | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.7.2 | yes | Unauthorized access blocked | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.7.3 | yes | User session management | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.8.1 | yes | API health check | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.8.2 | yes | Accounts CRUD API | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.8.3 | yes | Journal entry lifecycle API | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.8.4 | yes | Reports API | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.8.5 | yes | Reconciliation API | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.9.1 | yes | PR workflow runs E2E tests | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.9.2 | yes | Smoke tests integrated | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.9.3 | yes | Critical test check | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.9.4 | yes | Environment isolation | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.10.1 | yes | Health endpoint reachable | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.10.2 | yes | User can create account | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.10.3 | yes | User can create journal entry | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.10.4 | yes | Statement upload triggers AI | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.10.5 | yes | Reconciliation engine runs | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.10.6 | yes | Unbalanced entry rejected | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.10.7 | yes | Reports API accessible | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.10.8 | yes | User registration flow | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.10.9 | yes | Authentication validation | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.11.1 | yes | Income Recording | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.11.2 | yes | Credit Card Spend | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.11.3 | yes | Credit Card Repayment | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.11.4 | yes | Internal Transfer | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.11.5 | yes | Split Transaction | apps/backend/tests/e2e/test_core_journeys.py |
✅ |
| AC8.12.1 | no | apps/backend/tests/reporting/test_fx_revaluation.py |
✅ (optional) | |
| AC8.12.2 | no | apps/backend/tests/reporting/test_fx_revaluation.py |
✅ (optional) | |
| AC8.12.3 | no | apps/backend/tests/reporting/test_fx_revaluation.py |
✅ (optional) | |
| AC8.12.4 | no | apps/backend/tests/extraction/test_extraction_error_paths.py |
✅ (optional) | |
| AC8.12.5 | no | apps/backend/tests/extraction/test_extraction_error_paths.py |
✅ (optional) | |
| AC8.13.1 | yes | DBS PDF upload → appears in list | apps/backend/tests/_ac_stubs/test_epic_08_stubs.py |
✅ |
| AC8.13.2 | yes | Polling → parsed status visible | apps/backend/tests/_ac_stubs/test_epic_08_stubs.py |
✅ |
| AC8.13.3 | yes | Detail page shows transactions | apps/backend/tests/_ac_stubs/test_epic_08_stubs.py |
✅ |
| AC8.13.4 | yes | Approve → status badge updates in-place on /statements/{id} (no redirect) | apps/backend/tests/_ac_stubs/test_epic_08_stubs.py |
✅ |
| AC8.13.5 | yes | Balance sheet report loads | apps/backend/tests/_ac_stubs/test_epic_08_stubs.py |
✅ |
📋 EPIC-009: pdf-fixture-generation¶
- Total ACs: 37
- Mandatory ACs: 36
- Mandatory ACs with test reference: 36 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC9.1.1 | yes | PDF analyzer exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.pyscripts/tests/test_generate_ac_registry.py |
✅ |
| AC9.1.2 | yes | Template extractor exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.1.3 | yes | CLI tool exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.1.4 | yes | DBS template exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.1.5 | yes | CMB template exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.1.6 | yes | Mari Bank template exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.2.1 | yes | Base generator class exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.2.2 | yes | DBS generator exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.2.3 | yes | CMB generator exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.2.4 | yes | Mari Bank generator exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.2.5 | yes | Font utilities exist | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.2.6 | yes | Fake data generator exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.2.7 | yes | Main script exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.3.1 | yes | Format validator exists | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.3.2 | yes | Generated DBS PDF parseable | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.3.3 | yes | Generated CMB PDF parseable | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.3.4 | yes | Generated Mari PDF parseable | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.3.5 | yes | Balance calculations correct | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.3.6 | yes | Date formats correct | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.3.7 | no | scripts/tests/test_pdf_fixture_parseable.py |
✅ (optional) | |
| AC9.4.1 | yes | Format analysis README | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.4.2 | yes | Generation README | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.4.3 | yes | Template format specification | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.4.4 | yes | Usage examples | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.5.1 | yes | .gitignore excludes real PDFs | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.5.2 | yes | Format templates committed | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.5.3 | yes | Generators committed | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.5.4 | yes | Analyzers committed | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.5.5 | yes | Validators committed | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.6.1 | yes | DBS generator loads template | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.6.2 | yes | CMB generator loads template | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.6.3 | yes | CMB generator supports Chinese fonts | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.6.4 | yes | Mari generator generates interest section | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.6.5 | yes | Generators use fictional data | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.7.1 | yes | Main script supports --source parameter | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.7.2 | yes | Main script supports --output parameter | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
| AC9.7.3 | yes | Analyzer CLI supports input/output | apps/backend/tests/_ac_stubs/test_epic_09_stubs.py |
✅ |
📋 EPIC-010: signoz-logging¶
- Total ACs: 21
- Mandatory ACs: 21
- Mandatory ACs with test reference: 21 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC10.1.1 | yes | OTEL settings in config | apps/backend/tests/_ac_stubs/test_epic_10_stubs.pyscripts/tests/test_generate_ac_registry.py |
✅ |
| AC10.1.2 | yes | Optional OTLP log export configured | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.1.3 | yes | Fallback to stdout when OTEL vars absent | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.2.2 | yes | Build OTLP endpoint preserves logs path | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.4.1 | yes | Configure OTEL logging warns on missing dependency | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.4.2 | yes | Configure OTEL logging with fake exporter | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.5.1 | yes | Observability SSOT exists | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.5.2 | yes | SSOT linked in index | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.5.3 | yes | OTEL vars documented in .env.example | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.5.4 | yes | OTEL vars documented in config.py | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.6.1 | yes | OTEL keys in app secrets template | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.6.2 | yes | OTEL keys documented in app README | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.6.3 | yes | IAC_CONFIG_HASH in compose.yaml | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.6.4 | yes | Template helpers use printf not default | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.7.1 | yes | Backend starts without SigNoz | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.7.2 | yes | Logs export to SigNoz | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.7.3 | yes | No sensitive data in logs | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.7.4 | yes | OTLP optional by default | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.7.5 | yes | OTEL config documented | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.7.6 | yes | Vault templates include OTEL keys | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
| AC10.7.7 | yes | Structured JSON logs in non-debug | apps/backend/tests/_ac_stubs/test_epic_10_stubs.py |
✅ |
📋 EPIC-011: asset-lifecycle¶
- Total ACs: 34
- Mandatory ACs: 34
- Mandatory ACs with test reference: 34 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC11.1.1 | yes | Reconcile creates new position | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.2 | yes | Reconcile updates existing position quantity | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.3 | yes | Reconcile disposes position when quantity is 0 | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.4 | yes | Cost basis is set from market_value | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.5 | yes | Reconcile multiple different assets | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.6 | yes | Same asset at different brokers creates separate positions | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.7 | yes | Null broker name handled correctly | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.8 | yes | Disposed position can be reactivated | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.9 | yes | Get positions returns empty list when no positions exist | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.10 | yes | Reconcile with no snapshots does nothing | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.11 | yes | Negative quantities (short positions) handled correctly | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.1.12 | yes | Updated and disposed counts are mutually exclusive | apps/backend/tests/assets/test_asset_service.py |
✅ |
| AC11.2.1 | yes | GET /assets/positions returns empty list when no positions | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.2.2 | yes | GET /assets/positions returns positions with data | apps/backend/tests/assets/test_assets_router.pyapps/backend/tests/assets/test_assets_router_edge_cases.py |
✅ |
| AC11.2.3 | yes | GET /assets/positions filters by status correctly | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.3.1 | yes | GET /assets/positions/{id} returns position details | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.3.2 | yes | GET /assets/positions/{id} returns 404 for non-existent position | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.3.3 | yes | GET /assets/positions/{id} returns 404 for other user's position | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.4.1 | yes | POST /assets/reconcile creates positions from snapshots | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.4.2 | yes | POST /assets/reconcile with no snapshots returns 0 counts | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.5.1 | yes | GET /assets/positions requires authentication | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.5.2 | yes | GET /assets/positions/{id} requires authentication | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.5.3 | yes | POST /assets/reconcile requires authentication | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.6.1 | yes | GET /assets/positions/{id}/depreciation returns depreciation schedule | apps/backend/tests/assets/test_asset_depreciation.pyapps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.6.2 | yes | GET /assets/positions/{id}/depreciation returns 400 for non-existent position | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.6.3 | yes | GET /assets/positions/{id}/depreciation returns 400 for disposed position | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.6.4 | yes | GET /assets/positions/{id}/depreciation returns 422 for invalid params | apps/backend/tests/assets/test_asset_depreciation.pyapps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.7.1 | yes | Verify position queries are isolated by user_id | apps/backend/tests/assets/test_assets_router.py |
✅ |
| AC11.8.1 | yes | API endpoint GET /api/income/annualized returns {annualized_salary, annualized_bonus, annualized_dividend, annualized_total, currency, as_of} derived from last 12 months of Income-type journal entries |
apps/backend/tests/_ac_stubs/test_epic_11_stubs.pyapps/frontend/src/__tests__/uiGapAudit.annualizedIncome.test.ts |
✅ |
| AC11.8.2 | yes | Dashboard "Annualized Income" card renders the four annualized figures with the currency code and as_of date subtitle | apps/backend/tests/_ac_stubs/test_epic_11_stubs.pyapps/frontend/src/__tests__/uiGapAudit.annualizedIncome.test.ts |
✅ |
| AC11.8.3 | yes | API endpoint GET /api/assets/restricted returns ESOP/RSU/locked holdings with {ticker, quantity, vesting_schedule, unlock_date, fair_value} |
apps/backend/tests/_ac_stubs/test_epic_11_stubs.pyapps/frontend/src/__tests__/uiGapAudit.annualizedIncome.test.ts |
✅ |
| AC11.8.4 | yes | Dashboard "Restricted Holdings" card lists restricted holdings separated from liquid net worth, with vesting timeline tooltip | apps/backend/tests/_ac_stubs/test_epic_11_stubs.pyapps/frontend/src/__tests__/uiGapAudit.annualizedIncome.test.ts |
✅ |
| AC11.8.5 | yes | Net worth calculation toggle on dashboard (include_restricted=true | apps/backend/tests/_ac_stubs/test_epic_11_stubs.pyapps/frontend/src/__tests__/uiGapAudit.annualizedIncome.test.ts |
✅ |
| AC11.8.6 | yes | Frontend test mounts AnnualizedIncomeCard and asserts the four metric labels render | apps/backend/tests/_ac_stubs/test_epic_11_stubs.pyapps/frontend/src/__tests__/uiGapAudit.annualizedIncome.test.ts |
✅ |
📋 EPIC-012: foundation-libs¶
- Total ACs: 62
- Deprecated ACs: 3
- Mandatory ACs: 55
- Mandatory ACs with test reference: 55 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC12.1.1 | yes | OTEL logs endpoint adds suffix /v1/logs | apps/backend/tests/infra/test_logger.pyscripts/tests/test_generate_ac_registry.pyscripts/tests/test_lint_doc_consistency.py |
✅ |
| AC12.1.2 | yes | OTEL logs endpoint preserves logs path with /v1/logs | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.2.1 | yes | Debug mode uses ConsoleRenderer | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.2.2 | yes | Production mode uses JSONRenderer | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.3.1 | yes | OTEL logging not available logs warning | apps/backend/tests/ai/test_commit_boundary.pyapps/backend/tests/infra/test_logger.py |
✅ |
| AC12.3.2 | yes | OTEL tracing not available logs warning | apps/backend/tests/ai/test_commit_boundary.pyapps/backend/tests/infra/test_logger.py |
✅ |
| AC12.3.3 | yes | OTEL logging with no endpoint skips setup | apps/backend/tests/ai/test_commit_boundary.pyapps/backend/tests/infra/test_logger.py |
✅ |
| AC12.4.1 | yes | OTEL configuration sets up TracerProvider correctly | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.5.1 | yes | OTEL resource created with correct attributes | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.6.1 | yes | Sync log_timing logs operation with timing | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.6.2 | yes | Async log_timing includes additional context | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.6.3 | yes | log_timing yields mutable dict | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.6.4 | yes | log_timing with custom level | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.7.1 | yes | Sync external API call logs success | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.7.2 | yes | Sync external API call logs failure | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.7.3 | yes | Async external API call logs success | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.7.4 | yes | Async external API call logs failure | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.7.5 | yes | Sync external API with log_args=True logs args count | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.8.1 | yes | Log exception logs error with context | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.8.2 | yes | Log exception includes extra context fields | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.8.3 | yes | Log exception without traceback | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.8.4 | yes | Log exception with custom level | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.10.1 | yes | Build processors returns list | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.11.1 | yes | Trace context injects trace_id and span_id when span is valid | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.11.2 | yes | Trace context skips injection when span context is invalid | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.11.3 | yes | Trace context handles missing opentelemetry gracefully | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.12.1 | yes | OTEL tracing skips setup when no endpoint configured | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.12.2 | yes | TracerProvider created and resource attributes set | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.12.3 | yes | Traces path appends /v1/traces | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.15.1 | yes | Configure logging in debug mode | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.15.2 | yes | Configure logging in production mode | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.16.1 | yes | Async log_timing logs operation with timing | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.16.2 | yes | Async log_timing includes additional context | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.17.1 | yes | External API async with log_args=True logs args count | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.17.2 | yes | External API async failure with log_args=True logs args | apps/backend/tests/infra/test_logger.py |
✅ |
| AC12.18.1 | yes | Ensure PRIMARY_MODEL follows expected pattern | apps/backend/tests/infra/test_config_contract.py |
✅ |
| AC12.18.2 | yes | Ensure config.py default matches .env.example documentation | apps/backend/tests/infra/test_config_contract.py |
✅ |
| AC12.18.3 | yes | Ensure BASE_CURRENCY is valid ISO 4217 currency code | apps/backend/tests/infra/test_config_contract.py |
✅ |
| AC12.18.4 | yes | Ensure S3_BUCKET follows naming conventions | apps/backend/tests/infra/test_config_contract.py |
✅ |
| AC12.18.5 | yes | Ensure JWT_ALGORITHM is secure algorithm | apps/backend/tests/infra/test_config_contract.py |
✅ |
| AC12.18.6 | yes | Ensure DATABASE_URL follows expected format | apps/backend/tests/infra/test_config_contract.py |
✅ |
| AC12.18.7 | no | apps/backend/tests/reconciliation/test_reconciliation_scoring_helpers.py |
✅ (optional) | |
| AC12.19.1 | yes | Moon workspace configuration files exist | apps/backend/tests/_ac_stubs/test_epic_12_stubs.py |
✅ |
| AC12.20.1 | yes | DB_POOL_SIZE config field exists with default | apps/backend/tests/infra/test_config_contract.py |
✅ |
| AC12.20.2 | yes | DB_MAX_OVERFLOW config field exists with default | apps/backend/tests/infra/test_config_contract.py |
✅ |
| AC12.20.3 | yes | Pool config is positive integer | apps/backend/tests/infra/test_config_contract.py |
✅ |
| AC12.20.4 | no | apps/backend/tests/infra/test_config_contract.py |
✅ (optional) | |
| AC12.20.5 | no | apps/backend/tests/infra/test_config_contract.py |
✅ (optional) | |
| AC12.21.1 | yes | BaseAppException has error_id attribute | apps/backend/tests/infra/test_exceptions.py |
✅ |
| AC12.21.2 | yes | BaseAppException has status_code attribute | apps/backend/tests/infra/test_exceptions.py |
✅ |
| AC12.21.3 | yes | BaseAppException is subclass of Exception | apps/backend/tests/infra/test_exceptions.py |
✅ |
| AC12.21.4 | yes | BaseAppException can be raised and caught | apps/backend/tests/infra/test_exceptions.py |
✅ |
| AC12.21.5 | no | apps/backend/tests/infra/test_exceptions.py |
✅ (optional) | |
| AC12.22.1 | yes | Move 6 inline schemas from statements router to review module | apps/backend/tests/_ac_stubs/test_epic_12_stubs.py |
✅ |
| AC12.22.2 | yes | Extract background task schemas from inline/background definitions into dedicated modules | apps/backend/tests/_ac_stubs/test_epic_12_stubs.py |
✅ |
| AC12.23.1 | yes | Global rate limit middleware exempts /health | apps/backend/tests/_ac_stubs/test_epic_12_stubs.py |
✅ |
| AC12.23.2 | yes | Global rate limit middleware returns 429 after limit exceeded | apps/backend/tests/_ac_stubs/test_epic_12_stubs.py |
✅ |
| AC12.23.3 | yes | Global rate limit middleware allows normal requests | apps/backend/tests/_ac_stubs/test_epic_12_stubs.py |
✅ |
| AC12.23.4 | yes | Global rate limit middleware exempts /docs | apps/backend/tests/_ac_stubs/test_epic_12_stubs.py |
✅ |
| AC12.24.1 | deprecated | ~~/metrics endpoint returns 200 OK~~ | n/a | 🚫 deprecated |
| AC12.24.2 | deprecated | ~~/metrics endpoint returns text/plain~~ | n/a | 🚫 deprecated |
| AC12.24.3 | deprecated | ~~/metrics response contains Prometheus data~~ | n/a | 🚫 deprecated |
📋 EPIC-013: statement-parsing-v2¶
- Total ACs: 60
- Mandatory ACs: 58
- Mandatory ACs with test reference: 58 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC13.1.1 | yes | Test that valid balances pass validation | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.1.2 | yes | Test that invalid balances fail validation | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.1.3 | yes | Test that small differences are tolerated | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.2.1 | yes | Test that complete data gets high confidence (Auto-Accept) | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.2.2 | yes | Test that partial data gets medium confidence (Review) | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.2.3 | yes | Test that no transactions lowers confidence (Manual) | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.3.1 | yes | Test DBS fixture has correct structure | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.3.2 | yes | Test DBS fixture balances reconcile | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.3.3 | yes | Test MariBank fixture has sanitized merchant names | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.3.4 | yes | Test GXS fixture has daily interest entries | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.3.5 | yes | Test all fixtures have valid dates | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.4.1 | yes | Test default parsing prompt | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.4.2 | yes | Test DBS-specific prompt | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.4.3 | yes | Test CMB-specific prompt | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.4.4 | yes | Test with unknown institution returns base prompt | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.4.5 | yes | Test Futu-specific prompt | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.4.6 | yes | Test GXS-specific prompt | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.4.7 | yes | Test MariBank-specific prompt | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.5.1 | yes | Test that PDFs use OpenRouter 'file' type | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.5.2 | yes | Test that PNG images use 'image_url' type | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.5.3 | yes | Test that JPG images use 'image_url' type | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.5.4 | yes | Test that JPEG images use 'image_url' type | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.6.1 | yes | Test that CSV parsing raises error when institution is None | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.6.2 | yes | Test that parse_document accepts institution=None for PDFs (AI auto-detect) | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.6.3 | yes | Test that parse_document accepts force_model parameter | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.1 | yes | Test event confidence with complete data | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.2 | yes | Test event confidence with missing fields | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.3 | yes | Test event confidence with invalid date format | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.4 | yes | Test event confidence with null date | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.5 | yes | Test _safe_date with valid input | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.6 | yes | Test _safe_date with invalid format | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.7 | yes | Test _safe_date with empty input | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.8 | yes | Test _safe_decimal with valid input | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.9 | yes | Test _safe_decimal with invalid input | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.10 | yes | Test _safe_decimal with None | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.11 | yes | Test _safe_decimal None required | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.7.12 | yes | Test compute_confidence with missing transactions key | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.1 | yes | Test consistent chain scores 10 | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.2 | yes | Test inconsistent chain scores 0 | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.3 | yes | Test single transaction | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.4 | yes | Test no balance after | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.5 | yes | Test empty list | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.6 | yes | Test partial consistency | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.7 | yes | Test all currencies match | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.8 | yes | Test no currencies match | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.9 | yes | Test no header currency | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.10 | yes | Test no currencies in transactions | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.11 | yes | Test empty list (currency) | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.12 | yes | Test mixed currencies partial | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.8.13 | yes | Test missing currencies penalized | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.9.1 | yes | Test full score with all factors | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.9.2 | yes | Test no new factors caps at 85 | apps/backend/tests/extraction/test_extraction.py |
✅ |
| AC13.10.1 | yes | Source type stamped on manual entry creation | apps/backend/tests/_ac_stubs/test_epic_13_stubs.py |
✅ |
| AC13.10.2 | yes | Auto-match sets source_type=auto_matched | apps/backend/tests/_ac_stubs/test_epic_13_stubs.py |
✅ |
| AC13.10.3 | yes | Stage-1 approve promotes to user_confirmed | apps/backend/tests/_ac_stubs/test_epic_13_stubs.py |
✅ |
| AC13.10.4 | yes | Manual entry wins over auto_parsed in conflict | apps/backend/tests/_ac_stubs/test_epic_13_stubs.py |
✅ |
| AC13.10.5 | yes | source_type cannot be downgraded | apps/backend/tests/_ac_stubs/test_epic_13_stubs.py |
✅ |
| AC13.10.6 | yes | All four source_type values accepted by API | apps/backend/tests/_ac_stubs/test_epic_13_stubs.py |
✅ |
| AC13.11.1 | no | apps/backend/tests/extraction/test_extraction_error_paths.py |
✅ (optional) | |
| AC13.11.2 | no | apps/backend/tests/extraction/test_deduplication.py |
✅ (optional) |
📋 EPIC-014: ttd-transformation¶
- Total ACs: 6
- Mandatory ACs: 6
- Mandatory ACs with test reference: 6 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC14.1.1 | yes | Backend coverage ≥ 90% enforced locally via pyproject.toml (CI uses --cov-fail-under=0; target: 99%; local pre-push enfo | apps/backend/tests/_ac_stubs/test_epic_14_stubs.py |
✅ |
| AC14.1.2 | yes | Pre-commit mypy hook blocks type errors before commit | apps/backend/tests/_ac_stubs/test_epic_14_stubs.py |
✅ |
| AC14.1.3 | yes | validate_schemas.py exits non-zero when Pydantic fields lack Field() descriptions | apps/backend/tests/_ac_stubs/test_epic_14_stubs.py |
✅ |
| AC14.1.4 | yes | check_env_keys.py detects missing keys across secrets.ctmpl, config.py, .env.example | apps/backend/tests/_ac_stubs/test_epic_14_stubs.py |
✅ |
| AC14.1.5 | yes | smoke_test.sh runs successfully against local docker environment | apps/backend/tests/_ac_stubs/test_epic_14_stubs.py |
✅ |
| AC14.1.6 | yes | generate_ac_registry.py produces zero ghost ACs and zero overlap between feature and infra registries | apps/backend/tests/_ac_stubs/test_epic_14_stubs.py |
✅ |
📋 EPIC-015: processing-account¶
- Total ACs: 27
- Mandatory ACs: 27
- Mandatory ACs with test reference: 27 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC15.1.1 | yes | Processing Account Created | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.1.2 | yes | Idempotent Creation | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.1.3 | yes | Hidden from User Accounts | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.1.4 | yes | Per-User Isolation | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.2.1 | yes | Transfer OUT Entry | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.2.2 | yes | Transfer IN Entry | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.2.3 | yes | Paired Transfers Zero Balance | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.3.1 | yes | Unpaired Transfer Visible | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.3.2 | yes | Accounting Equation Holds | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.4.1 | yes | Keyword Detection | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.4.2 | yes | Non-Transfer Detection | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.4.3 | yes | Auto-Pairing Above Threshold | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.5.1 | yes | Amount Scoring (Exact) | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.5.2 | yes | Amount Scoring (Tiers) | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.5.3 | yes | Description Scoring | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.5.4 | yes | Date Scoring | apps/backend/tests/accounting/test_processing_account.py |
✅ |
| AC15.6.1 | yes | Transfer Detection During Reconciliation | apps/backend/tests/reconciliation/test_transfer_integration.py |
✅ |
| AC15.6.2 | yes | Transfer Detection Skips (No Account) | apps/backend/tests/reconciliation/test_transfer_integration.py |
✅ |
| AC15.6.3 | yes | Transfer IN Detection | apps/backend/tests/reconciliation/test_transfer_integration.py |
✅ |
| AC15.6.4 | yes | Auto-Pairing Phase | apps/backend/tests/reconciliation/test_transfer_integration.py |
✅ |
| AC15.6.5 | yes | Unpaired Transfer Balance | apps/backend/tests/reconciliation/test_transfer_integration.py |
✅ |
| AC15.6.6 | yes | Normal Matching Preserved | apps/backend/tests/reconciliation/test_transfer_integration.py |
✅ |
| AC15.7.1 | yes | API endpoint GET /api/accounts/processing/summary returns | apps/backend/tests/_ac_stubs/test_epic_15_stubs.pyapps/frontend/src/__tests__/uiGapAudit.processingVisibility.test.tsx |
✅ |
| AC15.7.2 | yes | Dashboard "Processing / In-Transit" card renders the four fields with currency code | apps/backend/tests/_ac_stubs/test_epic_15_stubs.pyapps/frontend/src/__tests__/uiGapAudit.processingVisibility.test.tsx |
✅ |
| AC15.7.3 | yes | 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} |
apps/backend/tests/_ac_stubs/test_epic_15_stubs.pyapps/frontend/src/__tests__/uiGapAudit.processingVisibility.test.tsx |
✅ |
| AC15.7.4 | yes | Pending entries older than 7 days render a warning badge on the listing row | apps/backend/tests/_ac_stubs/test_epic_15_stubs.pyapps/frontend/src/__tests__/uiGapAudit.processingVisibility.test.tsx |
✅ |
| AC15.7.5 | yes | Frontend test mounts ProcessingSummaryCard and asserts pending_count + pending_total labels render | apps/backend/tests/_ac_stubs/test_epic_15_stubs.pyapps/frontend/src/__tests__/uiGapAudit.processingVisibility.test.tsx |
✅ |
📋 EPIC-016: two-stage-review-ui¶
- Total ACs: 210
- Mandatory ACs: 186
- Mandatory ACs with test reference: 186 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC16.1.1 | yes | Balance validation tolerance = 0.001 USD | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyscripts/tests/test_generate_ac_registry.py |
✅ |
| AC16.1.2 | yes | Stage 1 UI shows PDF + parsed split view | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.1.3 | yes | Approve button disabled if balance invalid | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.2.1 | yes | Deduplication detection accuracy ≥ 95% | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.2.2 | yes | Transfer pair detection accuracy ≥ 90% | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.2.3 | yes | Batch approve blocked if unresolved checks | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.2.4 | yes | Stage 2 UI supports batch operations | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.3.1 | yes | validate_balance_chain raises ValueError when statement not found | apps/backend/tests/review/test_statement_validation.pyscripts/tests/test_generate_ac_registry.py |
✅ |
| AC16.3.2 | yes | _get_opening_balance falls back to opening_balance when no prev statement exists | apps/backend/tests/review/test_statement_validation.pyscripts/tests/test_calculate_unified_coverage.py |
✅ |
| AC16.3.3 | yes | _get_opening_balance uses prev statement closing_balance when available | apps/backend/tests/review/test_statement_validation.py |
✅ |
| AC16.3.4 | yes | reject_statement without reason clears validation_error | apps/backend/tests/review/test_statement_validation.py |
✅ |
| AC16.3.5 | yes | edit_and_approve raises ValueError when balance is still invalid after edits | apps/backend/tests/review/test_statement_validation.py |
✅ |
| AC16.3.6 | yes | _get_statement_for_update raises ValueError when wrong user_id supplied | apps/backend/tests/review/test_statement_validation.py |
✅ |
| AC16.4.1 | yes | detect_duplicates runs global scan when no statement_id provided | apps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC16.4.2 | yes | detect_duplicates is idempotent — does not create duplicate checks on re-run | apps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC16.4.3 | yes | detect_transfer_pairs runs global scan when no statement_id provided | apps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC16.4.4 | yes | resolve_check raises ValueError on invalid action | apps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC16.4.5 | yes | resolve_check raises ValueError when check not found or belongs to wrong user | apps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC16.4.6 | yes | resolve_check sets FLAGGED status when action=flag | apps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC16.4.7 | yes | get_pending_checks filters results by severity | apps/backend/tests/review/test_consistency_checks.py |
✅ |
| AC16.5.1 | yes | getUserId returns null when not set | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.5.2 | yes | getUserId returns stored userId from localStorage | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/auth.test.ts |
✅ |
| AC16.5.3 | yes | setUser stores userId, email, and optional token | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/auth.test.ts |
✅ |
| AC16.5.4 | yes | clearUser removes all auth keys from localStorage | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/auth.test.ts |
✅ |
| AC16.5.5 | yes | isAuthenticated returns false when no token, true when token exists | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/auth.test.ts |
✅ |
| AC16.6.1 | yes | formatDateInput formats Date as YYYY-MM-DD with zero-padded month and day | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/date.test.ts |
✅ |
| AC16.6.2 | no | apps/frontend/src/__tests__/date.test.ts |
✅ (optional) | |
| AC16.6.3 | no | apps/frontend/src/__tests__/date.test.ts |
✅ (optional) | |
| AC16.6.4 | no | apps/frontend/src/__tests__/date.test.ts |
✅ (optional) | |
| AC16.7.1 | yes | getTheme returns stored value or system preference | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/theme.test.ts |
✅ |
| AC16.7.2 | yes | setTheme adds/removes dark CSS class and saves to localStorage | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/theme.test.ts |
✅ |
| AC16.7.3 | yes | toggleTheme switches between dark and light | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/theme.test.ts |
✅ |
| AC16.7.4 | yes | initTheme applies stored or system theme on load | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/theme.test.ts |
✅ |
| AC16.8.1 | yes | fetchAiModels calls /api/ai/models with no params when no options provided | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/aiModels.test.ts |
✅ |
| AC16.8.2 | yes | fetchAiModels appends modality query param when provided | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/aiModels.test.ts |
✅ |
| AC16.8.3 | yes | fetchAiModels appends free_only=true when freeOnly is set | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/aiModels.test.ts |
✅ |
| AC16.9.1 | yes | useCurrencies returns default currencies while loading | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/useCurrencies.test.tsx |
✅ |
| AC16.9.2 | yes | useCurrencies updates currencies from API response | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/useCurrencies.test.tsx |
✅ |
| AC16.9.3 | yes | useCurrencies falls back to defaults on API error | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/useCurrencies.test.tsx |
✅ |
| AC16.10.1 | yes | apiFetch returns JSON on 200 response | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.2 | yes | apiFetch returns undefined on 204 No Content | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.3 | yes | apiFetch throws error with detail message on non-ok response | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.4 | yes | apiFetch throws on non-JSON error text | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.5 | yes | apiFetch calls handle401Redirect on 401 response | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.10.6 | yes | resetRedirectGuard resets the redirect guard state | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.7 | yes | apiDelete succeeds on 200 response | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.8 | yes | apiDelete throws on non-ok response | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.9 | yes | apiStream returns response and sessionId on success | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.10 | yes | apiStream throws on non-ok response | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.11 | yes | apiUpload returns JSON on 200 response | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.12 | yes | apiUpload returns undefined on 204 No Content | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.13 | yes | apiFetch normalizes path without leading slash | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.14 | yes | apiFetch includes Authorization header when token is present | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiFunctions.test.ts |
✅ |
| AC16.10.15 | no | apps/frontend/src/__tests__/apiFunctions.test.ts |
✅ (optional) | |
| AC16.10.16 | no | apps/frontend/src/__tests__/apiFunctions.test.ts |
✅ (optional) | |
| AC16.10.17 | no | apps/frontend/src/__tests__/apiFunctions.test.ts |
✅ (optional) | |
| AC16.10.18 | no | apps/frontend/src/__tests__/apiFunctions.test.ts |
✅ (optional) | |
| AC16.10.19 | no | apps/frontend/src/__tests__/apiFunctions.test.ts |
✅ (optional) | |
| AC16.11.1 | yes | debug — detect_environment returns CI when GITHUB_ACTIONS is true | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyscripts/tests/test_generate_ac_registry.py |
✅ |
| AC16.11.2 | yes | debug — detect_environment returns LOCAL when docker ps succeeds | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.3 | yes | debug — detect_environment falls back to PRODUCTION on docker failure | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.4 | yes | debug — validate_hostname rejects empty and leading-hyphen hostnames | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.5 | yes | debug — validate_username enforces unix-safe pattern | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.6 | yes | debug — get_container_name maps known service names by environment | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.7 | yes | debug — list_containers prints all mapped containers for an environment | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.8 | yes | cleanup_orphaned_dbs — extract_namespace handles worker suffix and invalid names | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.9 | yes | cleanup_orphaned_dbs — load_active_namespaces returns [] when file missing or corrupt | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.10 | yes | cleanup_orphaned_dbs — get_container_runtime returns first available runtime | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.11 | yes | cleanup_orphaned_dbs — list_test_databases parses psql output and handles subprocess errors | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.12 | yes | cleanup_orphaned_dbs — cleanup_orphaned returns error when runtime missing | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.13 | yes | cleanup_orphaned_dbs — cleanup_orphaned returns success when no test databases found | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.14 | yes | cleanup_orphaned_dbs — cleanup_orphaned skips active namespace databases | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.15 | yes | cleanup_orphaned_dbs — cleanup_orphaned cleans all databases in --all mode | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.16 | yes | cli — get_compose_cmd prefers podman then docker and exits when unavailable | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.17 | yes | cli — cmd_test routes frontend/e2e/perf/tests and lifecycle modes correctly | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.18 | yes | cli — cmd_clean routes db/containers/default cleanup targets correctly | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.19 | yes | dev_backend — check_database_ready returns false on migration subprocess errors | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.20 | yes | dev_frontend — cleanup terminates tracked process and exits cleanly | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.21 | yes | debug — view_remote_logs_docker exits when VPS_HOST is missing | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.22 | yes | debug — view_remote_logs_docker exits on invalid VPS hostnames | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.23 | yes | debug — view_remote_logs_docker exits on invalid VPS usernames | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.24 | yes | debug — view_local_logs builds docker logs command with tail and follow | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.25 | yes | debug — main routes logs command to signoz handler when method=signoz | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.26 | yes | debug — main routes status command to local log view with status tail | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.27 | yes | debug — main routes containers command to list_containers | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.28 | yes | dev_backend — check_database_ready returns true when migration subprocess succeeds | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.29 | yes | dev_backend — cleanup terminates tracked process and exits cleanly | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.30 | yes | cleanup_orphaned_dbs — drop_database returns true in dry-run mode | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.31 | yes | cleanup_orphaned_dbs — main forwards parsed flags to cleanup_orphaned | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.11.32 | yes | Vitest harness for Stage 1 split components — shared renderReviewComponent() helper in apps/frontend/src/tests/helpe | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/uiGapAudit.stage1Refactor.test.ts |
✅ |
| AC16.11.33 | yes | Playwright smoke covers inline-edit happy path on Stage 1 (open review → edit amount → save → assert persisted) | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/uiGapAudit.stage1Refactor.test.ts |
✅ |
| AC16.12.1 | yes | Dashboard page shows loading state before API responses resolve | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/dashboardPage.test.tsx |
✅ |
| AC16.12.2 | yes | Dashboard page renders error fallback and retry action when API request fails | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/dashboardPage.test.tsx |
✅ |
| AC16.12.3 | yes | Dashboard page renders KPI, charts, and recent activity when API requests succeed | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/dashboardPage.test.tsx |
✅ |
| AC16.12.4 | yes | Dashboard page renders empty-state copy when trend or activity datasets are empty | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/dashboardPage.test.tsx |
✅ |
| AC16.12.5 | yes | Login page submits login payload and redirects on success | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/loginPage.test.tsx |
✅ |
| AC16.12.6 | yes | Login page toggles register mode and switches endpoint for submit | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/loginPage.test.tsx |
✅ |
| AC16.12.7 | yes | Login page shows API error messages and resets loading state on failure | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/loginPage.test.tsx |
✅ |
| AC16.12.8 | yes | Ping-pong page loads initial state and displays current ping/pong value | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/pingPongPage.test.tsx |
✅ |
| AC16.12.9 | yes | Ping-pong page toggles state and updates toggle count on button click | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/pingPongPage.test.tsx |
✅ |
| AC16.12.10 | yes | Ping-pong page renders retry flow when initial load fails | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/pingPongPage.test.tsx |
✅ |
| AC16.12.11 | yes | Reports page renders all report cards with links for available reports | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/reportsPage.test.tsx |
✅ |
| AC16.12.12 | yes | Reports page displays accounting equation section content | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/reportsPage.test.tsx |
✅ |
| AC16.12.13 | no | apps/frontend/src/__tests__/loginPage.test.tsx |
✅ (optional) | |
| AC16.12.14 | no | apps/frontend/src/__tests__/loginPage.test.tsx |
✅ (optional) | |
| AC16.12.15 | no | apps/frontend/src/__tests__/loginPage.test.tsx |
✅ (optional) | |
| AC16.12.16 | no | apps/frontend/src/__tests__/loginPage.test.tsx |
✅ (optional) | |
| AC16.13.1 | yes | test_lifecycle — sanitize_namespace normalizes branch/workspace names | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyscripts/tests/test_generate_ac_registry.py |
✅ |
| AC16.13.2 | yes | test_lifecycle — get_namespace honors BRANCH_NAME and optional WORKSPACE_ID | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.3 | yes | test_lifecycle — get_namespace falls back to git branch plus path hash when env vars absent | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.4 | yes | test_lifecycle — get_test_db_name and get_s3_bucket format names deterministically | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.5 | yes | test_lifecycle — load_active_namespaces returns [] on missing or corrupted tracker file | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.6 | yes | test_lifecycle — register_namespace and unregister_namespace update active namespace tracker | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.7 | yes | test_lifecycle — get_container_runtime detects podman/docker and returns None when absent | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.8 | yes | test_lifecycle — is_db_ready returns false on pg_isready subprocess failure | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.9 | yes | test_lifecycle — cleanup_worker_databases skips invalid namespace values | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.10 | yes | test_lifecycle — cleanup_worker_databases drops valid worker DB names and skips invalid names | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.11 | yes | test_lifecycle — _get_changed_files maps backend python paths into module import names | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.12 | yes | generate_test_pdfs — generate_statement writes table rows and closing balance from Decimal transactions | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.13.13 | yes | Backend exposes GET /api/review/conflicts/{statement_id} returning {duplicates: [...], transfer_pairs: [...]} consumed b | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/uiGapAudit.stage1Refactor.test.ts |
✅ |
| AC16.13.14 | yes | Contract test asserts response schema and 404 when statement_id not found | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/uiGapAudit.stage1Refactor.test.ts |
✅ |
| AC16.14.1 | yes | Balance-sheet page renders loading and error retry states | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/balanceSheetPage.test.tsx |
✅ |
| AC16.14.2 | yes | Balance-sheet page renders totals and account sections on successful fetch | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/balanceSheetPage.test.tsx |
✅ |
| AC16.14.3 | yes | Balance-sheet page toggles account tree expansion controls | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/balanceSheetPage.test.tsx |
✅ |
| AC16.14.4 | yes | Income-statement page renders loading and error retry states | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/incomeStatementPage.test.tsx |
✅ |
| AC16.14.5 | yes | Income-statement page renders KPI cards and category lists on success | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/incomeStatementPage.test.tsx |
✅ |
| AC16.14.6 | yes | Income-statement page tag filters can be selected and cleared | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/incomeStatementPage.test.tsx |
✅ |
| AC16.14.7 | yes | Cash-flow page renders loading and error retry states | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/cashFlowPage.test.tsx |
✅ |
| AC16.14.8 | yes | Cash-flow page renders summary and section cards on success | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/cashFlowPage.test.tsx |
✅ |
| AC16.14.9 | yes | Cash-flow page renders sankey chart when summary exists | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/cashFlowPage.test.tsx |
✅ |
| AC16.14.10 | yes | Statements page renders loading, error, empty, and populated states | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/statementsPage.test.tsx |
✅ |
| AC16.14.11 | yes | Statements page enables polling when parsing status is present | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/statementsPage.test.tsx |
✅ |
| AC16.14.12 | yes | Statements page delete action calls delete API and toast on confirm | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/statementsPage.test.tsx |
✅ |
| AC16.15.1 | yes | Accounts page renders loading and error retry states | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/accountsPage.test.tsx |
✅ |
| AC16.15.2 | yes | Accounts page renders grouped account cards and type filters on successful fetch | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/accountsPage.test.tsx |
✅ |
| AC16.15.3 | yes | Accounts page delete action confirms and calls delete API with success toast | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/accountsPage.test.tsx |
✅ |
| AC16.15.4 | yes | Assets page renders loading and error retry states | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/accountsPage.test.tsxapps/frontend/src/__tests__/assetsPage.test.tsx |
✅ |
| AC16.15.5 | yes | Assets page renders grouped positions and status filters on successful fetch | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/accountsPage.test.tsxapps/frontend/src/__tests__/assetsPage.test.tsx |
✅ |
| AC16.15.6 | yes | Assets page reconcile action calls API and shows toast summary | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/accountsPage.test.tsxapps/frontend/src/__tests__/assetsPage.test.tsx |
✅ |
| AC16.15.7 | no | apps/frontend/src/__tests__/accountsPage.test.tsx |
✅ (optional) | |
| AC16.15.8 | no | apps/frontend/src/__tests__/accountsPage.test.tsx |
✅ (optional) | |
| AC16.15.9 | no | apps/frontend/src/__tests__/accountsPage.test.tsx |
✅ (optional) | |
| AC16.15.10 | no | apps/frontend/src/__tests__/accountsPage.test.tsx |
✅ (optional) | |
| AC16.16.1 | yes | Root page redirects to dashboard | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/rootPage.test.tsx |
✅ |
| AC16.16.2 | yes | Main layout renders children through AppShell wrapper | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/mainLayout.test.tsx |
✅ |
| AC16.16.3 | yes | Chat page renders advisor client within suspense boundary | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/chatPage.test.tsx |
✅ |
| AC16.16.4 | yes | Reconciliation entry pages render workbench and unmatched board components | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/reconciliationEntryPages.test.tsx |
✅ |
| AC16.16.5 | yes | Journal page renders error state and retries loading entries | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/journalPage.test.tsx |
✅ |
| AC16.16.6 | yes | Journal page filters entries by status and renders totals | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/journalPage.test.tsx |
✅ |
| AC16.16.7 | yes | Journal page draft actions post and delete entries with API calls | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/journalPage.test.tsx |
✅ |
| AC16.16.8 | yes | Journal page void flow submits reason and refreshes entries | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/journalPage.test.tsx |
✅ |
| AC16.17.1 | yes | Stage 2 review queue shows failure fallback and supports retry | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.17.2 | yes | Stage 2 review queue indicates unresolved checks and disables batch approval | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.17.3 | yes | Stage 2 review queue performs batch reject and approve API workflows | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.17.4 | yes | Stage 2 review queue resolves consistency checks through dialog actions | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.17.5 | yes | Root layout composes Providers and AuthGuard around children | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/rootLayout.test.tsx |
✅ |
| AC16.17.6 | yes | Providers wraps children with QueryClientProvider | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/providers.test.tsx |
✅ |
| AC16.17.7 | yes | API catch-all handlers return JSON 503 for all HTTP methods | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/apiCatchAllRoute.test.ts |
✅ |
| AC16.18.1 | yes | Statement detail page loads statement data and renders parsed transactions summary | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/statementDetailPage.test.tsx |
✅ |
| AC16.18.2 | yes | Statement detail page approve and reject actions call corresponding APIs | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/statementDetailPage.test.tsx |
✅ |
| AC16.18.3 | yes | Statement detail page retry action posts retry API and refreshes data | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/statementDetailPage.test.tsx |
✅ |
| AC16.18.4 | yes | Statement review page shows error fallback and supports retry | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.18.5 | yes | Statement review page disables approve when balance validation fails | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.18.6 | yes | Statement review page approve and reject actions call APIs and navigate back to statements | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.19.1 | yes | App shell renders workspace providers and main content with collapse-aware layout | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/shellAndAuth.test.tsx |
✅ |
| AC16.19.2 | yes | Auth guard redirects unauthenticated protected routes and allows public routes | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/shellAndAuth.test.tsx |
✅ |
| AC16.19.3 | yes | Sidebar shows auth-aware actions and logout triggers clearUser plus login redirect | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/sidebarAndTabs.test.tsx |
✅ |
| AC16.19.4 | yes | Workspace tabs derive route labels and invoke add/set/remove tab handlers | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/sidebarAndTabs.test.tsx |
✅ |
| AC16.19.5 | yes | Chat page client enforces disclaimer consent and passes initial prompt into chat panel | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/chatComponents.test.tsx |
✅ |
| AC16.19.6 | yes | Chat widget hides on chat route and toggles panel visibility elsewhere | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/chatComponents.test.tsx |
✅ |
| AC16.19.7 | yes | Confirm dialog handles required input, cancel, and confirm interactions | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/confirmDialogComponent.test.tsx |
✅ |
| AC16.19.8 | yes | Confirm dialog responds to escape key and backdrop click when not loading | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/confirmDialogComponent.test.tsx |
✅ |
| AC16.19.9 | yes | Toast provider shows, dismisses, and auto-expires notifications | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/toastProviderComponent.test.tsx |
✅ |
| AC16.19.10 | yes | Bar and pie chart components render semantic labels and filtered data | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/chartsComponents.test.tsx |
✅ |
| AC16.19.11 | yes | Trend chart renders line/area paths and point labels for provided series | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/chartsComponents.test.tsx |
✅ |
| AC16.19.12 | no | apps/frontend/src/__tests__/sidebarAndTabs.test.tsx |
✅ (optional) | |
| AC16.19.13 | no | apps/frontend/src/__tests__/sidebarAndTabs.test.tsx |
✅ (optional) | |
| AC16.19.14 | no | apps/frontend/src/__tests__/sidebarAndTabs.test.tsx |
✅ (optional) | |
| AC16.19.15 | no | apps/frontend/src/__tests__/sidebarAndTabs.test.tsx |
✅ (optional) | |
| AC16.19.16 | no | apps/frontend/src/__tests__/confirmDialogComponent.test.tsx |
✅ (optional) | |
| AC16.19.17 | no | apps/frontend/src/__tests__/confirmDialogComponent.test.tsx |
✅ (optional) | |
| AC16.20.1 | yes | Reconciliation workbench loads stats and pending queue with default selection | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/ChatWidget.test.tsxapps/frontend/src/__tests__/reconciliationWorkbenchComponent.test.tsx |
✅ |
| AC16.20.2 | yes | Reconciliation workbench triggers run, accept, reject, and batch accept APIs | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/ChatPageClient.test.tsxapps/frontend/src/__tests__/reconciliationWorkbenchComponent.test.tsx |
✅ |
| AC16.20.3 | yes | Unmatched board loads transactions and creates journal entry for selected item | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/ChatWidget.test.tsxapps/frontend/src/__tests__/unmatchedBoardComponent.test.tsx |
✅ |
| AC16.20.4 | yes | Unmatched board flag and ignore actions update list and local state | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/unmatchedBoardComponent.test.tsx |
✅ |
| AC16.20.5 | yes | Chat panel sends streaming responses, loads suggestions/history, and clears session | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/chatPanelComponent.test.tsx |
✅ |
| AC16.20.6 | no | apps/frontend/src/__tests__/reconciliationWorkbenchComponent.test.tsx |
✅ (optional) | |
| AC16.20.7 | no | apps/frontend/src/__tests__/chatPanelComponent.test.tsx |
✅ (optional) | |
| AC16.21.1 | yes | Account form modal create mode submits normalized payload and closes on success | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/accountFormModalComponent.test.tsx |
✅ |
| AC16.21.2 | yes | Account form modal edit mode pre-fills values and submits update payload | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/accountFormModalComponent.test.tsx |
✅ |
| AC16.21.3 | yes | Account form modal surfaces API errors and field validation feedback | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/accountFormModalComponent.test.tsx |
✅ |
| AC16.21.4 | yes | Journal entry form loads account options and enforces balanced double-entry totals | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/journalEntryFormComponent.test.tsx |
✅ |
| AC16.21.5 | yes | Journal entry form creates draft entries with normalized line amounts and optional posting | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/journalEntryFormComponent.test.tsx |
✅ |
| AC16.21.6 | yes | Journal entry form supports dynamic line add/remove and submit-time error handling | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/journalEntryFormComponent.test.tsx |
✅ |
| AC16.21.7 | yes | Sankey chart builds empty-state and data-state options for inflow and outflow links | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/sankeyChartComponent.test.tsx |
✅ |
| AC16.21.8 | yes | Sankey chart recomputes theme-aware colors when root theme attributes change | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/sankeyChartComponent.test.tsx |
✅ |
| AC16.21.9 | yes | Workspace provider restores tabs from storage and persists active workspace updates | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/useWorkspaceHook.test.tsx |
✅ |
| AC16.21.10 | yes | Workspace provider handles tab deduplication, removal, and cross-tab storage sync | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/useWorkspaceHook.test.tsx |
✅ |
| AC16.22.1 | yes | Stage 1 pending_review → approved transition requires balance delta ≤ 0.001 USD | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.22.2 | yes | Stage 1 pending_review → rejected transition triggers re-parse | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.22.3 | yes | Stage 2 pending_review → accepted transition blocked when unresolved checks exist | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.22.4 | yes | Journal entry created only on accepted transition, never on pending_review | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.22.5 | yes | Stage 1 tolerance is 0.001 USD (not 0.10 USD from Stage 2) | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.22.6 | yes | All service methods mutating pending_review enforce user_id ownership | apps/backend/tests/_ac_stubs/test_epic_16_stubs.py |
✅ |
| AC16.23.1 | yes | Stage 1 page split into <PdfPreviewPane />, <TransactionTable />, <ReviewActionBar />, <BalanceIndicator /> components, each independently mountable |
apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/dashboardPage.test.tsxapps/frontend/src/__tests__/uiGapAudit.stage1Refactor.test.ts |
✅ |
| AC16.23.2 | yes | TransactionTable supports inline edit of amount, description, date with optimistic update + server confirm; failed write reverts row and shows error toast |
apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/dashboardPage.test.tsxapps/frontend/src/__tests__/uiGapAudit.stage1Refactor.test.ts |
✅ |
| AC16.23.3 | yes | Conflict resolution dialog <ConflictResolutionDialog /> opens when backend returns duplicate or transfer-pair candidates; user can pick canonical row or link the pair |
apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/assetsPage.test.tsxapps/frontend/src/__tests__/uiGapAudit.stage1Refactor.test.ts |
✅ |
| AC16.23.4 | yes | Stage 2 listing exposes severity filter, check-type filter, and score-range slider; filters persist in URL query string for shareable links | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/assetsPage.test.tsxapps/frontend/src/__tests__/uiGapAudit.stage1Refactor.test.ts |
✅ |
| AC16.23.5 | yes | Mobile navigation drawer (<MobileNav />) renders below 768 px with links to Dashboard / Review / Processing / Portfolio; existing desktop sidebar hidden on mobile |
apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/reportsPage.test.tsxapps/frontend/src/__tests__/uiGapAudit.stage1Refactor.test.ts |
✅ |
| AC16.23.6 | yes | Frontend tests mount each new component (PdfPreviewPane, TransactionTable, ConflictResolutionDialog, MobileNav) and assert primary affordance renders | apps/backend/tests/_ac_stubs/test_epic_16_stubs.pyapps/frontend/src/__tests__/dashboardPage.test.tsxapps/frontend/src/__tests__/epic016Components.test.tsxapps/frontend/src/__tests__/mobileNav.coverage.test.tsxapps/frontend/src/__tests__/uiGapAudit.stage1Refactor.test.ts |
✅ |
📋 EPIC-017: portfolio-management¶
- Total ACs: 73
- Mandatory ACs: 29
- Mandatory ACs with test reference: 29 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC17.1.1 | yes | Holdings Summary | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.1.2 | yes | FIFO Cost Basis | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.1.3 | yes | LIFO Cost Basis | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.1.4 | yes | Average Cost Basis | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.1.5 | yes | Unrealized P&L Calculation | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.1.6 | yes | Manual Price Update | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.1.7 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.1.8 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.1.9 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.2.1 | yes | XIRR Accuracy (within 0.01% of Excel) | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.2.2 | yes | Time-Weighted Return | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.2.3 | yes | Money-Weighted Return | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.2.4 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.2.5 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.2.6 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.2.7 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.2.8 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.2.9 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.3.1 | yes | Sector Allocation Breakdown | apps/backend/tests/portfolio/test_performance_service.py |
✅ |
| AC17.3.2 | yes | Geography Allocation Breakdown | apps/backend/tests/portfolio/test_performance_service.py |
✅ |
| AC17.3.3 | yes | Asset Class Allocation Breakdown | apps/backend/tests/portfolio/test_performance_service.py |
✅ |
| AC17.3.4 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.3.5 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.3.6 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.3.7 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.3.8 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.3.9 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.3.10 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.3.11 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.3.12 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.3.13 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.3.14 | no | apps/backend/tests/portfolio/test_performance_service.py |
✅ (optional) | |
| AC17.4.1 | yes | Moomoo Statement Parsing | apps/backend/tests/portfolio/test_allocation_service.py |
✅ |
| AC17.4.2 | yes | Futu Statement Parsing | apps/backend/tests/portfolio/test_allocation_service.py |
✅ |
| AC17.4.3 | yes | Interactive Brokers Parsing | apps/backend/tests/portfolio/test_allocation_service.py |
✅ |
| AC17.4.4 | yes | Broker Auto-Detection (Moomoo) | apps/backend/tests/portfolio/test_allocation_service.py |
✅ |
| AC17.4.5 | yes | Broker Auto-Detection (Futu) | apps/backend/tests/portfolio/test_allocation_service.py |
✅ |
| AC17.4.6 | no | apps/backend/tests/portfolio/test_allocation_service.py |
✅ (optional) | |
| AC17.5.1 | yes | Buy Transaction → Journal Entry | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.5.2 | yes | Sell Transaction → Journal Entry + Realized P&L | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.5.3 | yes | Dividend → Journal Entry → Income Statement | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.5.4 | yes | Unrealized P&L → Balance Sheet | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ |
| AC17.5.5 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.5.6 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.5.7 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.5.8 | no | apps/backend/tests/portfolio/test_portfolio_service.py |
✅ (optional) | |
| AC17.6.1 | yes | Full Buy/Sell Cycle | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ |
| AC17.6.2 | yes | Dividend Accrual to Income | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ |
| AC17.6.3 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.4 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.5 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.6 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.7 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.8 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.9 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.10 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.11 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.12 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.13 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.14 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.15 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.16 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.17 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.18 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.19 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.20 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.6.21 | no | apps/backend/tests/portfolio/test_portfolio_router.py |
✅ (optional) | |
| AC17.7.1 | yes | Holding detail page /portfolio/[ticker] renders three tabs: Overview, Dividends, Realized P&L | apps/backend/tests/_ac_stubs/test_epic_17_stubs.pyapps/frontend/src/__tests__/uiGapAudit.portfolioFE.test.ts |
✅ |
| AC17.7.2 | yes | Dividends tab lists historical dividend events {ex_date, pay_date, amount, currency, reinvested} from GET /api/portfolio | apps/backend/tests/_ac_stubs/test_epic_17_stubs.pyapps/frontend/src/__tests__/uiGapAudit.portfolioFE.test.ts |
✅ |
| AC17.7.3 | yes | Cost-basis method selector (FIFO / LIFO / AvgCost) on holding detail page persists per-holding via PATCH /api/portfolio/ | apps/backend/tests/_ac_stubs/test_epic_17_stubs.pyapps/frontend/src/__tests__/uiGapAudit.portfolioFE.test.ts |
✅ |
| AC17.7.4 | yes | Realized P&L tab shows lot-level table {lot_id, acquired_date, sold_date, quantity, basis, proceeds, gain_loss, holding_ | apps/backend/tests/_ac_stubs/test_epic_17_stubs.pyapps/frontend/src/__tests__/uiGapAudit.portfolioFE.test.ts |
✅ |
| AC17.7.5 | yes | Portfolio summary card on dashboard adds realized_pnl_ytd and dividend_income_ytd figures from GET /api/portfolio/summar | apps/backend/tests/_ac_stubs/test_epic_17_stubs.pyapps/frontend/src/__tests__/uiGapAudit.portfolioFE.test.ts |
✅ |
| AC17.7.6 | yes | Frontend test mounts HoldingDetailPage, switches to Dividends tab, and asserts dividend row labels render | apps/backend/tests/_ac_stubs/test_epic_17_stubs.pyapps/frontend/src/__tests__/uiGapAudit.portfolioFE.test.ts |
✅ |
📋 EPIC-018: ai-driven-pipeline¶
- Total ACs: 23
- Mandatory ACs: 23
- Mandatory ACs with test reference: 23 (100.0%)
| AC ID | Mandatory | Description | Test References | Status |
|---|---|---|---|---|
| AC18.1.1 | yes | Extraction prompt returns suggested_category and category_confidence | apps/backend/tests/_ac_stubs/test_epic_18_stubs.py |
✅ |
| AC18.1.2 | yes | BankStatementTransaction has suggested_category and category_confidence columns | apps/backend/tests/_ac_stubs/test_epic_18_stubs.py |
✅ |
| AC18.1.3 | yes | RuleType.ML_MODEL evaluates AI suggestion with confidence threshold >= 0.7 | apps/backend/tests/_ac_stubs/test_epic_18_stubs.py |
✅ |
| AC18.1.4 | yes | Classification priority: KEYWORD > REGEX > ML_MODEL > Uncategorized | apps/backend/tests/_ac_stubs/test_epic_18_stubs.py |
✅ |
| AC18.1.5 | yes | create_entry_from_txn reads classification before defaulting to Uncategorized | apps/backend/tests/_ac_stubs/test_epic_18_stubs.py |
✅ |
| AC18.1.6 | yes | Auto-created category accounts are user-scoped and correctly typed | apps/backend/tests/_ac_stubs/test_epic_18_stubs.py |
✅ |
| AC18.2.1 | yes | CorrectionLog model records original and corrected categories | apps/backend/tests/extraction/test_correction_service.py |
✅ |
| AC18.2.2 | yes | Corrections API records and retrieves correction stats | apps/backend/tests/extraction/test_correction_service.py |
✅ |
| AC18.2.3 | yes | Few-shot examples from corrections injected into extraction prompt | apps/backend/tests/extraction/test_correction_service.py |
✅ |
| AC18.2.4 | yes | Correction cache with 1-hour TTL | apps/backend/tests/extraction/test_correction_service.py |
✅ |
| AC18.3.1 | yes | ai_semantic_score() returns similarity for transaction description pairs | apps/backend/tests/reconciliation/test_ai_reconciliation.py |
✅ |
| AC18.3.2 | yes | Hybrid scoring: 0.7 * algorithmic + 0.3 * AI for 60-84 range only | apps/backend/tests/_ac_stubs/test_epic_18_stubs.py |
✅ |
| AC18.3.3 | yes | Feature flag enable_ai_reconciliation controls AI scoring | apps/backend/tests/_ac_stubs/test_epic_18_stubs.py |
✅ |
| AC18.4.1 | yes | Reports read Layer 3 TransactionClassification for category breakdowns | apps/backend/tests/_ac_stubs/test_epic_18_stubs.py |
✅ |
| AC18.4.2 | yes | ReportSnapshot (Layer 4) generated and queryable via API | apps/backend/tests/_ac_stubs/test_epic_18_stubs.py |
✅ |
| AC18.4.3 | yes | AI CSV parsing handles unknown institutions as fallback | apps/backend/tests/extraction/test_ai_csv_parsing.py |
✅ |
| AC18.5.1 | yes | apps/backend/tests/_ac_stubs/test_epic_18_stubs.pyapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsx |
✅ | |
| AC18.5.2 | yes | ConfidenceBadge mounted on every transaction row in Stage 1 review, Stage 2 listing, and processing-account listing; rea | apps/backend/tests/_ac_stubs/test_epic_18_stubs.pyapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsx |
✅ |
| AC18.5.3 | yes | AI Suggestion Review Queue page /review/ai-suggestions lists pending AI classifications and AI reconciliation matches in | apps/backend/tests/_ac_stubs/test_epic_18_stubs.pyapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsx |
✅ |
| AC18.5.4 | yes | Queue actions: Accept, Reject, Edit-then-Accept; each action calls POST /api/ai/feedback with {suggestion_id, action, co | apps/backend/tests/api/test_ai_feedback_router.pyapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsx |
✅ |
| AC18.5.5 | yes | Settings page /settings/ai exposes toggles for enable_ai_reconciliation, enable_ai_classification, persisted via PATCH / | apps/backend/tests/api/test_user_settings_router.pyapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsx |
✅ |
| AC18.5.6 | yes | Audit Trail panel on transaction detail page lists chronological {timestamp, actor, action, old_value, new_value} from G | apps/backend/tests/api/test_ai_feedback_router.pyapps/backend/tests/api/test_audit_router.pyapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsx |
✅ |
| AC18.5.7 | yes | Frontend tests: mount ConfidenceBadge for each tier; mount AI Suggestion Queue and assert Accept/Reject buttons render; | apps/backend/tests/_ac_stubs/test_epic_18_stubs.pyapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsapps/frontend/src/__tests__/uiGapAudit.confidenceAndAiQueue.test.tsx |
✅ |
🔁 Regeneration¶
# Regenerate this file
python scripts/build_ac_traceability.py
# CI guard (exit 1 if the file would change)
python scripts/build_ac_traceability.py --check
Source registries: docs/ac_registry.yaml, docs/infra_registry.yaml. AC reference pattern: ACx.y.z (matched by scripts/check_ac_traceability.py).