/** * Granskningsskript för revisionerna m3.2.1 → m3.3.1 → m3.4.0. * m3.4.0 redovisas separat i avsnitt 8: C. rättat omställningsstöd (grossSupportBase), * skilt från nya scenarioantaganden (nya scenarier och variant). * Kör: bun run scripts/granskning.ts > AVSTAMNING.md * * Föregående version ligger oförändrad i audit/m3.2.1/. Två ändringar redovisas var * för sig: * A. Rättad avgränsning av produktionsunderlaget (privateSurplusScope): * marknadssektorernas lönesumma och överskott ur sektorsräkenskaperna. * B. Omformulerat tillväxtscenario (relativeGrowth): AI-avvikelse i basårets * ekonomi mot samma referens som övriga scenarier, uteblivna jobb utan * automatiskt stöd. */ import { EMPTY_POLICY, MODEL_SWITCHES, MODEL_VERSION as V_CUR, calibrate, evaluate, evaluateGrowth, growthRelative, reference, simulate, type PolicyParams, type ScenarioParams, } from "../src/model/engine"; import { SCENARIOS, SCENARIOS_IN_DISPLAY_ORDER, GROWTH_VARIANTS, growthVariantParams, explainGrowthJobs } from "../src/model/scenarios"; import { DATA, DATA_VERSION, SECTOR_DATA_VERSION, SECTOR_SOURCE, YEARS } from "../src/data/dataset"; import sectorRaw from "../src/data/eurostat-sektorer-se-2026-09-23.json"; import * as Old from "../audit/m3.2.1/model/engine"; import { SCENARIOS as OLD_SCENARIOS } from "../audit/m3.2.1/model/scenarios"; const YEAR = 2024; // Avsnitt 1–10 är avstämningen för m3.4.0 och räknas med m3.4.0:s förval. m3.4.1 ändrar bara // förvalet för "AI tar över en stor del av jobben" (fall C) och redovisas i avsnitt 11. const V_NEW = "m3.4.0"; const CAPITAL = SCENARIOS.find((s) => s.id === "capital")!; const CAPITAL_C = { ...CAPITAL.params }; Object.assign(CAPITAL.params, { jobsLostPct: 20, aiImportCost: 160 }); const n = (v: number, d = 1) => Number.isFinite(v) ? v.toLocaleString("sv-SE", { minimumFractionDigits: d, maximumFractionDigits: d }) : "–"; type Sw = typeof MODEL_SWITCHES; function withSwitches(sw: Partial, fn: () => T): T { const saved = { ...MODEL_SWITCHES }; Object.assign(MODEL_SWITCHES, sw); try { return fn(); } finally { Object.assign(MODEL_SWITCHES, saved); } } const OFF: Partial = { privateSurplusScope: false, relativeGrowth: false, grossSupportBase: false }; const SCOPE: Partial = { privateSurplusScope: true, relativeGrowth: false, grossSupportBase: false }; const REL: Partial = { privateSurplusScope: false, relativeGrowth: true, grossSupportBase: false }; const ALL: Partial = { privateSurplusScope: true, relativeGrowth: true, grossSupportBase: false }; const CUR: Partial = { privateSurplusScope: true, relativeGrowth: true, grossSupportBase: true }; type R = { tax: number; exp: number; bal: number; other: number }; /** Förändring mot jämförelsepunkt; för tillväxt i m3.2 är det nyanställningsvägen. */ function run(id: string, p: ScenarioParams, policy: PolicyParams = EMPTY_POLICY): R { const cal = calibrate(YEAR); if (id === "growth") { const g = evaluateGrowth(cal, p, policy); return { tax: g.final.taxTotal - g.baseline.taxTotal, exp: g.final.expenditureTotal - g.baseline.expenditureTotal, bal: g.final.balance - g.baseline.balance, other: g.final.otherRevenue - g.baseline.otherRevenue, }; } const e = evaluate(cal, p, policy); return { tax: e.final.taxTotal - e.ref.taxTotal, exp: e.final.expenditureTotal - e.ref.expenditureTotal, bal: e.final.balance - e.ref.balance, other: e.final.otherRevenue - e.ref.otherRevenue, }; } function runOld(id: string, p: Old.ScenarioParams, policy: Old.PolicyParams = Old.EMPTY_POLICY): R { const cal = Old.calibrate(YEAR); if (id === "growth") { const g = Old.evaluateGrowth(cal, p, policy); return { tax: g.final.taxTotal - g.hiring.taxTotal, exp: g.final.expenditureTotal - g.hiring.expenditureTotal, bal: g.final.balance - g.hiring.balance, other: g.final.otherRevenue - g.hiring.otherRevenue, }; } const e = Old.evaluate(cal, p, policy); return { tax: e.final.taxTotal - e.ref.taxTotal, exp: e.final.expenditureTotal - e.ref.expenditureTotal, bal: e.final.balance - e.ref.balance, other: e.final.otherRevenue - e.ref.otherRevenue, }; } const ref = reference(calibrate(YEAR)); let out = `# Avstämning m3.2.1 → ${V_NEW} Dataversion ${DATA_VERSION} och ${SECTOR_DATA_VERSION}. Basår ${YEAR}, inga egna skatte- eller utgiftsändringar. Belopp i miljarder kronor per år i basårets penningvärde. Genererad av \`scripts/granskning.ts\`. Föregående modellversion ligger oförändrad i \`audit/m3.2.1/\`. Tillväxtscenariot har två varianter; förvalet är "Företagen växer utan fler jobb". ${V_NEW} rättar omställningsstödet och lägger till två scenarier och en variant; se avsnitt 8. ## 1. Produktionsunderlaget: källa och avgränsning Källa: ${SECTOR_SOURCE.title}, tabell \`${SECTOR_SOURCE.table}\`, ${SECTOR_SOURCE.url}. Uttag ${SECTOR_SOURCE.retrieved}, tabellen uppdaterad ${SECTOR_SOURCE.datasetUpdated}. Miljoner kronor, löpande priser, redovisad sida (PAID). Oförändrad rådata: \`src/data/eurostat-sektorer-se-2026-09-23.json\`. Marknadssektorer = icke-finansiella bolag (S.11), finansiella bolag (S.12) och hushållens näringsverksamhet (S.14). Undantas: offentlig sektor (S.13), ideella organisationer (S.15) och hushållens driftsöverskott B2G (främst egnahem, beräknad boendetjänst). | År ${YEAR}, mdkr | Definition | Belopp | | --- | --- | --- | `; const ser = (sectorRaw as { series: Record> }).series; const g = (k: string) => (ser[k]?.[String(YEAR)] ?? NaN) / 1000; const rowsSrc: [string, string, number][] = [ ["D1, hela ekonomin (S.1)", "Ersättning till anställda", g("S1.D1")], ["D1, S.11 + S.12 + S.14", "Ersättning till anställda, marknadssektorer", g("S11.D1") + g("S12.D1") + g("S14.D1")], ["D1, S.13", "Offentlig sektor (ingår inte)", g("S13.D1")], ["D1, S.15", "Ideella organisationer (ingår inte)", g("S15.D1")], ["B2A3G, hela ekonomin (S.1)", "Driftsöverskott och blandinkomst, brutto", g("S1.B2A3G")], ["B2A3G, S.11", "Icke-finansiella bolag", g("S11.B2A3G")], ["B2A3G, S.12", "Finansiella bolag", g("S12.B2A3G")], ["B3G, S.14", "Blandinkomst, hushållens näringsverksamhet", g("S14.B3G")], ["B2G, S.14", "Hushållens driftsöverskott, främst egnahem (ingår inte)", g("S14.B2G")], ["B2A3G, S.13", "Offentlig sektor, i praktiken kapitalförslitning (ingår inte)", g("S13.B2A3G")], ["B2A3G, S.15", "Ideella organisationer (ingår inte)", g("S15.B2A3G")], ]; for (const [a, b, c] of rowsSrc) out += `| ${a} | ${b} | ${n(c)} |\n`; const calOld = withSwitches(OFF, () => calibrate(YEAR)); const calNew = calibrate(YEAR); const pvOld = DATA[YEAR]!.compensation * calOld.privateWageShare * (1 + calOld.employerTaxRatio) + calOld.privateSurplus; const pvNew = DATA[YEAR]!.compensation * calNew.privateWageShare * (1 + calNew.employerTaxRatio) + calNew.privateSurplus; out += ` Summakontroll: S.11 + S.12 + S.13 + S.14 (B2G + B3G) + S.15 = ${n(g("S11.B2A3G") + g("S12.B2A3G") + g("S13.B2A3G") + g("S14.B2G") + g("S14.B3G") + g("S15.B2A3G"))} mdkr mot S.1 ${n(g("S1.B2A3G"))} mdkr. | Storhet (${YEAR}) | m3.2.1 | ${V_NEW} | Status i ${V_NEW} | | --- | --- | --- | --- | | Andel av D1 som jobbantagandena verkar på | ${n(calOld.privateWageShare * 100, 2)} % | ${n(calNew.privateWageShare * 100, 2)} % | bearbetad uppgift (tidigare redaktionellt antagande) | | Överskott i produktionsunderlaget, mdkr | ${n(calOld.privateSurplus)} (hela ekonomin) | ${n(calNew.privateSurplus)} | bearbetad uppgift | | Produktionsunderlag, mdkr | ${n(pvOld)} | ${n(pvNew)} | arbetskraftskostnad + överskott, samma verksamheter | Andelarna beräknas för varje år ur sektorsräkenskaperna och tillämpas på modellens D1 och B2A3G. Nivån på bolagsskatten och övriga skatter är fortsatt kalibrerad mot verifierade intäkter; bara förändringsberäkningen använder den nya avgränsningen. ## 2. Före och efter per scenario Förändring mot jämförelsepunkt. I m3.2.1 och i steg 2–3 är tillväxtscenariots jämförelsepunkt nyanställningsvägen (framtidsekonomins skala); från steg 4 är jämförelsepunkten utgångsläget i basåret, som för övriga scenarier. | Scenario | Steg | Skatteintäkter | Utgifter | Offentlig ekonomi | | --- | --- | --- | --- | --- | `; for (const sc of SCENARIOS_IN_DISPLAY_ORDER) { const old = OLD_SCENARIOS.find((s) => s.id === sc.id); if (!old) continue; const steps: [string, R][] = [ ["1. m3.2.1 (publicerat)", runOld(sc.id, old.params)], ["2. " + V_NEW + ", ändringarna avstängda", withSwitches(OFF, () => run(sc.id, sc.params))], ["3. + rättat produktionsunderlag (A)", withSwitches(SCOPE, () => run(sc.id, sc.params))], ["4. + omformulerat tillväxtscenario (B) = m3.3.1", withSwitches(ALL, () => run(sc.id, sc.params))], ["5. + rättat omställningsstöd (C) = " + V_NEW, withSwitches(CUR, () => run(sc.id, sc.params))], ]; if (sc.id === "growth") steps.splice(3, 0, ["3b. bara B, utan A (oberoende kontroll −18,99)", withSwitches(REL, () => run(sc.id, sc.params))]); for (const [l, r] of steps) out += `| ${sc.label} | ${l} | ${n(r.tax, 2)} | ${n(r.exp, 2)} | ${n(r.bal, 2)} |\n`; } out += ` Steg 1 → 2 är noll (kontroll att växlarna återger m3.2.1). Steg 2 → 3 är enbart den rättade avgränsningen. Steg 3 → 4 påverkar bara tillväxtscenariot. Steg 4 → 5 är enbart rättelsen av omställningsstödet (m3.4.0) och påverkar bara scenarier med förlorade jobb och stöd över noll. **Förklaring av förändringarna** - Produktivitet, omställning och "AI ersätter mycket arbete": lönesumman som jobbantagandena verkar på är nu marknadssektorernas andel (${n(calNew.privateWageShare * 100, 1)} % i stället för 72 %), och produktionsbidraget räknas på ${n(pvNew)} i stället för ${n(pvOld)} mdkr. Mindre lönebas ger något mindre löneeffekter; mindre produktionsunderlag ger mindre produktionsbidrag där det är större än noll. - Tillväxt: steg 3 ändrar tvåvägsmåttet via samma underlag. Steg 4 byter fråga: AI-vägens avvikelse i basårets ekonomi i stället för skillnaden mellan två framtidsekonomier. ## 3. Alla scenarier mot samma referens (${V_NEW}) Stresstest: utgångsläget ${YEAR}, med AI-avvikelse enligt scenariot. Inte en daterad prognos. Referens (verifierat utfall ${YEAR}): skatteintäkter ${n(ref.taxTotal)} mdkr, utgifter ${n(ref.expenditureTotal)} mdkr, saldo ${n(ref.balance)} mdkr. | Scenario | Skatteintäkter | % av referensens skatteintäkter ${YEAR} | Övriga inkomster | Utgifter | Offentlig ekonomi | Summakontroll | | --- | --- | --- | --- | --- | --- | --- | `; for (const sc of SCENARIOS_IN_DISPLAY_ORDER) { const r = run(sc.id, sc.params); const check = r.tax + r.other - r.exp - r.bal; out += `| ${sc.label} | ${n(r.tax, 2)} | ${n((r.tax / ref.taxTotal) * 100, 2)} % | ${n(r.other, 2)} | ${n(r.exp, 2)} | ${n(r.bal, 2)} | ${n(check, 9)} |\n`; } out += ` Summakontroll = skatteintäkter + övriga inkomster − utgifter − offentlig ekonomi (ska vara 0). ## 4. Tillväxtscenariot: omräkningen och avstämning av produktion och AI-kostnad `; const growth = SCENARIOS.find((s) => s.id === "growth")!.params; const rel = growthRelative(growth); const gEval = evaluateGrowth(calNew, growth, EMPTY_POLICY); const d = gEval.aiPath.detail; out += `| Kvot AI-väg / nyanställningsväg | Värde | | --- | --- | | Jobb | ${n(rel.employmentPct, 4)} % | | Lönesumma (uteblivna jobb) | ${n(rel.wageBillPct, 4)} % | | Produktionsbidrag före AI-inköp | ${n(rel.productionPct, 4)} % | | Ytterligare AI-inköp, basårets skala | ${n(rel.aiImportCost, 2)} mdkr | | Avstämning (${V_NEW}) | mdkr | | --- | --- | | Produktionsunderlag | ${n(d.productionBase)} | | Produktionsbidrag före AI-inköp | ${n(d.productionGain, 2)} | | − Förändrad arbetskraftskostnad | ${n(-d.dLabourCost, 2)} | | − Ytterligare AI-inköp (enda avdraget) | ${n(-d.aiImportCost, 2)} | | = Förändrat överskott | ${n(d.netSaving, 2)} | | Kontroll: bidrag − kostnad − AI − överskott | ${n(d.productionGain - d.dLabourCost - d.aiImportCost - d.netSaving, 9)} | | varav svensk beskattningsbar vinst / lägre priser | ${n(d.toProfits, 2)} / ${n(d.toPrices, 2)} | | Omställningsstöd (uteblivna jobb, inga uppsägningar) | ${n(d.support, 2)} | ## 5. Tvåvägsberäkningen jämfört med avvikelseberäkningen, egna inställningar Båda kolumnerna utan rättat produktionsunderlag, så att bara omformuleringen jämförs. "Skalad" = tvåvägsskillnaden dividerad med nyanställningsvägens produktionsindex, dvs. vad den skulle vara i basårets skala om sambanden vore linjära. Avvikelse = ny − skalad. | Fall | Överskott H / A (tvåväg) | Överskott, avvikelse | Tvåväg (m3.2.1) | Skalad | Avvikelse (${V_NEW}) | Skillnad | Förklaring | | --- | --- | --- | --- | --- | --- | --- | --- | `; type Case = [string, Partial, PolicyParams, string]; const cases: Case[] = [ ["Förval", {}, EMPTY_POLICY, "Bara skalning."], ["Lönegenomslag referens 50 %", { growthWagePassHiringPct: 50 }, EMPTY_POLICY, "Liten skillnad: lönekvoten läggs på basårets lönesumma, och skatte- och fördelningssambanden är inte helt proportionella mot skalan."], ["Lönegenomslag referens 150 %", { growthWagePassHiringPct: 150 }, EMPTY_POLICY, "Som ovan; skillnaden växer med skillnaden i lönegenomslag mellan vägarna."], ["AI-inköp i båda, 60 / 120", { growthAiImportCostHiring: 60 }, EMPTY_POLICY, "Bara skalning; skillnaden 60 mdkr räknas en gång."], ["AI-inköp större i referensen, 150 / 120", { growthAiImportCostHiring: 150 }, EMPTY_POLICY, "Negativ nettokostnad för AI-inköp i avvikelsen; linjärt."], ["AI-vägen med minskat överskott (AI 400)", { aiImportCost: 400 }, EMPTY_POLICY, "Överskottet ökar i båda framtidsvägarna men avvikelsen blir negativ. Ett minskat överskott bärs helt av vinsterna, medan en ökning delas med lägre priser. Tvåvägsmåttet delade båda ökningarna; avvikelsen låter hela minskningen slå mot vinsten."], ["Merkostnad för stöd 20", { extraSupportCost: 20 }, EMPTY_POLICY, "m3.2.1 lade stödet i båda vägarna, så det tog ut sig (fel). Nu räknas det en gång."], ["Omställningsstöd 50 %, referensen −10 % jobb", { transferSupportPct: 50, growthEmploymentHiringPct: -10 }, EMPTY_POLICY, "m3.2.1 tolkade den fallande lönesumman i nyanställningsvägen som uppsägningar och räknade stöd där. Uteblivna eller tillkommande jobb ger nu inget automatiskt stöd."], ["Offentlig effektivisering 2 %", { publicEfficiencyPct: 2 }, EMPTY_POLICY, "m3.2.1 lade effektiviseringen i båda vägarna, så den tog ut sig. Nu ingår den i AI-avvikelsen."], ["Egen åtgärd: bolagsskatt +10 %", {}, { tax: { corporate: 10 }, spending: {} }, "Åtgärden verkar på basårets underlag i stället för på framtidsekonomins."], ]; for (const [label, over, pol, why] of cases) { const p = { ...growth, ...over } as ScenarioParams; const oldP = { ...OLD_SCENARIOS.find((s) => s.id === "growth")!.params, ...over } as Old.ScenarioParams; const oc = Old.calibrate(YEAR); const og = Old.evaluateGrowth(oc, oldP, pol); const two = og.taxDiffVsHiring; const sH = Old.simulate(oc, Old.growthPathParams(oldP, "hiring")).detail.netSaving; const sA = Old.simulate(oc, Old.growthPathParams(oldP, "ai")).detail.netSaving; const scale = growthRelative(p).scale; const ev = withSwitches(REL, () => evaluateGrowth(calibrate(YEAR), p, pol)); const nw = ev.taxChange; out += `| ${label} | ${n(sH, 0)} / ${n(sA, 0)} | ${n(ev.aiPath.detail.netSaving, 0)} | ${n(two, 2)} | ${n(two / scale, 2)} | ${n(nw, 2)} | ${n(nw - two / scale, 2)} | ${why} |\n`; } out += ` Slutsats: likheten gäller för förvalen och för fall där AI-inköpen ändras. Mindre skillnader uppstår vid olika lönegenomslag och vid egna skatteändringar. Större skillnader uppstår när avvikelsens överskott blir negativt, när stöd, offentlig effektivisering eller merkostnader för stöd finns, och när en framtidsväg har fallande lönesumma. I övriga fall ger avvikelseberäkningen ett annat svar, eftersom den besvarar en annan fråga och eftersom två fel i m3.2.1 (stöd och effektivisering som tog ut sig) inte längre finns. ## 5b. Tillväxtscenariots varianter (${V_NEW}, redaktionella stresstester) Varianten "Företagen växer utan fler jobb" ändrar bara AI-alternativets sysselsättning och lönegenomslag. Båda varianterna räknas som AI-avvikelse i basårets ekonomi, mot samma utgångsläge som övriga scenarier. Ingen separat femårsprognos ingår. Inget målvärde har använts. Varianten "Företagen växer med få nya jobb" är fortsatt valbar. `; for (const yr of [YEAR, 2020]) { const c = calibrate(yr); const cols = GROWTH_VARIANTS.map((v) => { const p = growthVariantParams(growth, v.id); const r = growthRelative(p); const g = evaluateGrowth(c, p, EMPTY_POLICY); return { v, p, r, g, d: g.aiPath.detail }; }); const row = (l: string, f: (x: (typeof cols)[number]) => string) => `| ${l} | ${cols.map(f).join(" | ")} |\n`; out += `### Basår ${yr}\n\n| Storhet | ${cols.map((x) => x.v.label).join(" | ")} |\n| --- | ${cols.map(() => "---").join(" | ")} |\n`; out += row("Indata: jobb, jämförelsealternativet %", (x) => n(x.p.growthEmploymentHiringPct)); out += row("Indata: jobb, AI-alternativet %", (x) => n(x.p.growthEmploymentAiPct)); out += row("Indata: arbetstid per jobb H / A %", (x) => `${n(x.p.growthHoursHiringPct)} / ${n(x.p.growthHoursAiPct)}`); out += row("Indata: produktion per timme H / A %", (x) => `${n(x.p.growthProductivityHiringPct)} / ${n(x.p.growthProductivityAiPct)}`); out += row("Indata: lönegenomslag H / A %", (x) => `${n(x.p.growthWagePassHiringPct, 0)} / ${n(x.p.growthWagePassAiPct, 0)}`); out += row("Indata: AI-inköp H / A mdkr", (x) => `${n(x.p.growthAiImportCostHiring, 0)} / ${n(x.p.aiImportCost, 0)}`); out += row("Indata: merkostnad stöd mdkr", (x) => n(x.p.extraSupportCost, 0)); out += row("Härlett: jobb mot jämförelsealt. %", (x) => n(x.r.employmentPct, 4)); out += row("Härlett: lönesumma %", (x) => n(x.r.wageBillPct, 4)); out += row("Härlett: produktionsbidrag före AI-inköp %", (x) => n(x.r.productionPct, 4)); out += row("Härlett: AI-inköp, basårets skala mdkr", (x) => n(x.r.aiImportCost, 2)); out += row("Produktionsbidrag mdkr", (x) => n(x.d.productionGain, 2)); out += row("Förändrad arbetskraftskostnad mdkr", (x) => n(x.d.dLabourCost, 2)); out += row("Förändrat överskott mdkr", (x) => n(x.d.netSaving, 2)); out += row("Kontroll bidrag − kostnad − AI − överskott", (x) => n(x.d.productionGain - x.d.dLabourCost - x.d.aiImportCost - x.d.netSaving, 9)); out += row("Svensk beskattningsbar vinst / lägre priser mdkr", (x) => `${n(x.d.toProfits, 2)} / ${n(x.d.toPrices, 2)}`); out += row("Skatteintäkter mdkr", (x) => n(x.g.taxChange, 2)); out += row("Skatteintäkter % av referensen", (x) => n((x.g.taxChange / x.g.baseline.taxTotal) * 100, 3)); out += row("varav skatt på arbete / övrigt mdkr", (x) => `${n(x.g.final.taxByOrigin.labour - x.g.baseline.taxByOrigin.labour, 2)} / ${n(x.g.final.taxByOrigin.other - x.g.baseline.taxByOrigin.other, 2)}`); out += row("Utgifter mdkr", (x) => n(x.g.final.expenditureTotal - x.g.baseline.expenditureTotal, 2)); out += row("Offentlig ekonomi mdkr", (x) => n(x.g.final.balance - x.g.baseline.balance, 2)); out += row("Summakontroll (skatt + övr. inkomst − utgift − saldo)", (x) => n((x.g.final.taxTotal - x.g.baseline.taxTotal) + (x.g.final.otherRevenue - x.g.baseline.otherRevenue) - (x.g.final.expenditureTotal - x.g.baseline.expenditureTotal) - (x.g.final.balance - x.g.baseline.balance), 9)); out += "\n"; if (yr === YEAR) for (const x of cols) out += `- ${x.v.label}: ${explainGrowthJobs(x.p)}\n`; out += "\n"; } out += `Resultatet −57 mdkr i tidigare diskussion avsåg en äldre modell och jämförelsepunkt och används inte som kontrollvärde. ## 6. Äldre delningslänkar - Tillväxtlänkar från före m3.3.0 visar inget resultat direkt. En banderoll förklarar att scenariot nu mäter en annan sak. Alla parametrar och länkens modellversion bevaras i adressen tills användaren väljer "Visa med aktuell modell". - m3.1-länkar med gwh, gwa, gph eller gpa: befintlig spärr behålls. - Länkar från m3.3.0 och m3.3.1 räknas om med ${V_NEW} och visas med omräkningsnotis (rättat omställningsstöd). - Varianten följer av \`gv\` och parametrarna gea/gsa i adressen; egna värden visas som "Egna antaganden". m3.3.1-länkar utan \`gv\` men utan egna variantparametrar återskapar den tidigare varianten för att inte tyst byta innebörd. - Övriga scenarier: visas med versionsnotis om att resultatet är omräknat (produktionsunderlaget). ## 7. Historiska totaler `; let maxDiff = 0; let maxSplit = 0; for (const y of YEARS) { const r = reference(calibrate(y)); maxDiff = Math.max(maxDiff, Math.abs(r.taxTotal - DATA[y]!.taxTotal), Math.abs(r.balance - DATA[y]!.balance)); maxSplit = Math.max(maxSplit, Math.abs(r.taxByOrigin.labour + r.taxByOrigin.other - r.taxTotal)); } out += ` Största avvikelse mellan referens och officiella totaler, alla år ${YEARS[0]}–${YEARS[YEARS.length - 1]}: ${n(maxDiff, 9)} mdkr. Största avvikelse i uppdelningen arbete + övrigt mot totala skatter: ${n(maxSplit, 9)} mdkr. Neutralt scenario (inga AI-antaganden) ger ${n(simulate(calNew, { ...growth, inputMode: "direct", wageChangePct: 0, aiImportCost: 0, productionGainPct: 0, publicEfficiencyPct: 0 }).taxTotal - ref.taxTotal, 9)} mdkr. `; // ---- 8. m3.4.0 out += ` ## 8. ${V_NEW}: rättat omställningsstöd skilt från nya scenarioantaganden ### 8a. Rättelse (C): stödet räknas på de förlorade jobbens lön, inte netto efter nya jobb Samma förval som i m3.3.1. Inga antaganden har justerats för att bevara gamla resultat. | Scenario | Stöd m3.3.1 | Stöd ${V_NEW} | Skatt m3.3.1 | Skatt ${V_NEW} | Offentlig ekonomi m3.3.1 | Offentlig ekonomi ${V_NEW} | | --- | --- | --- | --- | --- | --- | --- | `; const stodCal = calibrate(YEAR); const detailOf = (id: string, p: ScenarioParams) => id === "growth" ? evaluateGrowth(stodCal, p, EMPTY_POLICY).final.detail : evaluate(stodCal, p, EMPTY_POLICY).final.detail; for (const sc of SCENARIOS_IN_DISPLAY_ORDER) { if (!OLD_SCENARIOS.find((s) => s.id === sc.id)) continue; const a = withSwitches(ALL, () => ({ r: run(sc.id, sc.params), d: detailOf(sc.id, sc.params) })); const b = withSwitches(CUR, () => ({ r: run(sc.id, sc.params), d: detailOf(sc.id, sc.params) })); out += `| ${sc.label} | ${n(a.d.support, 2)} | ${n(b.d.support, 2)} | ${n(a.r.tax, 2)} | ${n(b.r.tax, 2)} | ${n(a.r.bal, 2)} | ${n(b.r.bal, 2)} |\n`; } out += ` Skatteintäkterna blir mindre negativa när stödet ökar, eftersom stödet beskattas som transferering och delvis konsumeras. Den offentliga ekonomin försämras, eftersom stödet är en utgift. ### 8b. Nya scenarioantaganden (redaktionella exempel, inte prognoser) | Scenario / variant | Skatteintäkter | Utgifter | Offentlig ekonomi | Stöd | Produktion från nya jobb | Produktion från antagande | AI-inköp | Förändrat överskott | Summakontroll | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | `; const newCases: [string, string, ScenarioParams][] = [ ["morejobs", "AI skapar fler jobb än den tar", SCENARIOS.find((s) => s.id === "morejobs")!.params], ["fourday", "AI ger oss en fyradagarsvecka", SCENARIOS.find((s) => s.id === "fourday")!.params], ["transition", "Jobb försvinner – Lika många jobb – lägre löner", { ...SCENARIOS.find((s) => s.id === "transition")!.params, jobsReplacedPct: 100 }], ]; for (const [id, label, p] of newCases) { const r = run(id, p); const dd = detailOf(id, p); out += `| ${label} | ${n(r.tax, 2)} | ${n(r.exp, 2)} | ${n(r.bal, 2)} | ${n(dd.support, 2)} | ${n(dd.productionFromNewJobs, 2)} | ${n(dd.productionFromAssumption, 2)} | ${n(dd.aiImportCost, 2)} | ${n(dd.netSaving, 2)} | ${n(dd.productionGain - dd.dLabourCost - dd.aiImportCost - dd.netSaving, 9)} |\n`; } out += ` Summakontroll = produktionsbidrag − Δarbetskraftskostnad − AI-inköp − förändrat överskott (ska vara 0): AI-inköpen dras exakt en gång, och de nya jobbens produktion ingår en gång i produktionsbidraget. ### 8c. Känslighet | Fyradagarsvecka: produktion per timme | Skatteintäkter | Offentlig ekonomi | | --- | --- | --- | `; const fd = SCENARIOS.find((s) => s.id === "fourday")!.params; for (const q of [15, 20, 25, 30, 35]) { const r = run("fourday", { ...fd, hoursProductivityPct: q }); out += `| +${q} % | ${n(r.tax, 2)} | ${n(r.bal, 2)} |\n`; } out += ` | Fler jobb: produktion per nytt jobb | Skatteintäkter | Offentlig ekonomi | | --- | --- | --- | `; const mj = SCENARIOS.find((s) => s.id === "morejobs")!.params; for (const q of [0, 50, 75, 100, 125]) { const r = run("morejobs", { ...mj, newJobOutputPct: q }); out += `| ${q} % | ${n(r.tax, 2)} | ${n(r.bal, 2)} |\n`; } out += ` Begränsningar: modellen har inget arbetskraftstak (nettoökningen av jobb förutsätter att fler kan och vill arbeta); nya jobb ger egen produktion bara där reglaget är över noll; offentlig sektor ingår inte i arbetstidsförändringen; stödantagandet är ett sammansatt årsbelopp. `; // ---- 9. Avgränsad kontroll före publicering { const cal = calibrate(YEAR); const mjE = evaluate(cal, mj, EMPTY_POLICY); const d = mjE.final.detail; const va = d.productionBase; const per = va / 100; // produktion per ursprungligt jobb (genomsnitt), mdkr const lost = mj.jobsLostPct; const newJobs = (lost * mj.jobsReplacedPct) / 100; const kept = 100 - lost; const out9 = (s: string) => (out += s); out9(` ## 9. Avgränsad kontroll före publicering (${V_NEW}) Inga formler, förval eller resultat har ändrats i denna kontroll. Inget beräkningsfel har hittats; osäkra antaganden märks nedan. ### 9a. Produktionen i "AI skapar fler jobb än den tar", i index (ursprunglig privat sysselsättning = 100) Beräkningen använder hela den omfattade privata sysselsättningen i marknadssektorerna, normaliserad till index 100. En indexenhet motsvarar en procent av den sysselsättningen, inte ett faktiskt jobb eller en person. "6 jobb per 100" betyder alltså att 6 procent av den privata sysselsättningen försvinner. En indexenhet svarar mot ${n(per, 2)} mdkr i förädlingsvärde (marknadssektorernas arbetskraftskostnad + överskott, ${n(va, 1)} mdkr, före AI-inköp, delat med 100). | Led | Index (sysselsättning) | Produktion, mdkr | | --- | --- | --- | | Ursprunglig produktion | 100 | ${n(va, 1)} | | Produktion som hörde till sysselsättningen som försvinner | ${n(lost, 1)} | ${n(lost * per, 1)} | | Därav kvar genom AI (Scenarioantagande: 100 %) | – | ${n(lost * per, 1)} | | Produktion från kvarvarande sysselsättning | ${n(kept, 1)} | ${n(kept * per, 1)} | | Produktion från ny sysselsättning (${n(mj.newJobOutputPct ?? 0, 0)} % av genomsnittet) | ${n(newJobs, 1)} | ${n(d.productionFromNewJobs, 1)} | | Uttryckligt produktionsantagande | – | ${n(d.productionFromAssumption, 1)} | | **Total produktion före AI-inköp** | ${n(kept + newJobs, 1)} | ${n(va + d.productionGain, 1)} | | Kostnader och överskott | mdkr | | --- | --- | | Förändrad arbetskraftskostnad (D1 + löneberoende del av D29) | ${n(d.dLabourCost, 1)} | | AI-inköp (dras en gång) | ${n(d.aiImportCost, 1)} | | Förändrat överskott = ${n(d.productionGain, 1)} − ${n(d.dLabourCost, 1)} − ${n(d.aiImportCost, 1)} | ${n(d.netSaving, 1)} | Formler: nya jobb = ${lost} × ${mj.jobsReplacedPct} % = ${n(newJobs, 1)}; produktion från nya jobb = förädlingsvärde × ${n(newJobs / 100, 3)} × ${mj.newJobOutputPct} %; lönesumman ändras med −${lost} % + ${n(newJobs, 1)} % = ${n(newJobs - lost, 1)} % (samma lön i nya och försvunna jobb). **Produktionen från försvunna jobb antas finnas kvar genom AI.** Det gäller i hela jobbläget, inte bara här: modellen minskar arbetskraftskostnaden när jobb försvinner men lämnar produktionen oförändrad. AI-inköpen är kostnaden för detta. Det är ett scenarioantagande och står nu i scenariobeskrivningen och metoden. Ingen dubbelräkning: den ersatta produktionen ingår inte i produktionsbidraget (den finns redan i utgångsläget), nya jobbs produktion ingår en gång (productionFromNewJobs), och det uttryckliga produktionsantagandet är 0 i detta scenario. Känslighetens ändpunkter: **0 %** betyder att de nya jobben kostar lön men inte producerar något (produktionen blir ${n(va, 1)} mdkr, som före AI). **100 %** betyder att varje nytt jobb producerar lika mycket som ett genomsnittligt ursprungligt jobb, inklusive dess andel av överskottet. Resultat: skatteintäkter ${n(mjE.final.taxTotal - mjE.ref.taxTotal, 1)} mdkr/år. Ungefär ${n(run("morejobs", mj).tax - run("morejobs", { ...mj, newJobOutputPct: 0 }).tax, 1)} mdkr av dessa kommer från de nya jobbens produktion (skillnaden mellan 100 % och 0 %), som främst beskattas som vinst, kapitalinkomst och konsumtion. Det antagandet behöver extern bedömning. ### 9b. Produktionslogiken i alla scenarier (förval ${YEAR}) | Scenario | Försvunna jobbs produktion | Nya jobbs produktion | Produktivitet | Uttryckligt produktionsantagande | AI-inköp | | --- | --- | --- | --- | --- | --- | `); for (const sc of SCENARIOS_IN_DISPLAY_ORDER) { const p = sc.params; if (sc.id === "growth") { out9(`| ${sc.label} | – (inga uppsägningar) | ingår i produktion per timme × sysselsättning i vardera vägen | ${n(p.growthProductivityAiPct, 1)} % / ${n(p.growthProductivityHiringPct, 1)} % per timme (AI / jämförelse) | ingår inte separat | ${p.aiImportCost} mdkr (jämförelse ${p.growthAiImportCostHiring}) |\n`); continue; } if (p.inputMode === "hours") { out9(`| ${sc.label} | – (inga jobb försvinner) | – | +${p.hoursProductivityPct} % per timme, ${p.hoursPerPersonPct} % arbetstid | härleds: ${n(evaluate(cal, p).final.detail.productionFromAssumption, 1)} mdkr | ${p.aiImportCost} mdkr |\n`); continue; } const dd = evaluate(cal, p).final.detail; out9(`| ${sc.label} | kvar genom AI (${p.jobsLostPct} jobb) | ${p.newJobOutputPct ?? 0} % av genomsnitt (${n(dd.productionFromNewJobs, 1)} mdkr) | ingår i det uttryckliga antagandet | ${n(p.productionGainPct, 1)} % (${n(dd.productionFromAssumption, 1)} mdkr) | ${p.aiImportCost} mdkr |\n`); } out9(` Skillnaderna är avsiktliga: i de tre äldre jobbscenarierna ingår nya jobbs eventuella produktion i det samlade produktionsantagandet, som därför inte kompletteras automatiskt. I "AI skapar fler jobb än den tar" är produktionsantagandet 0 och nya jobbs produktion anges separat, så inget räknas två gånger. Olika beräkningsvägar med samma ekonomiska innebörd: arbetstidsläget räknar produktion som anställda × arbetstid × produktion per timme och har inga uppsägningar, så en nettoökning av sysselsättningen där ger bara nettots produktion. Jobbläget låter de försvunna jobbens produktion ligga kvar genom AI. Det är olika antaganden (ersättning med AI finns bara i jobbläget), inte samma antagande med olika resultat. Inget beräkningsfel har hittats; ingen rättelse föreslås. ### 9c. Omställningsstödet: ändrat samband Före ${V_NEW} (nettosamband): stödunderlag = max(0, försvunna jobbs lön − nya jobbs lön). Nya jobb kvittade bort stödbehovet, som om alla nya jobb gick till dem som sagts upp. Nu (bruttosamband): stödunderlag = försvunna jobbs lön. Stödfaktorn (reglaget) är sammansatt: ersättningsgrad × andel av de berörda som får stöd × andel av året med stöd. Täckning och varaktighet ska fånga att en del av de berörda får nytt arbete under året; modellen antar varken att alla nya jobb går till uppsagda eller att ingen uppsagd får ett nytt jobb. Uteblivna jobb och kortare arbetstid ger inget stöd. | Scenario | Berörd löneinkomst | Stödfaktor | Stödutgift | Återflöde via skatter | Nettoeffekt offentlig ekonomi | | --- | --- | --- | --- | --- | --- | `); for (const sc of SCENARIOS_IN_DISPLAY_ORDER) { const p = sc.params; const dd = sc.id === "growth" ? evaluateGrowth(cal, p, EMPTY_POLICY).final.detail : evaluate(cal, p).final.detail; const with_ = run(sc.id, p); const without = run(sc.id, { ...p, transferSupportPct: 0 }); out9(`| ${sc.label} | ${n(dd.lostWageIncome, 1)} | ${p.transferSupportPct} % | ${n(dd.support, 1)} | ${n(with_.tax - without.tax, 1)} | ${n(with_.bal - without.bal, 1)} |\n`); } out9(` Återflödet = skatteintäkter med stöd − skatteintäkter med stödfaktor 0 (skatt på transfereringar plus konsumtionsskatter när stödet används). Nettoeffekten = offentlig ekonomi med stöd − utan stöd. Förval som behöver ekonomisk bedömning (behålls oförändrade, ingen kalibrering mot äldre resultat): - Stödfaktorn i "AI hjälper oss att producera mer" är 0 % trots att 6 av 100 jobb försvinner, medan samma jobbförlust i "AI skapar fler jobb än den tar" har 35 %. Skillnaden är ett förvalsval, inte en beräkningsväg. - Stödfaktorerna 35 % och 45 % i övriga scenarier (sammansatt ersättning, täckning och varaktighet). - Antagandet att försvunna jobbs produktion finns kvar genom AI till AI-inköpens kostnad. - Nya jobbs produktion på 100 % av genomsnittet i "AI skapar fler jobb än den tar". - Att nettoökningen av jobb förutsätter att fler kan och vill arbeta; modellen har inget arbetskraftstak. `); } // --------------------------------------------------------------------------- // 10. Valda stresstest – större bortfall av jobb (granskningsunderlag, inga förval ändrade) { const cal = calibrate(YEAR); // Underlaget är versionsmärkt m3.4.0: A är förvalet i m3.4.0, C blev förval i m3.4.1. const base: ScenarioParams = { ...SCENARIOS.find((s) => s.id === "capital")!.params, jobsLostPct: 20, aiImportCost: 160 }; const cases10: [string, string, ScenarioParams][] = [ ["A", "Förval i m3.4.0", base], ["B", "Större jobbförlust", { ...base, jobsLostPct: 30 }], ["C", "Som B, AI-kostnad proportionellt uppskalad", { ...base, jobsLostPct: 30, aiImportCost: (base.aiImportCost * 30) / base.jobsLostPct }], ]; const s10 = (v: number) => (v > 0 ? "+" : v < 0 ? "−" : "±") + n(Math.abs(v), 1); const rows = cases10.map(([k, label, p]) => { const e = evaluate(cal, p); const e0 = evaluate(cal, { ...p, transferSupportPct: 0 }); const lost = p.jobsLostPct; const kept = 100 - lost; const neu = (lost * p.jobsReplacedPct) / 100; const total = kept + neu; const labour = e.final.taxByOrigin.labour - e.ref.taxByOrigin.labour; const otherAll = e.final.taxByOrigin.other - e.ref.taxByOrigin.other; const back = e.final.taxTotal - e0.final.taxTotal; const tax = e.final.taxTotal - e.ref.taxTotal; const exp = e.final.expenditureTotal - e.ref.expenditureTotal; const bal = e.final.balance - e.ref.balance; const bal0 = e0.final.balance - e0.ref.balance; const tax0 = e0.final.taxTotal - e0.ref.taxTotal; const d = e.final.detail; return { k, label, p, lost, kept, neu, total, labour, otherEx: otherAll - back, back, tax, exp, bal, bal0, tax0, d }; }); const t = (f: (r: (typeof rows)[number]) => string) => rows.map(f).join(" | "); out += ` ## 10. Valda stresstest – större bortfall av jobb (${V_NEW}, basår ${YEAR}) Versionsmärkt granskningsunderlag från m3.4.0. A var förvalet för "AI tar över en stor del av jobben" i m3.4.0. B och C är **valda stresstest**, inte prognoser eller forskningsbelagda sannolikheter. Från m3.4.1 är fall C förval i scenariot (ett kraftigt redaktionellt stresstest, inte ett bedömt mest sannolikt utfall); beräkningen är oförändrad och C ska bedömas utifrån sina antaganden, inte utifrån sitt skatteutfall. Inga formler har ändrats; värdena räknas med samma motor som simulatorn. ### 10a. Jobb per 100 ursprungliga privata jobb (sysselsättningsindex) | Led | ${t((r) => r.k)} | | --- | --- | --- | --- | | Försvunna ursprungliga jobb | ${t((r) => n(r.lost, 1))} | | Kvarvarande ursprungliga jobb | ${t((r) => n(r.kept, 1))} | | Nya jobb (${n(base.jobsReplacedPct, 0)} % av de försvunna) | ${t((r) => n(r.neu, 1))} | | Totalt antal jobb efter förändringen | ${t((r) => n(r.total, 1))} | | Nettoförändring | ${t((r) => s10(r.total - 100))} | | Samlade löneinkomster, förändring | ${t((r) => s10(r.d.wageChangePct) + " %")} | En indexenhet är en procent av den omfattade privata sysselsättningen, inte en person. ### 10b. Produktion och AI-kostnad | Led | ${t((r) => r.k)} | | --- | --- | --- | --- | | Produktionsantagande (total privat produktion, Scenarioantagande) | ${t((r) => "+" + n(r.p.productionGainPct, 1) + " %")} | | Produktionsbidrag, mdkr | ${t((r) => s10(r.d.productionFromAssumption))} | | Separat produktionstillägg från nya jobb | ${t((r) => n(r.d.productionFromNewJobs, 1))} | | AI-kostnad, mdkr (C: redaktionellt uppskalad) | ${t((r) => n(r.p.aiImportCost, 0))} | | Förändrad arbetskraftskostnad, mdkr | ${t((r) => s10(r.d.dLabourCost))} | | Förändrat överskott i företagen, mdkr | ${t((r) => s10(r.d.netSaving))} | | Implicit produktion per sysselsättningsindex (utgångsläge = 1,00) | ${t((r) => n((100 + r.p.productionGainPct) / r.total, 3))} | **Vad modellen antar.** Den privata produktionen i de berörda verksamheterna antas bli ${n(base.productionGainPct, 1)} % högre än i utgångsläget, före AI-inköp, oavsett hur många jobb som försvinner eller tillkommer. Det samlade antagandet avser hela produktionen: den som kvarvarande och nya anställda utför och den som AI tar över. Nya jobb har därför **inget separat produktionstillägg** (newJobOutputPct = 0), men det betyder **inte att de saknar produktion** – deras produktion ingår i det samlade antagandet. Deras löner räknas som arbetskraftskostnad. Tidigare formulering om att nya jobb "ger lönekostnad men ingen produktion" var oprecis och ersätts av denna. Produktionen räknas en gång; inget bidrag läggs till. **Definitionsfråga för ekonomisk bedömning.** Att procentsatsen är oförändrad (+${n(base.productionGainPct, 1)} %) bevisar inte att innebörden är oförändrad. Med fler försvunna jobb måste AI stå för en större del av produktionen, och den implicita produktionen per sysselsättningsindex efter förändringen stiger från ${n((100 + base.productionGainPct) / rows[0]!.total, 3)} (A) till ${n((100 + base.productionGainPct) / rows[1]!.total, 3)} (B/C). I B bärs den större AI-insatsen utan högre AI-kostnad; C prövar en proportionell kostnadsökning. Om produktionen i försvunna jobb inte helt bevaras genom AI, eller om nya jobb producerar mer eller mindre än genomsnittet, ändras både överskott och vinstskatt. Det är öppet. ### 10c. Skatter, utgifter och offentlig ekonomi, mdkr per år mot utgångsläget | Led | ${t((r) => r.k)} | | --- | --- | --- | --- | | Förändrad skatt på arbete | ${t((r) => s10(r.labour))} | | Övriga skatteeffekter exklusive stödets återflöde | ${t((r) => s10(r.otherEx))} | | Skatteåterflöde från omställningsstöd | ${t((r) => s10(r.back))} | | **Förändrade skatteintäkter totalt** | ${t((r) => s10(r.tax))} | | Förändrade offentliga utgifter | ${t((r) => s10(r.exp))} | | **Förändring i hela den offentliga ekonomin** | ${t((r) => s10(r.bal))} | | Varav stödutgift | ${t((r) => n(r.d.support, 1))} | Summeringarna görs med oavrundade värden; avrundade rader kan skilja 0,1 från totalen. Återflödet är skillnaden mot samma fall med stödfaktor 0 och ingår i totalen en gång (det är utbrutet ur övriga skatteeffekter, inte lagt ovanpå dem). **Isolering av stödets budgeteffekt** (samma fall med stödfaktor 0, A | B | C): skatteintäkter ${t((r) => s10(r.tax0))}; offentlig ekonomi ${t((r) => s10(r.bal0))}. Jämförelsen visar bara stödets effekt på den offentliga budgeten. Den är inte ett förslag om bättre politik: modellen värderar inte hushållens trygghet, omställning eller andra följdeffekter av uteblivet stöd. **Stödet.** Stödfaktorn ${n(base.transferSupportPct, 0)} % är sammansatt: ersättningsgrad × täckningsgrad × andel av året med stöd, tillämpad på de berördas bortfallna löneinkomst. Den innebär inte att alla berörda får 45 procents ersättning under ett helt år. **Vad som dämpar skattebortfallet.** (1) Produktionen i försvunna jobb antas bevaras genom AI, så lägre personalkostnad blir högre överskott; (2) en del av överskottet (${n(base.savingToProfitsPct, 0)} %) blir svensk beskattningsbar vinst; (3) omställningsstödet beskattas och konsumeras, men är samtidigt en offentlig utgift. ### 10d. Sammanfattning av fall C för extern bedömning - 30 procent av de privata jobben försvinner; 35 procent av dem ersätts av nya (10,5 per 100). - ${n(100 - rows[2]!.total, 1)} procent färre privata jobb netto (80,5 per 100 efter förändringen). - AI-kostnad ${n(rows[2]!.p.aiImportCost, 0)} mdkr, proportionellt uppskalad från ${n(base.aiImportCost, 0)} mdkr vid 20 procent – ett redaktionellt antagande för känslighetsanalys, inte ett påstående om verklig kostnadsutveckling. - Övriga antaganden oförändrade från förvalet. - Resultat: skatteintäkter ${s10(rows[2]!.tax)}, offentliga utgifter ${s10(rows[2]!.exp)}, offentlig ekonomi ${s10(rows[2]!.bal)} mdkr/år. Öppna frågor: - **Produktion:** Är det rimligt att total produktion är +${n(base.productionGainPct, 1)} % även när 30 procent av jobben försvinner, dvs. att AI fullt ut ersätter försvunnen produktion? Hur ska nya jobbs produktion värderas? - **Svensk vinstandel:** Hur stor del av det ökade överskottet blir beskattningsbar vinst i Sverige (nu ${n(base.savingToProfitsPct, 0)} %)? - **Stödets omfattning:** Är den sammansatta stödfaktorn ${n(base.transferSupportPct, 0)} % rimlig vid en större jobbförlust, med avseende på täckning och varaktighet? `; } // ---- 11. m3.4.1: nytt förval för "AI tar över en stor del av jobben" { const cal = calibrate(YEAR); const res = (p: ScenarioParams, id: string) => { if (id === "growth") { const g = evaluateGrowth(cal, p, EMPTY_POLICY); return [g.final.taxTotal - g.baseline.taxTotal, g.final.expenditureTotal - g.baseline.expenditureTotal, g.final.balance - g.baseline.balance]; } const e = evaluate(cal, p); return [e.final.taxTotal - e.ref.taxTotal, e.final.expenditureTotal - e.ref.expenditureTotal, e.final.balance - e.ref.balance]; }; const before = SCENARIOS_IN_DISPLAY_ORDER.map((sc) => res(sc.params, sc.id)); Object.assign(CAPITAL.params, CAPITAL_C); out += ` ## 11. ${V_CUR}: nytt förval för "AI tar över en stor del av jobben" (basår ${YEAR}) Endast två förval ändras: andelen privata jobb som försvinner 20 → ${CAPITAL.params.jobsLostPct} procent och AI-inköp 160 → ${CAPITAL.params.aiImportCost} mdkr per år (fall C i avsnitt 10). Ersättningsandelen ${CAPITAL.params.jobsReplacedPct} procent och övriga antaganden är oförändrade. Inga beräkningsformler har ändrats; ${V_CUR} räknar identiskt med m3.4.0 för samma indata. Scenariot beskrivs som ett kraftigt redaktionellt stresstest, inte en prognos eller ett bedömt mest sannolikt utfall. Äldre delningslänkar (modellversion före ${V_CUR}) behåller förval A och visar en förklaring. | Scenario | Skatt m3.4.0-förval | Skatt ${V_CUR} | Utgifter m3.4.0-förval | Utgifter ${V_CUR} | Offentlig ekonomi m3.4.0-förval | Offentlig ekonomi ${V_CUR} | | --- | --- | --- | --- | --- | --- | --- | `; SCENARIOS_IN_DISPLAY_ORDER.forEach((sc, i) => { const a = before[i]!; const b = res(sc.params, sc.id); out += `| ${sc.label} | ${n(a[0]!, 2)} | ${n(b[0]!, 2)} | ${n(a[1]!, 2)} | ${n(b[1]!, 2)} | ${n(a[2]!, 2)} | ${n(b[2]!, 2)} |\n`; }); out += ` Övriga fem scenarier är oförändrade. Det nya förvalet ger samma värden som fall C i avsnitt 10 (jämförelsevärden, inte måltal). `; } console.log(out);