# Budget Phase 1.8 — Core candidate confirm flow and effective expenses

Use this reference when Budget/Cashflow review pages or candidate-confirm behaviour are incorrect, duplicated, or show test/seed data as productive expenses.

## Goal

The only acceptable core workflow is:

`budget_transaction_candidate -> category set/overridden -> Confirm -> productive budget_transactions row -> Effective Expenses -> Budgetstatus`

Do not add new import sources or broaden the feature surface while this flow is unstable.

## Navigation / UX pattern

- Avoid duplicating Import Review and Category Assignment as separate surfaces for the same rows.
- User Mode Budget menu should have a single central candidate work page, e.g. **Ausgaben -> Buchungen prüfen**.
- The central page owns: pending/import candidates, category proposal display, category override, Confirm, Ignore, Reopen, Split preparation, Transfer marking, details drawer and bulk category/confirm/ignore/reopen.
- Old routes may redirect to the central page to preserve bookmarks, but must not be visible as duplicate menu items.
- Confirm controls must be hidden/disabled unless the required fields are present, especially category and account.

## Backend confirm contract

`confirm_transaction_candidate` must validate before writing:

- active category for expense/income candidates
- active account
- amount
- currency
- date
- description

On success it must:

1. Insert a real `budget_transactions` row.
2. Set `status='confirmed'`.
3. Set `source_type='import_candidate'`.
4. Store `source_candidate_id` on `budget_transactions`.
5. Store `confirmed_transaction_id`, `confirmed_at`, `confirmed_by` on `budget_transaction_candidates`.
6. Write separate audit events for candidate confirmation and transaction creation, e.g. `candidate_confirmed` and `budget_transaction_created`.
7. Commit only after both productive row and candidate status are updated.

Default candidate list views should hide confirmed/ignored/non-booking statuses. Status-specific tabs or filters may still show `covered_by_migros`, `ignored`, etc. for review/admin needs.

## Effective Expenses contract

The Effective Expenses page/API must show only productive confirmed expense transactions:

- `budget_transactions.status='confirmed'`
- `transaction_type='expense'`

It must not show:

- import candidates
- seed candidates
- ignored candidates
- `covered_by_migros`
- superseded article rows
- archived/test/UAT rows

Row click/detail drawer may allow category/tag changes, but amount changes require adjustment/reversal flow. Category/tag changes must write audit and refresh Budgetstatus.

## Budgetstatus coupling

Budgetstatus by category must include categories that have confirmed actuals even if no budget plan exists yet. Otherwise a newly confirmed expense can appear under Effective Expenses but not in category status, which breaks acceptance.

Row-click/category detail should query confirmed transactions by `category_id` rather than candidates.

## Runtime cleanup pattern for UAT/test data

Before mutating runtime:

1. Create a verified runtime DB backup outside Git using SQLite online backup where possible.
2. Dry-run cleanup and report aggregate counts only; never report real amounts.
3. Archive/deactivate test artefacts rather than hard-deleting unless explicitly required:
   - budget accounts: `is_active=0`, `archived_at`
   - budget categories/tags: `is_active=0`
   - budget transactions: `status='archived'`
   - candidates: `status='ignored'` or equivalent non-visible state
4. Write a cleanup audit event.
5. Verify user-facing views show zero matching test/UAT artefacts.

For temporary Runtime-UAT objects created by the agent, archive them again after verifying the flow, so Effective Expenses remains free of test data.

## SQLite migration pitfall

When rebuilding SQLite tables with `ALTER TABLE ... RENAME TO ...`, SQLite may rewrite foreign-key references in dependent tables to the temporary table name (e.g. `budget_transactions__phase18` or `budget_transaction_candidates__phase18`). This can later break inserts into related tables with `no such table: main.<temp_table>`.

After table rebuilds, inspect `sqlite_master.sql` for `__phase` references and rebuild dependent tables or avoid FK references for cross-phase helper links where necessary. Tests should exercise inserts into dependent tables such as:

- `budget_transaction_tags`
- `budget_transfers`
- `budget_import_line_items`
- `budget_candidate_splits`

## Tests to add

Minimum regression tests:

- Confirm candidate creates `budget_transactions` row and stores `confirmed_transaction_id`.
- Confirmed candidate disappears from default pending/open candidate view.
- Effective Expenses lists the resulting confirmed expense transaction.
- Pending candidate category update is audited but does not book.
- Confirmed transaction category update is audited and updates Budgetstatus.
- Ignore hides candidate; Reopen makes it visible again.
- UAT/test artefacts are archived and absent from user-facing views.
- Navigation exposes **Buchungen prüfen** once and does not expose duplicate Import Review / Kategoriezuordnung menu entries.
- Migration has no lingering `__phase*` temporary table references in `sqlite_master`.

## Verification

Run in this order:

1. Focused backend tests for the core flow.
2. Full `pytest` with `JARVIS_FINANCE_DB_PATH` unset unless explicitly testing runtime.
3. Frontend vitest.
4. Frontend build.
5. Apply migration to runtime and verify no temp FK references remain.
6. Changed-file secret scan and Git-safety; remove `frontend/dist`, `.vite`, `.pytest_cache`, `__pycache__` after tests/build.
7. Commit, push, and verify remote hash with authenticated temporary askpass if needed.
