feat(mcp): onboarding flow v2: migration-first SIE import in chat, one-confirm momentum, extended first-year heuristic (#1949)

Three changes from the first real E2E run (Arcim, 2026-08-26):

1. gnubok_sie_preflight: read-only scan of a SIE file shared in chat
   BEFORE anything is staged: parse, validate (per-verifikat balance, IB,
   closed-year P&L residual), CP1252-mojibake tripwire, duplicate
   file/period check, org-number match against the company (the
   wrong-company import is the worst silent failure this flow can have),
   and suggested account mappings shaped for direct passthrough to
   gnubok_import_sie. Both tools now also accept file_content_base64,
   decoded with the same encoding detection as the HTTP upload route so
   CP437 exports keep their åäö.

2. Onboarding skill v2: opens with TWO questions (orgnr + 'vilket system
   hade du innan?'), imports history before the bank (PSD2 rarely reaches
   far enough back), and a momentum rule: the create preview is the ONLY
   stop; connect tools are called without asking, and categorization
   starts as soon as the bank is active. connect_bank instructions now
   describe the account-selection dialog that actually gates the first
   sync, and the bank history cap.

3. deriveFirstYearDefaults: no closed fiscal period in the registry now
   extends the first-year window from 12 to 18 months (BFL 3 kap 3 §):
   a 13-month-old company with no annual report is still in its first,
   extended räkenskapsår (the Arcim case the 12-month rule missed).
   Applied in the web journey and the lookup tool.

tools/list ceiling 61.5K to 62K, documented in the bench.

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-08-26 14:16:40 +02:00
committed by GitHub
co-authored by Jakob Wennberg Claude Fable 5
parent 52bfd7a399
commit b436d47b64
8 changed files with 516 additions and 90 deletions
@@ -514,7 +514,9 @@ export default function OnboardingJourney({
? parseStartMonthDay(state.ticLookup?.fiscalYear?.startMonthDay)
: null
const firstYearSuggested = state.lookupRan
? deriveFirstYearDefaults(state.ticLookup?.registrationDate).isFirstFiscalYear
? deriveFirstYearDefaults(state.ticLookup?.registrationDate, Date.now(), {
noClosedPeriod: state.ticLookup?.fiscalYear == null,
}).isFirstFiscalYear
: false
const confirmMode = startMonth !== null
const title = confirmMode ? t('journey_fy_confirm_title') : t('journey_fy_ask_title')