Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i
server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma
strängvärde byggs med konkatenering i stället för att matcha mönstret.
Lägger docs/production-readiness.md och siax/production-gaps.json enligt SIAX Master Definition of Done. Underlag: git-, kod- och live-evidens 2026-11-11. Nivån är evidensbaserad, inte ett leveransgodkännande.
* chore: repo-wide bloat sweep, remove dead code and fold duplicate helpers
Remove 33 dead files, ~270 unreferenced exports/types, 13 dead i18n
namespaces and 4 unused dependencies; fold byte-identical helper copies
into one canonical home each (lib/utils chunk/sleep/utcDateStamp,
lib/dates/iso, lib/invariants/uuid, lib/xml/escape, lib/reports/sru/format,
lib/pdf/number-text, lib/browser/panel-request, lib/api/v1/body +
v1ValidationError rolled out to ~55 v1 routes, booking-template schemas).
No behaviour change: v1 bodies and status codes, MCP tool schemas, DB
writes and money math are untouched. Naive ore rounding was deliberately
not swapped for roundOre; see DECISIONS.md 2026-09-02 for the full list
of things left alone on purpose.
tsc, lint, 19588 unit tests and check:guards green; antipattern baseline
ratcheted (naive-ore-round 622 -> 620, hand-rolled-invariant 115 -> 113).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* test(transactions): import RawTransaction from @/types after the ingest re-export removal
CI's type ratchet (check:types, full tsconfig) caught the one test file
that still imported the type through lib/transactions/ingest.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
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>
* feat(dimensions): PR10 advanced — custom dimensions, hierarchy, account rules, commit enforcement
The final rung of the dimensions ladder
(dev_docs/dimensions_implementation_plan.md §7 row 10):
- custom dimensions: POST /api/dimensions creates registry dims (next free
SIE number >= 20 when omitted; explicit numbers allowed — SIE import
already mints reserved ones); register gets a 'Ny dimension' dialog with
a quiet Avancerat disclosure for the #UNDERDIM parent; GET now carries
parent_sie_dim_no (the column + SIE round-trip existed since PR1/PR5 —
this exposes it)
- account_dimension_rules (migration 20260703120000): one rule per
(account, dimension) — required / default / fixed, per-rule is_active,
company-scoped RLS, composite FK to the registry, value-presence CHECK
- enforcement, opt-in BY CONSTRUCTION (zero rules = engine byte-identical;
deliberately NO settings toggle — a rule that exists but is ignored is
worse than either extreme): default/fixed apply onto line bags at draft
creation (fixed overwrites, default fills); required asserts at
commitEntry with a Swedish MANDATORY_DIMENSION_MISSING naming every
account + dimension; the bulk-book route runs the same policy before its
RPC; storno/correction paths never pass through commitEntry so history
always reverses regardless of policy; rule fetches fail open incl.
thrown exceptions
- chart of accounts: per-account Dimensionsregler section in
EditAccountDialog (Krävs/Förval/Låst, value picker, pause switch),
gated on the existing dimensions toggle, quiet when empty
- pickers: LineDimensionFields is registry-driven (one combobox per active
dimension, cached fetch, hardcoded 1/6 fallback) — every existing mount
lights up custom dims with zero changes
- agent briefing: per-dimension required_on_accounts/default_on_accounts
so agents self-correct instead of bouncing off the policy error
- rules CRUD API with existence/active/company validation and qualified
DTO ids; firm_id FK deferred until the firms table lands (per plan)
39 new tests (pure-fn rules, engine enforcement, both new API surfaces,
pg-real RLS/CHECK/cascade suite); full suite 6,791 green; migration
replayed on a fresh container.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: renumber migration to 20260703200000 — version collision with prod
The concurrent session shipped pending_operations_add_link_document_to_voucher
as 20260703120000 today; the Supabase preview branch (cloned from prod)
rejected the duplicate version key.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: review round — auto-pick retry on collision, fail-open warnings, query schema
- POST /api/dimensions retries once past a concurrent number claim when the
number was auto-picked (explicit choices still 409)
- every fail-open skip of the dimension-rules policy now logs a structured
warning (engine draft/commit paths + bulk-book) — deliberate fail-open,
but observable
- GET /api/dimensions/rules validates its query through
ListDimensionRulesQuerySchema instead of an inline regex
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Phase 3 of dev_docs/dimensions_implementation_plan.md. Companies with
dimensions_enabled=false see zero change; existing free-text API writers keep
working (validation is toggle-governed).
Engine (soft validation):
- validateEntryDimensions() in dimension-resolver: zero queries for untagged
entries; toggle off → passthrough; toggle on → one settings fetch + two
registry queries, rejects unknown dims/codes and archived values with
Swedish per-code messages (DimensionValidationError, 400, details.issues).
Wired into createDraftEntry + updateDraftEntry before any insert; reversal/
storno paths untouched (verbatim copies). Fails open on transient registry
errors — soft validation must never block bookkeeping.
MCP (agent write path):
- New tools: gnubok_list_dimensions, gnubok_list_dimension_values (fuse.js
fuzzy), gnubok_create_dimension_value (STAGED via pending_operations —
agents never silently mint reporting values; new op type + CHECK migration
+ executor with duplicate-idempotency).
- create_voucher/correct_entry: per-line dimensions bag + default_dimensions,
resolve-don't-select server-side (code OR natural-language name; exact →
fuzzy ≤0.30 with ≥0.15 runner-up margin; non-exact resolutions echoed with
confidence; ambiguous → ranked candidates, no auto-create).
- gnubok_get_agent_briefing gains a dimensions block (enabled, dims, top
values) — omitted when registry empty.
- TOOL_SCOPE_MAP entries; risk tier low for staged value creation.
UI:
- JournalEntryForm (manual voucher + TransactionBookingDialog embed): header
"+ Kostnadsställe/Projekt" progressive disclosure (gäller alla rader with
documented inheritance rule) + per-row tag popover + compact KS·PR badges;
gated on dimensions_enabled.
- Voucher detail: display-only dimension badges with registry-name resolution.
- EditDraftEntryDialog carries line dimensions so editing a draft no longer
strips tags.
categorize/bulk_book dims deferred to PR7 (needs the bulk_book RPC migration).
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>