c0ecf2fa3bebd46bdfd0169efd73b89653d1dfed
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
78a581bca1 |
fix(import): guard against CP437-as-CP1252 mojibake entering via pre-decoded SIE text (#1569)
* refactor(arcim-migration): remove the dead gateway SIE export path fetchSIEExport and SIEExportFile have had zero callers since the direct provider clients replaced the Arcim Sync gateway (#181, #718). The path returned SIE as a pre-decoded string, and the gateway's decode of CP437 bytes as windows-1252 is what wrote the 2026-03-17 mojibake into posted entries. Deleting it makes the string-typed SIE fetch impossible to re-wire; a comment marks the grave. The consent lifecycle and entity accessors stay untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(import): warn when SIE text carries CP437-as-CP1252 mojibake The 2026-03-17 migration wrote mojibake ("L"neutbetalning"-style C1 specials) into posted entries because the retired gateway handed the /import-sie handler an already-decoded string: byte-level encoding detection never saw it, and nothing downstream checked. The live bug is gone; this is the tripwire so the signature can never land silently again. - lib/import/sie-artifact-scan.ts: pure scanner over parsed SIE account names and voucher/line descriptions, reusing hasCp1252Artifact from charset-repair; flags at >= 2 hits so a lone legitimate curly quote or apostrophe cannot false-positive a whole file. - arcim-migration /import-sie: warn-never-block; the Swedish warning rides on result.warnings, which the workspace UI already renders, plus a server-side log.warn. - wizard parse route: same scan, surfaced through the existing parse-issue warnings card in the preview, pointing at the first affected line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(bookkeeping): pin the reported gateway mojibake strings Adds the four strings reported from the affected company's journal as reverse_cp437 cases (all reverse losslessly) plus a false-positive guard: space-padded typography must never route into the CP437 reversal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ec27228a8e |
style: remove em/en dashes repo-wide, add CLAUDE.md rule against them (#890)
Em dashes (—) and en dashes (–) had spread across comments, docs, tests, and a few UI strings, reading as AI-generated boilerplate rather than house style. Replaced each with punctuation matching its context: colon for explanatory clauses, comma for asides, plain hyphen for numeric/legal ranges (e.g. "21-23§"), "to"/"till" for date ranges, parentheses for paired-dash asides. messages/en.json and messages/sv.json were fixed by hand together to keep sv/en in sync. Left untouched where the dash is the functional subject rather than decorative punctuation: date-range-parser.ts's separator regex, charset-repair.ts's CP1252 byte-mapping table (and its test), the SIE encoding mojibake docs, generic-csv.ts's minus-sign normalizer, the agent system-prompt files that already instruct against em dashes, and a golden iXBRL test fixture compared byte-for-byte. Also fixes two bugs surfaced along the way: an off-by-one in ApiKeysPanel's scope-label split (a leftover from an earlier partial pass), and a charset-repair test that had lost the literal en-dash it exists to verify. Regenerated the agent atom seed migration (skills:generate) since 27 SKILL.md files changed. Added a CLAUDE.md rule against em/en dashes, with an explicit carve-out for the functional-dash cases above. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
d95a0b6105 |
fix(bookkeeping): comprehensive chart_of_accounts charset repair (#736)
* fix(bookkeeping): comprehensive chart_of_accounts charset repair The 20260625120000 backfill (PR #734) only covered the 26 short-name seed accounts. Investigation found the corruption was far broader — ~4,500 rows across 858 companies — in four signatures, and verified the root cause is already closed (prod's seed_chart_of_accounts() carries correct diacritics; the corruption was prod-migration-drift, the seed fix reached prod ~2026-06-12, no companies corrupted since). Adds a tested, reusable repair core + a guarded script: - lib/bookkeeping/charset-repair.ts — pure, unit-tested resolvers: * stripped diacritics ("Utgaende moms forsaljning...") → restore from a de-accent-equal clean sibling. DIRECTIONAL guard (only acts on a fully de-accented input) so a correct name is never stripped down; unique-match only, so user-renamed accounts are never clobbered. * double-encoded UTF-8-as-CP1252 ("Företagskonto") → lossless CP1252-aware byte reversal (recovers custom names too). * CP437-as-CP1252 ("F”rmedlad", "™vriga", "V„rdef”r„ndring") → lossless CP437 letter reversal. * lost-byte U+FFFD ("p� bilar") → fill via single-char-wildcard match to a unique clean sibling (the byte is gone, so only a confident sibling wins). isClean() rejects mojibake AND mid-word CP1252 artifacts, but treats a space-padded en-dash ("Kundfordringar – delad faktura") as legitimate. - scripts/repair-chart-of-accounts-charset.ts — dry-run by default, --execute to apply; idempotent; refuses any non-prod project. Sources canonical names from the table's own clean sibling rows + BAS_REFERENCE. Applied to production (UPDATE-only, account_name is display-only): 4,499 rows across 858 companies repaired, 0 double-encoded remaining, 0 errors. 247 rows left untouched and reported — custom account names with lost bytes and no canonical (unrecoverable from the data; need the source SIE file or manual fix). 21 unit tests cover every transform with real prod fixtures, plus the two dry-run bugs caught before any write (correct→stripped direction; matching a CP437-mojibake sibling). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(scripts): avoid supabase-js generic mismatch in charset repair fetch next build's tsc rejected fetchAll(supabase: ReturnType<typeof createClient>) — the default-generic SupabaseClient type doesn't unify with the inferred createClient() return. Make fetchAll a closure over the inferred client. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(scripts): add TOCTOU guard to charset repair updates Per PR review: only write when the row still holds the exact corrupted value read (.eq account_name), so a concurrent rename is skipped, not clobbered, and the script is strictly idempotent. Track skipped count. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(charset-repair): build combining-marks regex from ASCII string Per PR review: the deaccent regex literal embedded raw U+0300–U+036F combining marks (invisible, encoding-fragile). Build it via RegExp('[\\u0300-\\u036f]') so the source is plain ASCII. Behavior-identical; 21 tests still green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |