c90ccc9c429277299fd4ecec0652cd8b6fa080be
13
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1976129478 |
feat(import): let the Fortnox import fetch older fiscal years: the three-year limit becomes a default selection (#2280)
* fix(import): say which fiscal years the Fortnox connection fetches, list the ones left out Root cause: the guided provider migration fetches SIE only for fiscal years that start within a rolling three-calendar-year window (getAllowedFiscalYears in extensions/general/arcim-migration/lib/sie-fetcher.ts: current year and the two before it). A first, broken year 2022/2023 starts in 2022 and falls outside the window in 2026, and the wizard said nothing: not before the import, not after. Users concluded the books were complete, or that they had done something wrong (issue #2211, second report via support 2026-08-27). Fix: - The fetcher already lists every fiscal year at the source before applying the window, so the left-out years are derived from that same list at no extra provider call: `omittedYears` (years starting before the window, oldest first, with the provider's own from/to dates so a broken year is named as "2022-09-01 till 2023-12-31"). Fortnox and Briox year refs now carry those bounds; WINT's listYears reports the unfiltered year list. - GET /preview returns `fiscalYearWindow` and `omittedYears`; GET /sie-data returns `omittedYears` next to `failedYears`. - Wizard, preview step (before the import runs): one muted sentence that the direct connection fetches the three latest fiscal years (years starting in {fromYear} or later); when years are left out, they are named with a link to the SIE import (one SIE file per year under Import, oldest first). - Wizard, result step: a "Räkenskapsår som inte följde med" section naming the omitted years with the same SIE pointer, shown when SIE data was imported in the run. - MCP: the connect_migration tool description, its instructions and the onboarding skill claimed the wizard "fetches every fiscal year"; they now say three latest, older years via SIE. - Strings in both messages/sv.json and messages/en.json. Out of scope: fetching more years through the connection (#2238). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015qgLgdt4mLmha1ZLFMwq1u * feat(import): make the Fortnox import's three-year limit a default selection, not a cap Root cause, from first principles: the guided provider migration fetched SIE only for fiscal years starting within a rolling three-calendar-year window (getAllowedFiscalYears in extensions/general/arcim-migration/lib/sie-fetcher.ts, introduced in #718 with no stated reason). The window was a silent cap: the wizard never said it existed, and a first broken year 2022/2023 simply never arrived (#2211). The user's actual problem is that the year is missing from the books, so explaining the cap (the previous commit) treats the symptom. What the window gated, by evidence: only the SIE fetch. Documents already list every Fortnox financial year and match against the vouchers that exist locally (import-documents.ts), invoices, customers, suppliers and assets are not year-gated, and the SIE import itself is one request per year (hosted function limit 300 s, import_sie_journal_entries statement_timeout 290 s), so its cost is linear in wall time and bounded per year regardless of how many years are imported. The only place the number of years multiplies inside one invocation is /preview and /sie-data: one SIE export per year (Fortnox client: 15 s per-call timeout, 3 attempts, backoff up to 30 s, 4 req/s) fetched and parsed inside a single 300 s function, and /sie-data returns every raw file in one response. The repo holds no measurement of Fortnox's per-year SIE export latency, and the maintainer's memory is that a full history can take unreasonably long, so a fixed lift to every year cannot be shown safe for a long history. Fix: the window becomes the DEFAULT selection, and the user chooses. - sie-fetcher: fetchProviderSieFiles takes `years` (explicit start years); without it the default window applies. The result carries `sourceYears` (every year at the source, oldest first, with the provider's own bounds and an inDefaultSelection flag) and `omittedYears` (source years outside the selection). Both derived from the year list already fetched: no extra provider call. Fortnox and Briox year refs carry their bounds; WINT's listYears reports the unfiltered list and its voucher chain follows the selection. - GET /preview returns `sourceYears`; GET /sie-data honours `?years=` (validated, deduplicated, oldest first; 400 VALIDATION_ERROR when malformed) and returns `omittedYears`. PROVIDER_SIE_NO_YEARS names the selection. - Wizard, preview step: a "Räkenskapsår att hämta" picker with one checkbox row per source year, the three latest ticked by default, older years marked "tar längre tid"; Fortsätt is disabled with an attn line until at least one year is ticked. The selection is sent to /sie-data, so each extra year is the user's own wait, and it fails loudly there, before any ledger write, if it is too much. - Wizard, result step: the per-year lines already report exactly what was imported; a "Räkenskapsår som inte hämtades" section names the source years outside the selection, with the re-run path (documents come along) and the SIE path. - MCP connect_migration description, instructions and the onboarding skill say "three latest by default, older years selectable" instead of "every fiscal year". - Strings in both messages/sv.json and messages/en.json. Closes #2238 as well: the wish to fetch more years is the same control. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015qgLgdt4mLmha1ZLFMwq1u * fix(import): bound the fiscal-year selection per import run Superagent P2 on #2280: the `years` selection was unbounded and every selected year is one provider export fetched and parsed inside the single 300 s /sie-data invocation, so nothing bounded the work before provider calls. The bound: MAX_SELECTED_FISCAL_YEARS = 6, exported from sie-fetcher.ts with the derivation. One export call is 15 s per attempt (Fortnox client FETCH_TIMEOUT_MS), 3 attempts with 1 s and 2 s backoff (retry defaults), so a year that times out on every attempt costs 48 s; six such years are 288 s, leaving 12 s of the 300 s hosted function for the year listing, parsing and the response; seven would be 336 s. Enforced server-side: - /sie-data refuses a selection of more than the cap with 400 VALIDATION_ERROR naming the cap, before the consent is resolved, so an oversized request does no provider work. - fetchProviderSieFiles throws FiscalYearSelectionError for a selected year the source does not have, right after the year listing and before any export; /sie-data maps it to 400 VALIDATION_ERROR naming the year. - /preview returns maxSelectedYears so the picker enforces the same number without a client-side copy: Fortsätt is disabled and an attn line says how many can be fetched at once and that older years go in a second run (sv + en). Tests: cap accepted at 6 and refused at 7 with no provider call, unknown year refused (route and fetcher), the cap's arithmetic, maxSelectedYears on /preview. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015qgLgdt4mLmha1ZLFMwq1u --------- Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
dae0aac26a |
fix(mcp): reconcile_match callable + two-phase efterkontroll + instant value for web-onboarded users (#1967)
* docs(plugin): starter prompt nudges the connector's onboarding guide Several E2E runs composed the first reply from tool descriptions before the skill loaded (questionnaire instead of the guided round). Four words in the published prompt point the agent at the guide from message one; the rest of the prompt stays memory-first and universal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(mcp): reconcile_match into the default catalog + two-phase efterkontroll + instant value for web-onboarded users E2E #12 (the smoothest run yet) surfaced three things: 1. gnubok_reconcile_match was search-only, so Claude.ai could not call it: the agent misread the uncallable tool as a missing reconciliation:write scope and punted the entire dont-double-book matching step to the web app. Promoted to the default catalog (the standing rule: skill-instructed tools must be callable); ceiling 63K to 63.4K documented. 2. Skill: efterkontroll split into two phases per founder direction. Step 3b runs DIRECTLY after the import commits: verify the trial balance, sanity-read the content, and PREPARE the chart (create 1630/8423/8314/6992 when the SIE lacks them) so the bank and Skatteverket connections land in a book that is ready for them. Step 4b after the connections: match SIE-covered bank rows with reconcile_match (never re-categorize), reconcile skattekontot to the öre, names, underlag, in a prioritized numbered list. 3. Skill: users who onboarded via the web app and connect the MCP with everything already set up get the reconciliation pass and Att göra-list as the FIRST reply instead of setup steps: immediate value regardless of onboarding path. 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> |
||
|
|
c2f055b903 |
fix(bank): 90-day lookback is the default: long PSD2 requests make some banks kill the session (#1964)
E2E #11: the account picker's fiscal-year default sent a 365-day request for a 405-day-old fiscal year; Swedbank answered by TERMINATING the session: zero transactions, connection expired, no error surfaced (initial_sync_requested_from 2025-08-26, returned min/max null). 90 days worked. - Default lookback mode is now 'fast' (90 days), labeled rekommenderas on a first connect; the fiscal-year option stays but carries an inline 'vissa banker avbryter kopplingen' note when its span exceeds 90 days, and the long-range helper names the real failure mode + the SIE/CSV path for older history. - SIE drop card: stage + arm in ONE click (three clicks was one too many): after the verdict, the single button reads 'Bokför: oåterkalleligt (BFL 5 kap 5 §)' and the deliberate click commits with confirmed=true. - Skill: never re-ask an answered question; when a connect card rendered, do not paste the URL as text too. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
53c4d0d194 |
feat(mcp): approve the SIE import in the drop card + post-import efterkontroll in the skill (#1963)
E2E #10 (the first fully successful drop-card run) left the staged import stranded until the user prodded the agent, and the agent then improvised an excellent post-import audit (skattekonto reconciliation, missing 1630, over-stated payroll liabilities). Codify both: 1. The drop card now carries the approval: after staging, the button becomes 'Godkänn bokföringen' with a two-click BFL confirmation (confirmed=true armed on the deliberate second click, exactly the pending-operations widget pattern), then 'Bokfört' + a ui/updateContext pointing the agent at trial balance and voucher-gap follow-ups. 2. Skill: when the user writes after a card was shown, the FIRST call is list_pending_operations (an empty ledger does not mean the file never arrived); new Step 4b 'efterkontroll' codifies the audit pass (trial balance vs SIE, skattekonto vs 1630 with 8423/8314/6992 for ränta/avgifter, auto-created bank account names, underlag coverage, voucher gaps); memory-first extended with memory-back (save orgnr, bank, fiscal year, moms period after creation so the next conversation needs zero questions). Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d8244ecaff |
feat(mcp): connect_migration: one-click card into the previous-system wizard (#1960)
* feat(mcp): gnubok_connect_migration: one-click connect card into the previous-system wizard 'Jag hade Fortnox' now gets the same feel as Skatteverket: the tool returns the migration-wizard link for the named provider and renders the connect-card widget (new migration branch: 'Hämta från Fortnox', button opens the wizard that logs into the old system and fetches all fiscal years plus invoices, customers, suppliers and documents). For visma/bokio (no API export) the instructions order the SIE drop card first and this card as the complement. Scope companies:read; skill step 3 points at the tool instead of raw wizard links; ceiling 62.4K to 63K documented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(mcp): 5-minute freshness hint on tools/list, widgets and prompts: the catalog changes with every deploy The stateless-client CacheableResult hint on tools/list, resources/read (widget HTML) and prompts/list was 1 hour. Claude.ai honors it, so for up to an hour after a deploy the connector served a pre-deploy catalog: a freshly shipped tool flapped in and out of the tool list depending on which fetch hit the client cache, and two E2E runs dead-ended on 'tool does not exist' for a tool that was live server-side. These payloads are static only within one deploy; 5 minutes bounds the stale window. 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> |
||
|
|
5715dd3def |
docs(mcp): onboarding skill branches on the named previous system (#1959)
'Jag hade Fortnox' now has a real answer instead of one generic SIE instruction: API-connected systems (Fortnox/BL/Briox/Wint) get two offered paths (full migration wizard with invoices/customers/documents vs quick SIE drop, recommended by need), Visma/Bokio get the file-first path with the wizard as a complement after, unknown systems get the universal SIE export ask. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
0f7625535b |
feat(mcp): drag-and-drop SIE import card: exact bytes via tools/call, no model in the byte path (#1957)
E2E #6: the flow ordered SIE-first correctly, but the agent never discovered gnubok_create_sie_upload, ran a local preflight, and sent the user to the web wizard again; it also rendered a duplicate generic bank card before the Swedbank-specific one. 1. New sie-drop widget (ui://sie-drop/app.html), rendered definition-level by gnubok_create_sie_upload: the user drags the .se/.sie file onto the card, the widget reads the EXACT bytes (FileReader), computes sha256 (WebCrypto), calls gnubok_sie_preflight via tools/call with file_content_base64 + sha256, shows the verdict, and on Importera stages gnubok_import_sie with the preflight's mappings. No network from the iframe, no model reproduction: byte path goes through the host bridge only, narrated into chat via ui/updateContext. 2. The inline size cap now applies only WITHOUT sha256: a hash-verified payload is byte-exact by proof, so the widget's 100 KB+ base64 passes while unhashed model-retyped content stays refused. 3. Discovery + ordering fixes: create_sie_upload/preflight/import descriptions name the card path explicitly; create_company's history_note points at the card; connect_bank description says pass bank on the FIRST call when the user has named it (the duplicate generic card came from a bare call followed by the nudged retry). Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
cd9fb5b717 |
feat(mcp): byte-exact SIE upload path + brevity and memory-first onboarding (#1954)
From the fourth E2E run: the agent correctly refused to reproduce a 104 KB SIE file token by token (silent mid-verifikat truncation) and dead-ended to the web wizard, and its replies were walls of compliance prose. 1. gnubok_create_sie_upload: signed same-origin upload URL (reuses the pending-document infra; .se/.sie/.si only, 50 MB HTTP cap). gnubok_sie_preflight and gnubok_import_sie accept upload_id as the byte-exact source, plus optional sha256 (hex of the raw bytes) verified on the upload_id/base64 paths so truncation is DETECTED, never silent. Inline content above 120k chars is refused with a pointer to the upload flow. Scope bookkeeping:write (same intent as import_sie). 2. Skill: brevity rule (max ~8 short lines per reply, one warning per step, no legal essays), memory-first rule (check what is already known before asking the opening questions), the upload-first SIE step, and gnubok_explain_voucher_gap after import for skipped voucher numbers. 3. CONNECTORS.md starter prompt rewritten memory-first so it stays copy-paste ready without the user's own data in it. Plugin v1.2.2. tools/list ceiling 62K to 62.4K 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> |
||
|
|
4af7469523 |
feat(onboarding): minimal input: orgnr + moms period is the whole ask (#1952)
* feat(onboarding): minimal input: orgnr + moms period is the whole ask
Two fixes from the third E2E attempt (2026-08-26):
1. accounting_method is now optional in CompanySetupSchema and defaults by
form in planCompanySetup: aktiebolag = accrual (the norm), enskild
firma = cash (the common small-EF choice; legal under 3 MSEK, BFL 4
kap 4 paragraf). The plan flags the default (resolved.accountingMethodDefaulted)
and gnubok_create_company's preview carries accounting_method_defaulted
so the readback names it and the user overrides in the same 'ja'.
Never silent: the preview is the checkpoint. Applies to the MCP tool
and POST /api/v1/companies (additive; response shows the resolved
value). The lookup tool's still_to_ask no longer lists it.
2. The agent refused a real orgnr because the user said 'nytt bolag' and
the registry showed an established company ('Stopp. Numret matchar
inte ett nytt bolag'): lookup instructions now state that an
established company with F-skatt/VAT is the NORMAL case (new = new to
Accounted) and the orgnr is never second-guessed for looking
established.
Skill + plugin (v1.2.1) updated; API skill regenerated; DECISIONS.md entry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(onboarding): surface the kontantmetod 3-MSEK condition on the defaulted cash method
Compliance-review finding on #1952: the EF cash default carries a legal
eligibility condition (turnover normally under 3 MSEK, BFL 4 kap 4 §)
that a client not reading the onboarding skill would never see. The
create preview now carries accounting_method_note with the condition
whenever cash was defaulted, and the v1 pitfall states it for API
integrators. The registry cannot verify turnover, so the confirm-time
human check is the gate; the default itself stays (a brand-new EF has
zero turnover by definition).
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>
|
||
|
|
ec9cab24cc |
feat(mcp): ask the bank first: connect link deep-starts the named bank's consent (#1951)
* feat(mcp): ask the bank first: connect link deep-starts the named bank's consent The connect card used to open the generic picker page; the user then chose the bank there. The agent now asks 'vilken bank har företaget?' among the opening questions and passes it to gnubok_connect_bank, whose connect_url becomes /import?mode=psd2&bank=<name>. BankSelector resolves the name (exact, then unique prefix, then unique substring: ambiguous names fall back to the prefilled picker rather than guessing an institution) and auto-starts that bank's consent through the same onConnect handler, so the duplicate-pending and renew-instead guards stay fully interactive. The param is stripped via history.replaceState after the one-shot so an aborted bank flow plus back-navigation does not silently relaunch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(mcp): first-year suggestion keeps the AB vs enskild firma distinction Compliance-review finding on #1949: the suggestion text collapsed both forms onto a 31 December end. Only an enskild firma's first year MUST end 31 December; an AB may pick any end within BFL 3 kap 3 §'s 18-month cap, with 31 December as the common default. The lookup tool's still_to_ask line and the skill now say so explicitly, and first-year-defaults documents that fiscalYear-null is a strong-not-perfect filed-report signal that must only ever feed confirm-question suggestions. 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> |
||
|
|
b436d47b64 |
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> |
||
|
|
8ddc77fdfd |
feat(mcp): org-number-first onboarding: gnubok_lookup_company prefills the company from the registry (#1940)
The onboarding flow now mirrors the web wizard: ask for the organisationsnummer first, look the company up in the public registry (one TIC Lens call through the extracted extensions/general/tic/lib/lookup.ts, shared with the /lookup HTTP route), and present the facts for confirmation instead of interrogating the user. The new gnubok_lookup_company tool (companies:read, company-independent, default catalog) returns the registry facts, a prefilled suggested_create_company_input, and a still_to_ask list that encodes the same fact-vs-question rules as lib/onboarding-journey/reducer.ts: F-skatt is a fact both ways, VAT is a fact only when positively registered (ML 17 kap 24 paragraf), moms period and accounting method are always asked, an enskild firma's verksamhetsnamn is the user's choice, and a known fiscal year becomes a confirm question. Registry outages degrade to the full question list instead of failing onboarding. The onboarding skill and the plugin's /accounted:setup command are updated to the orgnr-first flow (plugin 1.2.0). tools/list ceiling bumped 61.2K to 61.5K with the reason 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> |
||
|
|
31e0cd6e05 |
feat(onboarding): company setup from the conversation and POST /api/v1/companies (#1814 PR 3) (#1864)
* feat(onboarding): company setup from the conversation and POST /api/v1/companies Third PR of agent-first onboarding (#1814). Once connected, the agent can now set up a company end to end without the web wizard, and partner platforms can provision companies over REST. - create_company_for_user: service-role-only SECURITY DEFINER twin of create_company_with_owner taking the owner explicitly (service clients have no auth.uid()). pg-real test covers creation, role gating, unknown owner and foreign team. - lib/company/create-company.ts: the wizard's creation sequence (org number, TIC snapshot, BAS chart, settings, first fiscal period, tax deadlines, rollback) extracted into createCompanyCore; the Server Action delegates to it, behaviour unchanged. - lib/company/onboarding-input.ts: one Zod schema + planner for the agent/API paths; a VAT-registered company without moms_period is refused (a missing period silently yields zero VAT deadlines). - MCP: gnubok_create_company (two-phase: preview, then confirm=true; companies:write, company-independent), gnubok_connect_bank and gnubok_connect_skatteverket (status + the browser link, gated on bank_sync / skatteverket, search-only in the catalog), the "onboarding" skill, and initialize instructions pointing at it. - Consent page pre-ticks companies:write for an account with no company yet, so the setup does not dead-end on insufficient scope after signup. - POST /api/v1/companies (companies:write, dry-run aware) on the same core; scope map, registry, spec snapshot and the generated API skill updated. - tools/list payload ceiling raised 59.95K -> 60.4K for the one new default-catalog tool (documented in the guard). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018wCdzRTatKiDByKB8hCNT6 * fix(onboarding): explicit f_skatt, org number when VAT-registered, EF first year ends 31 Dec Review findings on #1864 (Swedish compliance review): - f_skatt is required, never defaulted to approved (SE-R-005 risk). - org_number is required when vat_registered: the invoice momsregistreringsnummer derives from it (ML 17 kap 24 §). - An enskild firma's first fiscal year must end on 31 December and its start month is forced to 1 even with first_fiscal_year set, mirroring the wizard's own rule text (BFL 3 kap. 1 §). - POST /api/v1/companies no longer claims Idempotency-Key support (the wrapper only honours it on company-scoped routes). - pg-real: createCompanyCore's chart seed runs under the real service_role, which the unit tests could not prove. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018wCdzRTatKiDByKB8hCNT6 * test(pg): starter chart has 41 accounts, assert non-empty The service_role chart-seed proof passed the part that mattered (no 42501 from seed_chart_of_accounts) and failed on a wrong row-count guess: the seeded chart is a curated starter set, not the full BAS list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018wCdzRTatKiDByKB8hCNT6 * fix(migrations): move create_company_for_user to 20260825120000 main gained 20260824170000_bulk_book_transactions_service_actor.sql with the same version while this branch was open; two files on one version abort every Supabase branch apply and the prod auto-apply. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018wCdzRTatKiDByKB8hCNT6 * chore(api): refresh spec snapshot and generated skill after rebasing onto main Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018wCdzRTatKiDByKB8hCNT6 * fix(mcp): flat create_company result, refuse localhost connect links, test hygiene CodeRabbit on #1864: the confirmed-create result was wrapped in the { data, next } envelope while its outputSchema promised top-level fields; it now returns the fields with next as a sibling. The two connect-link tools refuse to build a link when NEXT_PUBLIC_APP_URL is unset instead of handing a remote user a localhost URL. Tests clear mocks and the event bus in beforeEach. Not changed: the rollback already survives user_preferences.active_company_id (that FK is ON DELETE SET NULL since 20260331010000), and v1 error details stay in the surface's English developer convention. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018wCdzRTatKiDByKB8hCNT6 --------- Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |