fix(transactions): derive pre-migration marker cutoff from imported voucher dates, not fiscal_year_end (#2047)
* fix(transactions): derive pre-migration marker cutoff from imported voucher dates, not fiscal_year_end A SIE file exported mid-year still declares the full fiscal year in #RAR 0, so sie_imports.fiscal_year_end is a future date for mid-year migrators and the 'fran perioden fore din migrering' marker fired on every new bank transaction until New Year. The cutoff now comes from the latest posted source_type='import' entry_date (excluding the M-series omforingsverifikation, which is deliberately dated at fiscal year end), so it tracks where the imported bokforing actually ends and self-corrects on undo/replace. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UU5QbL3p8xNB3tSZDbyrr3 * fix(transactions): arm pre-migration cutoff on completed SIE import, exclude omforing by description Skeptic findings on the frozen commit: (1) source_type='import' is accepted from v1 API clients, so a never-migrated company with an API-labeled backfill would get a false cutoff; the marker is now armed only when a completed sie_imports row exists. (2) Imported vouchers keep the source file's voucher series, so excluding series M dropped genuine M-series vouchers (6 prod companies); the omforingsverifikation is now excluded by its hardcoded description prefix instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UU5QbL3p8xNB3tSZDbyrr3 * docs(transactions): state the pre-migration cutoff residuals truthfully The ledger duplicate guard only reaches the completed-year single-skip case (7-day window vs a fiscal-year-end-dated aggregate omforing), so it is not a general backstop for the skip-window gap; the gap is accepted on rarity. Also documents the rattelse-rename fragility of the description-keyed exclusion. Skeptic re-review condition, no code change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UU5QbL3p8xNB3tSZDbyrr3 --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
f43a6653f1
commit
84ba8323b4
@@ -1364,3 +1364,6 @@ One line per decision: `[YYYY-MM-DD] <decision>: <why>`. Appended by agents and
|
||||
[2026-08-30] book_skattekonto_row(s) tier 'medium' + scope 'transactions:write': rule-driven booking with no caller-supplied lines mirrors book_mileage_period (not create_voucher's 'high'); scope follows reconcile_residual (books an outside row). Commit service gates on SKATTEVERKET_ENABLED for HTTP-dispatcher parity, recoverable so the op stays pending.
|
||||
[2026-08-30] Reminder text overrides (company_settings.reminder_text_overrides, level_1..3 x subject/body): the defaults are expressed as placeholder patterns (REMINDER_EMAIL_DEFAULT_TEXTS) and BOTH the stock mail and overrides render through the same substitution pipeline (applyPlaceholders + escape per output variant), so the settings-UI prefill is byte-for-byte the mail that goes out and cannot drift; this differs from the invoice_email_texts precedent, whose hand-written pattern forms can drift from the coded defaults. The level-3 default body is now an explicit inkassovarning (8 days, fordran till inkasso, costs per lag (1981:739)) but the level TITLE stays 'Slutlig paminnelse': the title is reused as the level name in settings labels and subject prefix, and renaming it everywhere is wording churn beyond the ask. An overridden subject owns the whole line (no automatic ' (inkl. drojsmalsranta)' suffix; {belopp} already includes surcharges), the stock subject keeps the suffix byte-identically. No pg test for the migration: a declarative CHECK (jsonb_typeof object) identical in shape to invoice_email_texts (20260703091000), which also shipped without one. The v1 REST/MCP update_company_settings surface was NOT extended: it is a curated field set with staged operations and its own placeholder refinement, a separate parity slice. typecheck/antipattern baselines deliberately not ratcheted in this diff: both one-count drops predate the branch (main drift), gates only fail on increase.
|
||||
[2026-08-30] PR #2021 round 2 (#546): the relayed Peppol buyer restriction now says the customer's org number must not be a personnummer (prepareParty('buyer') in lib/invoices/peppol-bis-billing.ts refuses it with BUYER_PARTICIPANT_IDENTIFIER_UNSUPPORTED, so an enskild firma CUSTOMER is refused, not only an enskild firma sender), Step 4 of the invoicing-rules workflow points at the Peppol section so a top-down reader never reaches the external-provider fallback first, the mark-sent recovery is scoped to the still-draft invoice in every text (INVOICE_MARK_SENT_REPAIR_REQUIRED leaves the invoice sent with the verifikat posted and a second mark-sent returns 409; the reviewer's proposed repair tool gnubok_link_invoice_to_voucher is the PAYMENT link and requires status sent/overdue/partially_paid, so no tool is named and the repair is left to support), and the verifikat parenthetical says "under faktureringsmetoden" (kontantmetod and defer_invoice_booking companies get none at issue). The guard test now also pins the two v1 route descriptions by reading the route source (apiskill:check only detects generated-vs-source drift, not a truth regression). The atom bump was seeded as a THIRD append-only migration (20260830101500, atom v9) rather than consolidating to one: the Supabase preview branch for the PR (xxnqggttsefleehmarjo) has applied both 20260829000100 and 20260829010000 per its schema_migrations, so deleting either would leave a remote with versions absent from the repo, the orphan class the migration rule forbids; all three seeds are idempotent upserts with the version guard, so prod applying them in sequence ends at v9. The generator's max-plus-one name (20260829010001) was renamed to 20260830101500 for the same reason as round 1 (newer than every file on origin/main and every sibling worktree; skills:check hashes content, the pg replay test globs the seed).
|
||||
[2026-08-30] Pre-migration inbox marker cutoff derived at query time from max posted source_type='import' entry_date (excl. series M) instead of a stored sie_imports coverage column: no migration/backfill needed and undo/replace self-corrects; series M excluded because the importer's omforingsverifikation is dated at fiscal year end.
|
||||
[2026-08-30] Skeptic round on PR #2047: cutoff armed by a completed sie_imports row (API clients can post source_type='import', which would false-mark never-migrated companies) and omforingsverifikation excluded by description prefix instead of voucher_series 'M' (imported vouchers keep the source file's series; 6 prod companies use series M for real vouchers). Residual known gap: skip-window covered only by the omforing stays unmarked; DuplicateBookingDialog is the backstop.
|
||||
[2026-08-30] Correction to the PR #2047 residual-gap note: the DuplicateBookingDialog backstop only covers a single skipped bank movement within 7 days of the omforing's fiscal-year-end date; mid-year and aggregated-skip variants are unmitigated and accepted on rarity (conjunction of skipped voucher + tail date + synced account + fetched history). Exact closure = persist skipped-voucher max date as coverage_end on sie_imports at import time (skippedDetails already has the dates); filed as follow-up.
|
||||
|
||||
Reference in New Issue
Block a user