Completes the #985/#986/#987 caller sweep: categorize-core, v1 batch-categorize, pending-operation edits and the MCP categorize path now resolve the settlement leg from the transaction's cash account instead of inheriting a hardcoded or stale account. Extends the correct_entry preview with currency, tax and dimension line metadata so staged corrections preserve full line fidelity. Adds a read-only audit query and a runbook for reviewing and correcting historical mis-bookings via staged storno with explicit approval; no automated bulk mutation. Fixes #1001 Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
5.4 KiB
Settlement account remediation
Use this runbook to review journal entries that may have been posted against a different settlement account than the cash account linked to their source bank transaction. It covers historical entries created before and around the fixes for issues #985, #986, and #987.
The audit is intentionally broader than a list of confirmed errors. A current
cash_account_id does not prove that the transaction had that link when the
entry was posted. Never correct an entry from query output alone.
Invariants
- Never edit or delete a posted journal entry.
- Correct a confirmed error with storno plus a replacement entry through
gnubok_correct_entry. - Keep every replacement line balanced and preserve the original line metadata.
- Do not write directly to
journal_entriesorjournal_entry_lines. - Do not correct a locked or closed period without a separately reviewed and explicitly approved unlock or reopening workflow.
- Never run a production correction without explicit approval for the exact company, vouchers, and replacement lines.
Detect candidates
Run scripts/audit-settlement-account-mismatches.sql
against the intended database. The query is read-only and returns current
posted entries whose exact directional settlement leg differs from
cash_accounts.ledger_account.
Treat review_priority only as an ordering aid:
high_review_priority_hardcoded_1930_signaturematches the known historical failure shape, but still needs evidence review.manual_review_payment_aware_correction_requiredidentifies a payment flow with a mismatching account. Detection is supported, but the generic correction procedure below is not. Stop and use a payment-aware correction path.- Every
manual_review_*result may be a later cash-account link, a manual reconciliation, or another legitimate accounting shape.
Review each candidate
- Confirm the transaction belongs to the reported cash account using the original bank feed or statement and the bank connection metadata.
- Confirm that the cash-account link existed when the journal entry was
posted.
transaction_updated_atclose tocommitted_atis supporting evidence, not proof. - Fetch the current journal entry and all lines. Stop if the entry was already reversed, corrected, or linked manually after posting.
- Confirm there is exactly one settlement leg and that its direction and SEK amount match the bank transaction.
- Confirm the only required accounting change is replacing the observed
settlement account with
expected_settlement_account. - Check
effective_lock_status. Both the fiscal period'sis_closedandlocked_atfields and the company-widebookkeeping_locked_throughdate are authoritative lock layers. Any result other thanopenis a hard stop for the ordinary correction flow. If VAT has already been filed, determine whether an omprövning is required before reopening anything. - Stop when
booking_flowiscustomer_invoice_paymentorsupplier_invoice_payment. The generic correction service does not relink all invoice-payment references from the reversed entry. A payment-aware, tested correction procedure is required for those candidates.
Keep the reviewed candidate set, evidence, proposed replacement lines, and reviewer identity together as the correction record.
Stage the correction
For a confirmed candidate in an open and unlocked period:
- Re-run the audit query immediately before staging and retain its
original_linesvalue. It includes currency amounts, exchange rates, tax codes, dimensions, cost centers, and projects that the ordinary journal query does not return. - Re-fetch the entry with
gnubok_query_journalto confirm that its status, voucher, amounts, and visible lines still match the fresh audit result. - Copy every object from
original_linesinto thelinesinput forgnubok_correct_entry. - On the one confirmed settlement line, replace only
account_numberwithexpected_settlement_account. - Preserve debit and credit amounts, line descriptions, currency metadata, tax codes, dimensions, cost centers, and projects exactly as recorded.
- Verify that total debits equal total credits and both totals are positive.
- Stage
gnubok_correct_entryusing the voucher reference or freshly fetched entry UUID. Review its original and correction previews line by line. The preview must show the preserved currency, tax, and dimension metadata. - Approve the staged operation with
gnubok_approve_pending_operationonly after the exact operation has explicit authorization. High-risk approval requiresconfirmed: true.
Do not use gnubok_reverse_journal_entry by itself for this case. The business
event remains valid; only its settlement account is being corrected.
Verify after approval
- Confirm the original entry is retained with status
reversed. - Confirm a posted storno and a posted corrected entry were created in the intended fiscal period.
- Confirm the bank transaction now links to the posted corrected entry.
- Confirm the corrected settlement leg uses the expected account and amount.
- Run
gnubok_get_general_ledgerfor both the observed and expected accounts. - Re-run the audit query. The corrected transaction must no longer appear.
- Record the new voucher references and verification evidence with the reviewed candidate set.