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(skatt): setup gates + auto-loading momsdeklaration across Skatt & bokslut tabs
Every tab in the Skatt & bokslut nav group now tells an unconfigured user
what is missing and where to fix it, instead of dead-ending or rendering
zeros:
- Momsdeklaration: gates on vat_registered with a settings CTA; auto-fetches
the configured period on load and on every period change (no more "Hämta"
button); one period control (räkenskapsår picked inline for helårsmoms,
shell selector + back link dropped via new ReportDescriptor.standalone);
raw <select>s replaced with the Select primitive; banner when moms_period
is missing; BankID connect returns to the page instead of the report
library.
- Deadlines: callout (sv+en) when no system-generated tax deadlines exist —
they are derived from tax settings, so point at /settings/tax rather than
presenting an empty manual todo list.
- Årsbokslut: "no räkenskapsår yet" (CTA to bookkeeping settings) is now
distinguished from "nothing to close yet".
- Skattekonto: non-auth fetch failures render an error card with retry
instead of the misleading "inget saldo hämtat ännu" empty state.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(skatt): address bot review — res.ok guard, blocking moms_period gate, panel hidden while räkenskapsår unresolved
- Auto-fetch treats non-2xx or unparsable responses as errors (with retry)
instead of rendering undefined data.
- momsPeriodMissing now blocks the declaration (EmptyState + settings CTA)
rather than fetching a guessed quarterly period behind a banner — a
declaration submittable for the wrong period type is a hazard, not a
convenience.
- SkatteverketPanel is not rendered while yearly mode awaits a fiscal
period, so its actions can never target an unconfirmed period.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(ux): create salary runs, employees & recurring schedules in modals
The last three full-page create flows move to ?new=1 URL-driven dialogs,
matching the verifikat/invoice pattern (#861):
- Salary run: 4-field form on /salary — creation was pure interruption
before landing on the run-detail workspace.
- Employee: the last register entity still page-based after customers,
suppliers, and articles.
- Recurring schedule: consistency with the invoice modal it feeds.
Old /new routes survive as redirects so bookmarks and agent intents keep
working. Dialogs close explicitly (header X / Avbryt) so half-typed forms
survive stray Escape or backdrop clicks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs: move DECISIONS.md to repo root
dev_docs/ is gitignored, so the decision log was invisible to other
developers. Root matches the existing convention (CONTRIBUTING.md,
SECURITY.md). CLAUDE.md pointer updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(lint): ignore Claude Code worktrees in eslint walk
.claude/worktrees/ holds full repo copies; without the ignore, local
npm run lint / check:lint walks them until the ratchet's 64 MB JSON
parse buffer overflows. CI is unaffected (no worktrees there).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>