From 1bb40319d8fa985d21754784b769e00c3e9a2b9f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 4 Aug 2026 14:17:38 +0000 Subject: [PATCH] =?UTF-8?q?Metodikbiblioteket:=2016=20metodiker=20som=20t?= =?UTF-8?q?=C3=A4cker=20fordonets=20system?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tre metodiker räckte för att visa principen men inte för att arbeta. Biblioteket flyttas till en egen fil och växer till sexton: vibration, bromsar, styrning/fjädring, elsystem, start & laddning, motorgång, kylsystem, drivlina, avgas & emission, klimat, högvolt, felkoder & kommunikation, läckage, missljud, ADAS — plus generisk. Att "täcka allt" går inte att lova. Det som går är att täcka systemen systematiskt och låta generisk vara ett strukturellt komplett skyddsnät för det ingen förutsett. Tre regler gäller alla metodiker, och alla tre är låsta av test: 1. Varje kontroll har ett minimikrav — mätvärde, foto eller observation. En kryssruta är inte evidens. 2. Varje metodik börjar med att verifiera symptomet, aldrig med att åtgärda. Kundens ord blir ett symptom först när det reproducerats. 3. Där arbetet kan skada någon ligger säkerhetssteget först. Högvoltsmetodiken kan inte påbörjas utan dokumenterad spänningsfrihet, urtagen servicebrytare och skyddsutrustning — det arbetet kan döda, och en kryssruta duger inte. Motorn och innehållet skiljs åt: metodik.ts äger typer, val och härledningen av nästa steg, metodiker.ts äger metodikerna. Biblioteket kan växa utan att motorn ändras. Valet av metodik är inte längre en regexkedja utan poängsatt på nyckelord, där det längre — mer specifika — ordet väger tyngre: "traktionsbatteri" slår "batteri". Korta ord matchas som helt ord, längre som ordstam, annars hade "ac" träffat "acceleration" och en vibration hamnat i klimatanläggningen. Nyckelorden är stammar, inte färdigböjda ord: svensk böjning kapar ofta ett e (filter → filtret), så "partikelfilter" hade aldrig matchat texten teknikern faktiskt skriver. Valet är en frågeordning, inte en diagnos. Träffar inget blir det generisk — ett ärligt "vi vet inte var vi ska börja" i stället för en gissning — varefter orkesterns klassificerare får försöka. Orkesterns metodikkatalog byggs nu ur en lista i stället för att räknas upp i både schema och prompt, i båda kopiorna (ai-orkester och edge-funktionen). Ett test jämför den mot klientens: glider listorna isär returnerar klassificeraren ett id klienten inte känner igen, och valet faller tyst tillbaka på generisk. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt --- .../felsokning/__tests__/metodiker.test.ts | 152 +++ .../felsokning/__tests__/projektioner.test.ts | 4 +- felsokning/app/src/felsokning/metodik.ts | 288 ++---- felsokning/app/src/felsokning/metodiker.ts | 899 ++++++++++++++++++ felsokning/docs/DEMO.md | 2 +- felsokning/docs/MVP.md | 6 +- felsokning/services/ai-orkester/server.mjs | 33 +- .../supabase/functions/felsokning-ai/index.ts | 33 +- 8 files changed, 1210 insertions(+), 207 deletions(-) create mode 100644 felsokning/app/src/felsokning/__tests__/metodiker.test.ts create mode 100644 felsokning/app/src/felsokning/metodiker.ts diff --git a/felsokning/app/src/felsokning/__tests__/metodiker.test.ts b/felsokning/app/src/felsokning/__tests__/metodiker.test.ts new file mode 100644 index 0000000..b9baafa --- /dev/null +++ b/felsokning/app/src/felsokning/__tests__/metodiker.test.ts @@ -0,0 +1,152 @@ +// Metodikbiblioteket är produktens innehåll — går det sönder märks det +// inte som ett krasch, utan som att teknikern får sämre frågor. Därför +// låser testerna strukturen, inte bara att koden kör. +import { readFileSync } from "node:fs"; +import { describe, expect, it } from "vitest"; +import { ALLA_METODIKER, GENERISK, HOGVOLT, metodikForId, metodikPoang, valjMetodik } from "../metodik"; + +describe("metodikbiblioteket", () => { + it("har unika id:n och stabila namn", () => { + const id = ALLA_METODIKER.map((m) => m.id); + expect(new Set(id).size).toBe(id.length); + for (const m of ALLA_METODIKER) { + expect(m.namn.length, m.id).toBeGreaterThan(0); + expect(m.omrade.length, m.id).toBeGreaterThan(0); + } + }); + + it("varje kontroll kräver bevis — en kryssruta är inte evidens", () => { + for (const m of ALLA_METODIKER) { + for (const steg of m.steg) { + for (const kontroll of steg.kontroller ?? []) { + expect(kontroll.krav, `${m.id}/${steg.id}/${kontroll.id}`).toBeDefined(); + } + } + } + }); + + it("varje metodik börjar med att verifiera symptomet, inte med att åtgärda", () => { + for (const m of ALLA_METODIKER) { + const symptom = m.steg.find((s) => s.id === "symptom"); + expect(symptom, m.id).toBeDefined(); + expect(symptom!.fragor?.length, m.id).toBeGreaterThan(0); + + // Undantaget är det enda som får gå före: säkerheten. + const index = m.steg.indexOf(symptom!); + expect(m.steg.slice(0, index).map((s) => s.id), m.id).toEqual( + index === 0 ? [] : ["sakerhet"], + ); + } + }); + + it("id:n inom en metodik är unika — nastaSteg spårar dem som steg/id", () => { + for (const m of ALLA_METODIKER) { + const nycklar = m.steg.flatMap((s) => [ + ...(s.fragor ?? []).map((f) => `${s.id}/f/${f.id}`), + ...(s.kontroller ?? []).map((k) => `${s.id}/k/${k.id}`), + ]); + expect(new Set(nycklar).size, m.id).toBe(nycklar.length); + expect(new Set(m.steg.map((s) => s.id)).size, m.id).toBe(m.steg.length); + } + }); + + it("val-frågor har alternativ att välja mellan", () => { + for (const m of ALLA_METODIKER) { + for (const steg of m.steg) { + for (const f of steg.fragor ?? []) { + if (f.svarstyp === "val") { + expect(f.val?.length, `${m.id}/${steg.id}/${f.id}`).toBeGreaterThan(1); + } + } + } + } + }); + + it("högvolt kan inte påbörjas utan att säkerheten är dokumenterad", () => { + // Fel här kan döda någon. Steget ligger först och kräver mätvärde på + // spänningsfrihet — inte ett ja på en fråga. + expect(HOGVOLT.steg[0].id).toBe("sakerhet"); + const krav = HOGVOLT.steg[0].kontroller ?? []; + expect(krav.some((k) => k.id === "spanningsfrihet" && k.krav === "matvarde")).toBe(true); + expect(krav.some((k) => k.id === "service_disconnect")).toBe(true); + expect(HOGVOLT.steg[0].beskrivning).toMatch(/livsfarlig/i); + }); +}); + +describe("val av metodik", () => { + it("väljer på symptomets ord, inte på ordningen i biblioteket", () => { + const fall: [string, string][] = [ + ["Bilen vibrerar runt 88 km/h", "vibration"], + ["Reläet klickar inte", "elsystem"], + ["Ingen spänning till bränslepumpen", "elsystem"], + ["Belysningen fungerar inte", "elsystem"], + ["Bilen startar inte, det klickar bara", "start_laddning"], + ["Motorn rycker vid acceleration och tappar kraft", "motor_drift"], + ["Det gnisslar vid inbromsning och bromspedalen pulserar", "bromsar"], + ["Bilen överhettar i kö, kylvätskan försvinner", "kylsystem"], + ["Automatlådan rycker vid växling", "drivlina"], + ["Partikelfiltret regenererar hela tiden", "avgas_emission"], + ["AC:n kyler inte längre", "klimat"], + ["Elbilen laddar inte på DC och räckvidden har minskat", "hogvolt"], + ["Ingen kontakt med styrenheten, flera lampor lyser", "diagnos_natverk"], + ["Det droppar olja på garagegolvet", "lackage"], + ["Ett knackande missljud från fram vänster", "missljud"], + ["Filhållningsassistansen måste kalibreras efter byte av vindruta", "adas"], + ["Stötdämparen läcker och bilen gungar", "styrning_fjadring"], + ]; + for (const [text, forvantat] of fall) { + expect(valjMetodik(text).id, text).toBe(forvantat); + } + }); + + it("faller tillbaka på generisk i stället för att gissa", () => { + for (const text of ["", "Kunden är missnöjd", "Se bifogad arbetsorder", "Konstigt beteende ibland"]) { + expect(valjMetodik(text).id, text).toBe("generisk"); + } + }); + + it("korta nyckelord matchas som helt ord, långa som ordstam", () => { + // "ac" får inte träffa "acceleration" — annars hamnar en vibration i + // klimatanläggningen. + expect(metodikPoang(ALLA_METODIKER.find((m) => m.id === "klimat")!, "vibration vid acceleration")).toBe(0); + // Men stammen "vibration" ska träffa böjda former. + const vibration = ALLA_METODIKER.find((m) => m.id === "vibration")!; + expect(metodikPoang(vibration, "kraftiga vibrationer")).toBeGreaterThan(0); + expect(metodikPoang(vibration, "skakningar i ratten")).toBeGreaterThan(0); + }); + + it("mer specifikt nyckelord vinner över mindre specifikt", () => { + // Både elsystem ("batteri" via ström/spänning) och högvolt kan kännas + // relevanta — "traktionsbatteri" avgör. + expect(valjMetodik("Traktionsbatteriet ger felmeddelande").id).toBe("hogvolt"); + }); + + it("är stabil: samma text ger samma metodik", () => { + const text = "Bilen drar åt höger och det gnisslar"; + const forsta = valjMetodik(text).id; + for (let i = 0; i < 5; i += 1) expect(valjMetodik(text).id).toBe(forsta); + }); + + it("metodikForId faller tillbaka på generisk vid okänt id", () => { + expect(metodikForId("hogvolt").id).toBe("hogvolt"); + expect(metodikForId("finns_inte")).toBe(GENERISK); + }); +}); + +describe("orkestern och klienten känner till samma metodiker", () => { + // Klassificeraren i orkestern kan bara returnera id:n som finns i + // schemat. Glider listorna isär returnerar den ett id klienten inte + // känner igen, och valet faller tyst tillbaka på generisk. + const idn = ALLA_METODIKER.map((m) => m.id).sort(); + + for (const fil of ["../services/ai-orkester/server.mjs", "../supabase/functions/felsokning-ai/index.ts"]) { + it(fil, () => { + const kalla = readFileSync(fil, "utf8"); + const katalog = kalla.match(/const METODIK_KATALOG = \[([\s\S]*?)\n\];/); + expect(katalog, "METODIK_KATALOG saknas").not.toBeNull(); + + const iOrkestern = [...katalog![1].matchAll(/\["([a-z_]+)",/g)].map((m) => m[1]).sort(); + expect(iOrkestern).toEqual(idn); + }); + } +}); diff --git a/felsokning/app/src/felsokning/__tests__/projektioner.test.ts b/felsokning/app/src/felsokning/__tests__/projektioner.test.ts index 3a0e34c..7baf8f0 100644 --- a/felsokning/app/src/felsokning/__tests__/projektioner.test.ts +++ b/felsokning/app/src/felsokning/__tests__/projektioner.test.ts @@ -42,7 +42,9 @@ describe("verifierade checklistor", () => { describe("metodikval", () => { it("väljer vibrationsmetodiken när felbeskrivningen nämner vibration", () => { expect(valjMetodik("Bilen vibrerar runt 88 km/h").id).toBe("vibration"); - expect(valjMetodik("Motorn startar inte").id).toBe("generisk"); + // Utan igenkännbart symptom väljs ingen ingång — generisk är svaret, + // inte en gissning. (Se metodiker.test.ts för hela urvalet.) + expect(valjMetodik("Kunden vill ha en genomgång").id).toBe("generisk"); }); it("väljer elsystemmetodiken vid elrelaterade symptom", () => { diff --git a/felsokning/app/src/felsokning/metodik.ts b/felsokning/app/src/felsokning/metodik.ts index bbf2695..9402d7a 100644 --- a/felsokning/app/src/felsokning/metodik.ts +++ b/felsokning/app/src/felsokning/metodik.ts @@ -2,11 +2,12 @@ // Systemet presenterar aldrig en hypotes som ett konstaterat fel — // motorn föreslår nästa verifierbara steg utifrån vad som redan är dokumenterat. // -// I MVP:t är metodikerna fördefinierade flöden. Den framtida AI-integrationen -// ansluter här: den väljer/genererar steg, men händelseloggen och -// projektionerna är oförändrade. +// Här bor motorn: typerna, valet av metodik och härledningen av nästa +// steg. Själva metodikerna ligger i ./metodiker — de växer i antal, och +// motorn ska inte behöva ändras när de gör det. import type { Arende } from "./domain"; +import { ALLA_METODIKER, ELSYSTEM, GENERISK, VIBRATION } from "./metodiker"; export interface Fraga { id: string; @@ -36,205 +37,108 @@ export interface MetodikSteg { export interface Metodik { id: string; namn: string; + /** Fordonets system, för gruppering i listor. */ + omrade: string; + /** + * Ord ur kundens eller teknikerns språk, inte ur konstruktörens. + * Används enbart för att välja ingång — aldrig för att dra en slutsats + * om vad felet är. + */ + nyckelord: string[]; steg: MetodikSteg[]; } -export const VIBRATION_METODIK: Metodik = { - id: "vibration", - namn: "Vibration under körning", - steg: [ - { - id: "symptom", - rubrik: "Verifiera symptom", - fragor: [ - { id: "hastighetsberoende", text: "Är vibrationen hastighetsberoende?", svarstyp: "janej" }, - { - id: "var", - text: "Var känns vibrationen?", - svarstyp: "val", - val: ["I ratten", "I stolen", "I hela bilen"], - }, - { - id: "nar", - text: "När uppstår vibrationen?", - svarstyp: "val", - val: ["Vid acceleration", "Vid jämn fart", "Vid inbromsning", "Alltid under körning"], - }, - { - id: "intervall", - text: "Försvinner den över eller under ett visst hastighetsintervall?", - svarstyp: "text", - }, - ], - }, - { - id: "visuell", - rubrik: "Visuell kontroll", - beskrivning: "Fotografera samtliga hjul. Skilj på observation och slutsats.", - kontroller: [ - { id: "foto_vf", text: "Fotografera vänster framhjul", krav: "foto" }, - { id: "foto_hf", text: "Fotografera höger framhjul", krav: "foto" }, - { id: "foto_vb", text: "Fotografera vänster bakhjul", krav: "foto" }, - { id: "foto_hb", text: "Fotografera höger bakhjul", krav: "foto" }, - { id: "dot", text: "Dokumentera DOT-/tillverkningsdatum", krav: "kommentar" }, - { id: "slitage", text: "Kontrollera däckslitage", krav: "kommentar" }, - ], - }, - { - id: "kontroller", - rubrik: "Rekommenderade kontroller", - kontroller: [ - { id: "lufttryck", text: "Kontrollera lufttryck", krav: "matvarde" }, - { id: "hjulmoment", text: "Kontrollera hjulmoment", krav: "matvarde" }, - { id: "kast", text: "Kontrollera radial- och sidokast", krav: "matvarde" }, - { id: "balansering", text: "Kontrollera hjulbalansering", krav: "kommentar" }, - { id: "bussningar", text: "Kontrollera bussningar och leder", krav: "kommentar" }, - ], - }, - { - id: "provkorning", - rubrik: "Provkörning", - beskrivning: "Verifiera under provkörning:", - kontroller: [ - { id: "pk_hastighet", text: "Hastighet där vibration uppstår", krav: "kommentar" }, - { id: "pk_acc", text: "Förändring vid acceleration", krav: "kommentar" }, - { id: "pk_motorbroms", text: "Förändring vid motorbroms", krav: "kommentar" }, - { id: "pk_kurva", text: "Förändring vid kurvtagning", krav: "kommentar" }, - { id: "pk_var", text: "Om vibration känns i ratt eller kaross", krav: "kommentar" }, - ], - }, - ], -}; +// ---- Biblioteket --------------------------------------------------------- +// +// Metodikerna definieras i ./metodiker. Namnen nedan finns kvar för att +// äldre kod och tester ska fortsätta fungera oförändrat. -export const GENERISK_METODIK: Metodik = { - id: "generisk", - namn: "Generell strukturerad felsökning", - steg: [ - { - id: "symptom", - rubrik: "Verifiera symptom", - fragor: [ - { id: "reproducerbart", text: "Går felet att reproducera?", svarstyp: "janej" }, - { - id: "nar", - text: "När uppträder felet?", - svarstyp: "val", - val: ["Alltid", "Ibland", "Endast under drift", "Endast vid start"], - }, - { - id: "var", - text: "Var upplevs felet?", - svarstyp: "val", - val: ["Fram", "Bak", "Höger", "Vänster", "Motor/drivkälla", "Kupé/förarplats", "Okänt"], - }, - { - id: "hur", - text: "Hur upplevs felet?", - svarstyp: "val", - val: ["Skakar/vibrerar", "Missljud (knack/gnissel/vinande)", "Rycker", "Tappar kraft", "Stannar helt", "Annat"], - }, - { id: "forlopp", text: "Beskriv förloppet när felet uppstår", svarstyp: "text" }, - { id: "forandring", text: "Har något förändrats nyligen (service, reparation, miljö)?", svarstyp: "text" }, - ], - }, - { - id: "visuell", - rubrik: "Visuell kontroll", - kontroller: [ - { id: "foto_objekt", text: "Fotografera objektet och det berörda området", krav: "foto" }, - { id: "skador", text: "Kontrollera synliga skador, läckage eller lösa anslutningar", krav: "kommentar" }, - { id: "typskylt", text: "Dokumentera typskylt/märkning", krav: "foto" }, - ], - }, - { - id: "grundkontroller", - rubrik: "Grundkontroller", - kontroller: [ - { id: "matning", text: "Utför grundläggande mätningar (spänning, tryck, temperatur — det som är relevant)", krav: "matvarde" }, - { id: "sakringar", text: "Kontrollera säkringar/skydd", krav: "kommentar" }, - { id: "anslutningar", text: "Kontrollera kontaktdon och anslutningar", krav: "kommentar" }, - ], - }, - { - id: "funktionstest", - rubrik: "Funktionstest", - kontroller: [ - { id: "test", text: "Genomför funktionstest och dokumentera resultatet", krav: "kommentar" }, - ], - }, - ], -}; +export { + ALLA_METODIKER, + VIBRATION, + BROMSAR, + STYRNING_FJADRING, + ELSYSTEM, + START_LADDNING, + MOTOR_DRIFT, + KYLSYSTEM, + DRIVLINA, + AVGAS_EMISSION, + KLIMAT, + HOGVOLT, + DIAGNOS_NATVERK, + LACKAGE, + MISSLJUD, + ADAS, + GENERISK, +} from "./metodiker"; -// Elsystem-metodik enligt visionens relä-exempel: mätningar med krav på -// värden, reläkontroll och funktionstest. -export const ELSYSTEM_METODIK: Metodik = { - id: "elsystem", - namn: "Elsystem / strömförsörjning", - steg: [ - { - id: "symptom", - rubrik: "Verifiera symptom", - fragor: [ - { id: "reproducerbart", text: "Går felet att reproducera?", svarstyp: "janej" }, - { - id: "omfattning", - text: "Är funktionen helt död eller delvis fungerande?", - svarstyp: "val", - val: ["Helt död", "Delvis fungerande", "Intermittent"], - }, - { id: "funktion", text: "Vilken funktion saknas eller felar?", svarstyp: "text" }, - { id: "forandring", text: "Har något åtgärdats eller förändrats nyligen?", svarstyp: "text" }, - ], - }, - { - id: "visuell", - rubrik: "Visuell kontroll", - kontroller: [ - { id: "foto_komponent", text: "Fotografera komponenten och dess anslutningar", krav: "foto" }, - { id: "skador", text: "Kontrollera synliga skador, korrosion och lösa kontaktdon", krav: "kommentar" }, - ], - }, - { - id: "matningar", - rubrik: "Mätningar", - kontroller: [ - { id: "batterispanning", text: "Mät batterispänning", krav: "matvarde" }, - { id: "sakringar", text: "Kontrollera berörda säkringar", krav: "kommentar" }, - { id: "matningsspanning", text: "Mät matningsspänning vid komponenten", krav: "matvarde" }, - { id: "jord", text: "Mät spänningsfall mot jord", krav: "matvarde" }, - ], - }, - { - id: "rela", - rubrik: "Relä och styrsignal", - kontroller: [ - { id: "rela_klick", text: "Kontrollera om reläet klickar vid aktivering", krav: "kommentar" }, - { id: "styrsignal", text: "Mät styrsignal till reläet", krav: "matvarde" }, - ], - }, - { - id: "funktionstest", - rubrik: "Funktionstest", - kontroller: [ - { id: "test", text: "Genomför funktionstest och dokumentera resultatet", krav: "kommentar" }, - ], - }, - ], -}; - -export const METODIKER = [VIBRATION_METODIK, ELSYSTEM_METODIK, GENERISK_METODIK]; +export const VIBRATION_METODIK = VIBRATION; +export const ELSYSTEM_METODIK = ELSYSTEM; +export const GENERISK_METODIK = GENERISK; +export const METODIKER = ALLA_METODIKER; export function metodikForId(id: string): Metodik { - return METODIKER.find((m) => m.id === id) ?? GENERISK_METODIK; + return ALLA_METODIKER.find((m) => m.id === id) ?? GENERISK; } -export function valjMetodik(felbeskrivning: string): Metodik { - const text = felbeskrivning.toLowerCase(); - if (/vibr|skak|obalans/.test(text)) return VIBRATION_METODIK; - if (/relä|rela\b|säkring|elektr|spänning|volt\b|batteri|lampa|belysning|ström|kortslut/.test(text)) { - return ELSYSTEM_METODIK; +// ---- Val av metodik ------------------------------------------------------ + +// Korta ord matchas som helt ord, längre som ordstam. Annars skulle "ac" +// träffa "acceleration" och en vibration hamna i klimatanläggningen. +const HELT_ORD = 3; +const ORDTECKEN = "a-z0-9åäöéèü"; + +const monsterCache = new Map(); + +function monster(nyckelord: string): RegExp { + let m = monsterCache.get(nyckelord); + if (!m) { + const bokstavligt = nyckelord.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const slut = nyckelord.length <= HELT_ORD ? `(?![${ORDTECKEN}])` : ""; + m = new RegExp(`(? basta) { + basta = poang; + bast = metodik; + } + } + return bast; } export interface NastaSteg { diff --git a/felsokning/app/src/felsokning/metodiker.ts b/felsokning/app/src/felsokning/metodiker.ts new file mode 100644 index 0000000..ca0e6f6 --- /dev/null +++ b/felsokning/app/src/felsokning/metodiker.ts @@ -0,0 +1,899 @@ +// Metodikbiblioteket. +// +// En metodik är inte en checklista över vad som brukar vara fel — det +// vore att gissa åt teknikern. Den är en ordning för att utesluta: +// symptomet verifieras först, sedan det billiga och synliga, sedan det +// som kräver mätning, sist det som kräver demontering. +// +// Tre regler gäller alla metodiker här: +// +// 1. Varje kontroll har ett minimikrav (mätvärde, foto eller +// observation). En kryssruta är inte evidens. +// 2. Symptomsteget frågar aldrig "vad är fel" utan "vad händer, när, +// var". Kundens ord blir ett verifierat symptom först när det +// reproducerats. +// 3. Där arbetet kan skada någon kommer säkerhetssteget först och kan +// inte hoppas över — se HÖGVOLT. +// +// Att "täcka allt" går inte att lova. Det som går är att täcka fordonets +// system systematiskt och låta GENERISK vara ett strukturellt komplett +// skyddsnät: den fungerar även för det ingen förutsett. + +import type { Metodik } from "./metodik"; + +export const VIBRATION: Metodik = { + id: "vibration", + namn: "Vibration under körning", + omrade: "Hjul och balans", + nyckelord: ["vibration", "vibrer", "skak", "obalans", "ojämn gång", "rattvibration"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { id: "hastighetsberoende", text: "Är vibrationen hastighetsberoende?", svarstyp: "janej" }, + { id: "var", text: "Var känns vibrationen?", svarstyp: "val", val: ["I ratten", "I stolen", "I hela bilen"] }, + { + id: "nar", + text: "När uppstår vibrationen?", + svarstyp: "val", + val: ["Vid acceleration", "Vid jämn fart", "Vid inbromsning", "Alltid under körning"], + }, + { id: "intervall", text: "Försvinner den över eller under ett visst hastighetsintervall?", svarstyp: "text" }, + ], + }, + { + id: "visuell", + rubrik: "Visuell kontroll", + beskrivning: "Fotografera samtliga hjul. Skilj på observation och slutsats.", + kontroller: [ + { id: "foto_vf", text: "Fotografera vänster framhjul", krav: "foto" }, + { id: "foto_hf", text: "Fotografera höger framhjul", krav: "foto" }, + { id: "foto_vb", text: "Fotografera vänster bakhjul", krav: "foto" }, + { id: "foto_hb", text: "Fotografera höger bakhjul", krav: "foto" }, + { id: "dot", text: "Dokumentera DOT-/tillverkningsdatum", krav: "kommentar" }, + { id: "slitage", text: "Kontrollera däckslitage och slitagemönster", krav: "kommentar" }, + ], + }, + { + id: "kontroller", + rubrik: "Mätningar", + kontroller: [ + { id: "lufttryck", text: "Kontrollera lufttryck", krav: "matvarde" }, + { id: "hjulmoment", text: "Kontrollera hjulmoment", krav: "matvarde" }, + { id: "kast", text: "Kontrollera radial- och sidokast", krav: "matvarde" }, + { id: "balansering", text: "Kontrollera hjulbalansering", krav: "kommentar" }, + { id: "bussningar", text: "Kontrollera bussningar och leder", krav: "kommentar" }, + ], + }, + { + id: "provkorning", + rubrik: "Provkörning", + beskrivning: "Verifiera under provkörning:", + kontroller: [ + { id: "pk_hastighet", text: "Hastighet där vibration uppstår", krav: "kommentar" }, + { id: "pk_acc", text: "Förändring vid acceleration", krav: "kommentar" }, + { id: "pk_motorbroms", text: "Förändring vid motorbroms", krav: "kommentar" }, + { id: "pk_kurva", text: "Förändring vid kurvtagning", krav: "kommentar" }, + { id: "pk_var", text: "Om vibration känns i ratt eller kaross", krav: "kommentar" }, + ], + }, + ], +}; + +export const ELSYSTEM: Metodik = { + id: "elsystem", + namn: "Elsystem och strömförsörjning", + omrade: "El", + nyckelord: ["relä", "rela", "säkring", "elektr", "spänning", "volt", "lampa", "belysning", "ström", "kortslut", "kabel", "kabla", "kontaktdon", "jordfel"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { id: "reproducerbart", text: "Går felet att reproducera?", svarstyp: "janej" }, + { + id: "omfattning", + text: "Är funktionen helt död eller delvis fungerande?", + svarstyp: "val", + val: ["Helt död", "Delvis fungerande", "Intermittent"], + }, + { id: "funktion", text: "Vilken funktion saknas eller felar?", svarstyp: "text" }, + { id: "forandring", text: "Har något åtgärdats eller förändrats nyligen?", svarstyp: "text" }, + ], + }, + { + id: "visuell", + rubrik: "Visuell kontroll", + kontroller: [ + { id: "foto_komponent", text: "Fotografera komponenten och dess anslutningar", krav: "foto" }, + { id: "skador", text: "Kontrollera synliga skador, korrosion och lösa kontaktdon", krav: "kommentar" }, + ], + }, + { + id: "matningar", + rubrik: "Mätningar", + beskrivning: "Mät under belastning. En spänning utan last säger nästan ingenting om en dålig förbindelse.", + kontroller: [ + { id: "batterispanning", text: "Mät batterispänning", krav: "matvarde" }, + { id: "sakringar", text: "Kontrollera berörda säkringar", krav: "kommentar" }, + { id: "matningsspanning", text: "Mät matningsspänning vid komponenten under last", krav: "matvarde" }, + { id: "jord", text: "Mät spänningsfall mot jord under last", krav: "matvarde" }, + ], + }, + { + id: "rela", + rubrik: "Relä och styrsignal", + kontroller: [ + { id: "rela_klick", text: "Kontrollera om reläet klickar vid aktivering", krav: "kommentar" }, + { id: "styrsignal", text: "Mät styrsignal till reläet", krav: "matvarde" }, + ], + }, + { + id: "funktionstest", + rubrik: "Funktionstest", + kontroller: [{ id: "test", text: "Genomför funktionstest och dokumentera resultatet", krav: "kommentar" }], + }, + ], +}; + +export const START_LADDNING: Metodik = { + id: "start_laddning", + namn: "Start- och laddningssystem", + omrade: "El", + nyckelord: ["startar inte", "startproblem", "startmotor", "generator", "laddning", "batteriet dör", "urladdat", "batterilampa", "drar inte runt", "klick vid start"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "beteende", + text: "Vad händer vid startförsök?", + svarstyp: "val", + val: ["Ingenting alls", "Ett klick", "Drar runt långsamt", "Drar runt normalt men tänder inte", "Startar ibland"], + }, + { id: "kallt_varmt", text: "Uppträder felet kallt, varmt eller alltid?", svarstyp: "val", val: ["Kallt", "Varmt", "Alltid"] }, + { id: "stillestand", text: "Hur länge har fordonet stått mellan försöken?", svarstyp: "text" }, + { id: "laddat", text: "Har batteriet laddats eller bytts nyligen?", svarstyp: "text" }, + ], + }, + { + id: "batteri", + rubrik: "Batteriets kondition", + beskrivning: "Ett svagt batteri ger följdfel i hela fordonet. Uteslut det först.", + kontroller: [ + { id: "vilospanning", text: "Mät vilospänning efter minst en timmes vila", krav: "matvarde" }, + { id: "batteritest", text: "Belastningstest — fotografera testarens resultat", krav: "foto" }, + { id: "poler", text: "Kontrollera polskor och jordflätor", krav: "kommentar" }, + ], + }, + { + id: "start", + rubrik: "Startsystem", + kontroller: [ + { id: "startspanning", text: "Mät spänning vid startmotorn under startförsök", krav: "matvarde" }, + { id: "spanningsfall_plus", text: "Mät spänningsfall i plusledningen under start", krav: "matvarde" }, + { id: "spanningsfall_jord", text: "Mät spänningsfall i jordledningen under start", krav: "matvarde" }, + { id: "startsignal", text: "Kontrollera styrsignal till startrelä", krav: "matvarde" }, + ], + }, + { + id: "laddning", + rubrik: "Laddningssystem", + kontroller: [ + { id: "laddspanning", text: "Mät laddspänning vid tomgång och vid förhöjt varvtal", krav: "matvarde" }, + { id: "rippel", text: "Mät rippel från generatorn", krav: "matvarde" }, + { id: "rem", text: "Kontrollera drivrem och spänning", krav: "kommentar" }, + ], + }, + { + id: "krypstrom", + rubrik: "Krypström", + beskrivning: "Endast relevant när batteriet laddar ur under stillestånd.", + kontroller: [ + { id: "vilostrom", text: "Mät viloström efter att fordonet somnat", krav: "matvarde" }, + { id: "sakringsdrag", text: "Lokalisera krets genom successiv säkringsurtagning", krav: "kommentar" }, + ], + }, + ], +}; + +export const MOTOR_DRIFT: Metodik = { + id: "motor_drift", + namn: "Motorgång och effekt", + omrade: "Motor", + nyckelord: ["ryck", "tappar kraft", "effektbrist", "misständ", "ojämn tomgång", "tomgång", "motorlampa", "kraftlös", "hack", "går på tre"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "nar", + text: "När uppträder felet?", + svarstyp: "val", + val: ["Vid kallstart", "Vid tomgång", "Under belastning", "Vid visst varvtal", "Alltid"], + }, + { id: "varvtal", text: "Vid vilket varvtal eller vilken last?", svarstyp: "text" }, + { id: "varningslampa", text: "Lyser eller blinkar motorlampan?", svarstyp: "val", val: ["Lyser fast", "Blinkar", "Slocknad"] }, + { id: "brankslebyte", text: "Har bränsle tankats eller service utförts strax innan?", svarstyp: "text" }, + ], + }, + { + id: "felkoder", + rubrik: "Felkoder och mätdata", + beskrivning: "Läs innan något demonteras. En felkod pekar på en krets, inte på en trasig komponent.", + kontroller: [ + { id: "dtc", text: "Läs felkoder — fotografera diagnosskärmen", krav: "foto" }, + { id: "frysdata", text: "Dokumentera frysramsdata för koden", krav: "kommentar" }, + { id: "misstandning", text: "Läs misständningsräknare per cylinder", krav: "matvarde" }, + { id: "branslekorrigering", text: "Läs kort- och långtidsbränslekorrigering", krav: "matvarde" }, + ], + }, + { + id: "mekanik", + rubrik: "Motorns grundkondition", + beskrivning: "Utan grundkondition är alla givarvärden svåra att tolka.", + kontroller: [ + { id: "kompression", text: "Mät kompression eller relativ kompression", krav: "matvarde" }, + { id: "vevhustryck", text: "Kontrollera vevhustryck", krav: "kommentar" }, + { id: "insugslackage", text: "Kontrollera insugssystemet för falskluft", krav: "kommentar" }, + ], + }, + { + id: "tandning_bransle", + rubrik: "Tändning och bränsle", + kontroller: [ + { id: "tandstift", text: "Kontrollera tändstift — fotografera samtliga", krav: "foto" }, + { id: "spolar", text: "Mät tändspolarnas resistans eller byt mellan cylindrar", krav: "matvarde" }, + { id: "bransletryck", text: "Mät bränsletryck under belastning", krav: "matvarde" }, + { id: "insprutare", text: "Kontrollera insprutarnas returmängd eller styrning", krav: "matvarde" }, + ], + }, + { + id: "provkorning", + rubrik: "Provkörning med loggning", + kontroller: [ + { id: "logg", text: "Logga mätdata under körning där felet uppträder", krav: "foto" }, + { id: "reproducerat", text: "Dokumentera under vilka förhållanden felet uppträdde", krav: "kommentar" }, + ], + }, + ], +}; + +export const BROMSAR: Metodik = { + id: "bromsar", + namn: "Bromssystem", + omrade: "Chassi", + nyckelord: ["broms", "bromspedal", "skevhet", "gnisslar vid inbromsning", "abs", "bromsvätska", "handbroms", "drar snett vid inbromsning"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "karaktar", + text: "Hur yttrar sig felet?", + svarstyp: "val", + val: ["Skevhet/pulsering", "Missljud", "Lång pedalväg", "Mjuk pedal", "Drar åt sidan", "Bromsen ligger på"], + }, + { id: "nar", text: "Vid vilken hastighet och bromskraft?", svarstyp: "text" }, + { id: "varningslampa", text: "Lyser broms- eller ABS-varning?", svarstyp: "janej" }, + { id: "senaste", text: "När byttes bromskomponenter senast?", svarstyp: "text" }, + ], + }, + { + id: "visuell", + rubrik: "Visuell kontroll", + kontroller: [ + { id: "foto_belagg", text: "Fotografera belägg och skivor på samtliga hjul", krav: "foto" }, + { id: "belaggtjocklek", text: "Mät beläggtjocklek", krav: "matvarde" }, + { id: "skivtjocklek", text: "Mät skivtjocklek och jämför med minmått", krav: "matvarde" }, + { id: "lackage", text: "Kontrollera slangar, rör och ok för läckage", krav: "kommentar" }, + ], + }, + { + id: "matningar", + rubrik: "Mätningar", + kontroller: [ + { id: "skivkast", text: "Mät skivkast med mätklocka", krav: "matvarde" }, + { id: "tjockleksvariation", text: "Mät tjockleksvariation på skivan", krav: "matvarde" }, + { id: "vatska", text: "Mät bromsvätskans kokpunkt eller vatteninnehåll", krav: "matvarde" }, + { id: "okens_rorlighet", text: "Kontrollera okens och styrbultarnas rörlighet", krav: "kommentar" }, + ], + }, + { + id: "system", + rubrik: "System och ABS", + kontroller: [ + { id: "dtc", text: "Läs felkoder ur ABS-styrenheten", krav: "foto" }, + { id: "hjulgivare", text: "Kontrollera hjulhastighetsgivarnas signal", krav: "matvarde" }, + { id: "bromsprov", text: "Utför bromsprov i provbänk — fotografera protokollet", krav: "foto" }, + ], + }, + ], +}; + +export const STYRNING_FJADRING: Metodik = { + id: "styrning_fjadring", + namn: "Styrning och fjädring", + omrade: "Chassi", + nyckelord: ["drar åt", "styrning", "ratt", "glapp", "stötdämpar", "fjäder", "fjädr", "hjulinställning", "spårar", "gungar", "knäpper i kurva", "servostyrning"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "karaktar", + text: "Hur yttrar sig felet?", + svarstyp: "val", + val: ["Drar åt sidan", "Glapp i ratten", "Missljud", "Dålig vägkänsla", "Ojämnt däckslitage", "Gungar/studsar"], + }, + { id: "underlag", text: "Uppträder det på visst underlag eller i viss kurva?", svarstyp: "text" }, + { id: "handelse", text: "Har fordonet kört på något eller varit i kontakt med trottoarkant?", svarstyp: "text" }, + ], + }, + { + id: "visuell", + rubrik: "Visuell kontroll", + kontroller: [ + { id: "foto_slitage", text: "Fotografera däckens slitagemönster", krav: "foto" }, + { id: "dampare", text: "Kontrollera dämpare för läckage", krav: "kommentar" }, + { id: "damask", text: "Kontrollera damasker på styrleder och drivknutar", krav: "kommentar" }, + ], + }, + { + id: "glapp", + rubrik: "Glappkontroll", + beskrivning: "Utförs med hjulet avlastat. Dokumentera var glappet finns, inte bara att det finns.", + kontroller: [ + { id: "hjullager", text: "Kontrollera hjullagerspel", krav: "kommentar" }, + { id: "styrleder", text: "Kontrollera styr- och bärleder", krav: "kommentar" }, + { id: "bussningar", text: "Kontrollera bussningar", krav: "kommentar" }, + { id: "kuggstang", text: "Kontrollera kuggstång och styrstagsändar", krav: "kommentar" }, + ], + }, + { + id: "installning", + rubrik: "Hjulinställning", + kontroller: [ + { id: "matning", text: "Mät hjulinställning — fotografera protokollet före justering", krav: "foto" }, + { id: "avvikelse", text: "Dokumentera avvikelser mot tillverkarens värden", krav: "matvarde" }, + ], + }, + ], +}; + +export const KYLSYSTEM: Metodik = { + id: "kylsystem", + namn: "Kylsystem och överhettning", + omrade: "Motor", + nyckelord: ["överhett", "koka", "kylvätska", "temperatur", "termostat", "kylare", "vattenpump", "värme i kupén", "expansionskärl"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "nar", + text: "När stiger temperaturen?", + svarstyp: "val", + val: ["Vid tomgång", "I låg fart", "I hög fart", "Vid belastning/backe", "Alltid"], + }, + { id: "kylvatskeforlust", text: "Förloras kylvätska? Hur mycket och hur ofta?", svarstyp: "text" }, + { id: "varme", text: "Fungerar kupévärmen?", svarstyp: "janej" }, + ], + }, + { + id: "visuell", + rubrik: "Visuell kontroll", + kontroller: [ + { id: "niva", text: "Kontrollera kylvätskenivå kall — fotografera expansionskärlet", krav: "foto" }, + { id: "lackage", text: "Kontrollera synligt läckage vid slangar, kylare och pump", krav: "kommentar" }, + { id: "kylarpaket", text: "Kontrollera kylarpaketet för igensättning", krav: "foto" }, + ], + }, + { + id: "matningar", + rubrik: "Mätningar", + kontroller: [ + { id: "trycktest", text: "Trycktesta kylsystemet", krav: "matvarde" }, + { id: "lock", text: "Trycktesta expansionskärlets lock", krav: "matvarde" }, + { id: "temperatur", text: "Mät temperatur in och ut ur kylaren med IR-termometer", krav: "matvarde" }, + { id: "flakt", text: "Kontrollera att kylfläkten startar vid rätt temperatur", krav: "kommentar" }, + { id: "givare", text: "Jämför styrenhetens temperaturvärde med uppmätt", krav: "matvarde" }, + ], + }, + { + id: "packning", + rubrik: "Topplockspackning", + beskrivning: "Görs när kylvätska förloras utan yttre läckage.", + kontroller: [ + { id: "avgastest", text: "Avgastest i kylvätskan (CO2-test)", krav: "foto" }, + { id: "kompression_kyl", text: "Kontrollera trycksättning av kylsystemet vid motorgång", krav: "kommentar" }, + ], + }, + ], +}; + +export const DRIVLINA: Metodik = { + id: "drivlina", + namn: "Växellåda och drivlina", + omrade: "Drivlina", + nyckelord: ["växellåda", "växlar", "koppling", "automatlåda", "rycker vid växling", "slir", "drivknut", "kardan", "differential", "kärvar i växeln"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "karaktar", + text: "Hur yttrar sig felet?", + svarstyp: "val", + val: ["Slirar", "Rycker vid växling", "Går inte i växel", "Missljud", "Vibration vid acceleration", "Läckage"], + }, + { id: "vaxel", text: "Vilken växel eller vilket varvtal?", svarstyp: "text" }, + { id: "kall_varm", text: "Kall eller varm låda?", svarstyp: "val", val: ["Kall", "Varm", "Ingen skillnad"] }, + ], + }, + { + id: "visuell", + rubrik: "Visuell kontroll", + kontroller: [ + { id: "olja", text: "Kontrollera oljenivå och oljans skick — fotografera", krav: "foto" }, + { id: "lackage", text: "Kontrollera läckage vid tätningar och sump", krav: "kommentar" }, + { id: "fasten", text: "Kontrollera växellådsfästen", krav: "kommentar" }, + ], + }, + { + id: "matningar", + rubrik: "Mätningar och avläsning", + kontroller: [ + { id: "dtc", text: "Läs felkoder ur växellådsstyrenheten", krav: "foto" }, + { id: "adaptioner", text: "Dokumentera adaptionsvärden och kopplingsslitage", krav: "matvarde" }, + { id: "oljetemp", text: "Mät oljetemperatur under provkörning", krav: "matvarde" }, + ], + }, + { + id: "provkorning", + rubrik: "Provkörning", + kontroller: [ + { id: "vaxlingspunkter", text: "Dokumentera växlingspunkter och beteende", krav: "kommentar" }, + { id: "belastning", text: "Provkör under belastning där felet uppträder", krav: "kommentar" }, + ], + }, + ], +}; + +export const AVGAS_EMISSION: Metodik = { + id: "avgas_emission", + namn: "Avgassystem och emissioner", + omrade: "Motor", + nyckelord: ["partikelfilt", "dpf", "adblue", "katalysator", "lambda", "avgas", "emission", "rökutveckling", "svart rök", "blå rök", "os", "egr", "regenerer", "utsläpp"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "karaktar", + text: "Hur yttrar sig felet?", + svarstyp: "val", + val: ["Varningslampa", "Rök", "Effektbegränsning", "Lukt", "Underkänd besiktning"], + }, + { id: "rokfarg", text: "Om rök — vilken färg och när?", svarstyp: "text" }, + { id: "korprofil", text: "Beskriv fordonets körprofil (mest kort- eller långkörning)?", svarstyp: "text" }, + ], + }, + { + id: "avlasning", + rubrik: "Avläsning", + kontroller: [ + { id: "dtc", text: "Läs felkoder — fotografera diagnosskärmen", krav: "foto" }, + { id: "sotmangd", text: "Läs beräknad och uppmätt sotmängd i partikelfiltret", krav: "matvarde" }, + { id: "regenerering", text: "Dokumentera antal och utfall av senaste regenereringar", krav: "kommentar" }, + { id: "lambda", text: "Läs lambdagivarnas signaler före och efter katalysator", krav: "matvarde" }, + ], + }, + { + id: "matningar", + rubrik: "Mätningar", + kontroller: [ + { id: "mottryck", text: "Mät avgasmottryck", krav: "matvarde" }, + { id: "differenstryck", text: "Mät differenstryck över partikelfiltret", krav: "matvarde" }, + { id: "adblue_niva", text: "Kontrollera AdBlue-nivå och kvalitet där sådant finns", krav: "matvarde" }, + { id: "egr", text: "Kontrollera EGR-ventilens funktion och läge", krav: "matvarde" }, + ], + }, + { + id: "orsak", + rubrik: "Bakomliggande orsak", + beskrivning: "Ett igensatt filter är oftast en följd, inte orsaken. Dokumentera vad som skapade sotet.", + kontroller: [ + { id: "grundorsak", text: "Kontrollera insprutning, turbo och luftflöde", krav: "kommentar" }, + { id: "korstrackor", text: "Bedöm om körprofilen tillåter regenerering", krav: "kommentar" }, + ], + }, + ], +}; + +export const KLIMAT: Metodik = { + id: "klimat", + namn: "Klimatanläggning", + omrade: "Komfort", + nyckelord: ["ac", "luftkonditionering", "klimatanläggning", "kyler inte", "kompressor", "köldmedi", "imma", "immig", "fläkt", "lukt i kupén", "värmepaket"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "karaktar", + text: "Hur yttrar sig felet?", + svarstyp: "val", + val: ["Kyler inte alls", "Kyler dåligt", "Kyler ibland", "Missljud", "Lukt", "Imma på rutorna"], + }, + { id: "sidor", text: "Skiljer det mellan höger och vänster sida?", svarstyp: "janej" }, + { id: "service", text: "När utfördes AC-service senast?", svarstyp: "text" }, + ], + }, + { + id: "visuell", + rubrik: "Visuell kontroll", + kontroller: [ + { id: "kondensor", text: "Fotografera kondensorn — kontrollera igensättning och skador", krav: "foto" }, + { id: "kupefilter", text: "Kontrollera kupéfiltret", krav: "foto" }, + { id: "kompressor_rem", text: "Kontrollera kompressorns drivning och magnetkoppling", krav: "kommentar" }, + ], + }, + { + id: "matningar", + rubrik: "Mätningar", + kontroller: [ + { id: "tryck", text: "Mät hög- och lågtryck vid känd omgivningstemperatur", krav: "matvarde" }, + { id: "utblastemp", text: "Mät utblåstemperatur vid mittre munstycke", krav: "matvarde" }, + { id: "mangd", text: "Väg upptagen köldmediemängd vid tömning", krav: "matvarde" }, + { id: "lackagesok", text: "Läcksök med spårgas eller UV", krav: "kommentar" }, + ], + }, + { + id: "styrning", + rubrik: "Styrning", + kontroller: [ + { id: "dtc", text: "Läs felkoder ur klimatstyrenheten", krav: "foto" }, + { id: "spjall", text: "Kontrollera spjällmotorernas rörelse", krav: "kommentar" }, + ], + }, + ], +}; + +export const HOGVOLT: Metodik = { + id: "hogvolt", + namn: "Högvoltsystem — elbil och hybrid", + omrade: "Högvolt", + nyckelord: ["högvolt", "elbil", "hybrid", "traktionsbatteri", "hv", "laddning av bil", "räckvidd", "laddbox", "orange kabel", "sköldpadda"], + steg: [ + { + id: "sakerhet", + rubrik: "Säkerhet — utförs först", + beskrivning: + "Högvoltsystem kan vara livsfarliga. Inget arbete på systemet påbörjas innan stegen nedan är dokumenterade. Kräver behörighet för arbete på högvoltsystem.", + fragor: [ + { id: "behorighet", text: "Har du behörighet för arbete på högvoltsystem?", svarstyp: "janej" }, + { id: "avstangt", text: "Är fordonet spänningslöst enligt tillverkarens rutin?", svarstyp: "janej" }, + ], + kontroller: [ + { id: "service_disconnect", text: "Dokumentera att servicebrytaren är urtagen och säkrad", krav: "foto" }, + { id: "vantetid", text: "Dokumentera väntetid enligt tillverkarens anvisning", krav: "kommentar" }, + { id: "spanningsfrihet", text: "Mät och dokumentera spänningsfrihet före ingrepp", krav: "matvarde" }, + { id: "skyddsutrustning", text: "Dokumentera använd skyddsutrustning och avspärrning", krav: "foto" }, + ], + }, + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "karaktar", + text: "Hur yttrar sig felet?", + svarstyp: "val", + val: ["Laddar inte", "Kortare räckvidd", "Effektbegränsning", "Varningsmeddelande", "Fordonet startar inte"], + }, + { id: "laddtyp", text: "Vid vilken laddning uppträder felet (AC, DC, vilken laddpunkt)?", svarstyp: "text" }, + { id: "temperatur", text: "Vid vilken omgivnings- och batteritemperatur?", svarstyp: "text" }, + ], + }, + { + id: "avlasning", + rubrik: "Avläsning", + beskrivning: "Utförs med diagnosverktyg — inga ingrepp i systemet krävs.", + kontroller: [ + { id: "dtc", text: "Läs felkoder ur samtliga högvoltstyrenheter", krav: "foto" }, + { id: "soh", text: "Läs batteriets hälsa (SOH) och laddnivå (SOC)", krav: "matvarde" }, + { id: "cellspanning", text: "Läs cellspänningar och dokumentera största avvikelse", krav: "matvarde" }, + { id: "isolationsvarde", text: "Läs systemets isolationsvärde", krav: "matvarde" }, + { id: "temperaturer", text: "Läs batteriets temperaturgivare", krav: "matvarde" }, + ], + }, + { + id: "laddning", + rubrik: "Laddkedjan", + kontroller: [ + { id: "laddkabel", text: "Kontrollera laddkabel och laddkontakt — fotografera stiften", krav: "foto" }, + { id: "laddlogg", text: "Läs laddhistorik och avbrottsorsaker", krav: "kommentar" }, + { id: "extern", text: "Testa mot annan laddpunkt för att utesluta yttre orsak", krav: "kommentar" }, + ], + }, + ], +}; + +export const DIAGNOS_NATVERK: Metodik = { + id: "diagnos_natverk", + namn: "Felkoder och kommunikation", + omrade: "Diagnos", + nyckelord: ["felkod", "dtc", "can", "canbuss", "kommunikationsfel", "ingen kontakt", "styrenhet", "obd", "diagnos", "flera lampor"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "omfattning", + text: "Hur många system är berörda?", + svarstyp: "val", + val: ["En styrenhet", "Flera styrenheter", "Hela fordonet", "Endast diagnosverktyget"], + }, + { id: "nar", text: "Uppstod felet efter ingrepp, batteribyte eller uppdatering?", svarstyp: "text" }, + ], + }, + { + id: "grund", + rubrik: "Grundförutsättningar", + beskrivning: "Kommunikationsfel beror oftare på matning och jord än på styrenheten.", + kontroller: [ + { id: "batteri", text: "Mät batterispänning under avläsning", krav: "matvarde" }, + { id: "obd_matning", text: "Mät matning och jord i diagnosuttaget", krav: "matvarde" }, + { id: "sakringar", text: "Kontrollera säkringar till berörda styrenheter", krav: "kommentar" }, + ], + }, + { + id: "buss", + rubrik: "Bussmätning", + kontroller: [ + { id: "terminering", text: "Mät bussens termineringsresistans med systemet spänningslöst", krav: "matvarde" }, + { id: "bussignal", text: "Mät CAN-signalen med oscilloskop — fotografera kurvan", krav: "foto" }, + { id: "avdelning", text: "Dela av bussen för att lokalisera störande nod", krav: "kommentar" }, + ], + }, + { + id: "koder", + rubrik: "Felkoder i sammanhang", + beskrivning: "En felkod pekar på en krets, inte på en trasig komponent. Läs alla system innan någon kod raderas.", + kontroller: [ + { id: "helavlasning", text: "Läs samtliga styrenheter — fotografera listan", krav: "foto" }, + { id: "frysdata", text: "Dokumentera frysramsdata innan radering", krav: "kommentar" }, + { id: "efter_radering", text: "Radera, provkör och dokumentera vilka koder som återkom", krav: "kommentar" }, + ], + }, + ], +}; + +export const LACKAGE: Metodik = { + id: "lackage", + namn: "Läckage", + omrade: "Övrigt", + nyckelord: ["läck", "läckage", "oljefläck", "dropp", "vatten i bilen", "fukt", "blöt matta", "oljeförbrukning"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "vatska", + text: "Vilken vätska misstänks?", + svarstyp: "val", + val: ["Motorolja", "Kylvätska", "Växellådsolja", "Bromsvätska", "Bränsle", "Vatten/kondens", "Okänt"], + }, + { id: "mangd", text: "Hur mycket och hur ofta?", svarstyp: "text" }, + { id: "plats", text: "Var på marken syns fläcken i förhållande till fordonet?", svarstyp: "text" }, + ], + }, + { + id: "visuell", + rubrik: "Lokalisering", + beskrivning: "Rengör först. Ett gammalt läckage döljer var det nya kommer ifrån.", + kontroller: [ + { id: "foto_fore", text: "Fotografera området före rengöring", krav: "foto" }, + { id: "rengoring", text: "Rengör området och dokumentera att det är torrt", krav: "foto" }, + { id: "provkorning", text: "Provkör eller låt gå och fotografera var vätskan uppträder", krav: "foto" }, + ], + }, + { + id: "metod", + rubrik: "Läcksökning", + kontroller: [ + { id: "uv", text: "Läcksök med UV-spårämne där det är tillämpligt", krav: "kommentar" }, + { id: "trycktest", text: "Trycktesta systemet", krav: "matvarde" }, + { id: "niva", text: "Mät nivåförändring över tid", krav: "matvarde" }, + ], + }, + ], +}; + +export const MISSLJUD: Metodik = { + id: "missljud", + namn: "Missljud", + omrade: "Övrigt", + nyckelord: ["missljud", "ljud", "knack", "gnissel", "gnissl", "vinande", "brumm", "skram", "väsande", "tjut"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + beskrivning: "Ett missljud som inte reproducerats går inte att åtgärda. Spela in det.", + fragor: [ + { + id: "karaktar", + text: "Vilken karaktär har ljudet?", + svarstyp: "val", + val: ["Knack", "Gnissel", "Vinande", "Brummande", "Skrammel", "Väsande", "Tjut"], + }, + { + id: "nar", + text: "När hörs det?", + svarstyp: "val", + val: ["Vid start", "Vid tomgång", "Under körning", "Vid inbromsning", "Vid kurvtagning", "Över ojämnheter"], + }, + { id: "beroende", text: "Följer ljudet varvtal eller hastighet?", svarstyp: "val", val: ["Varvtal", "Hastighet", "Ingetdera"] }, + { id: "temperatur", text: "Skillnad kallt mot varmt?", svarstyp: "text" }, + ], + }, + { + id: "inspelning", + rubrik: "Dokumentera ljudet", + beskrivning: "Video med ljud är evidens. En beskrivning i text är det inte.", + kontroller: [ + { id: "video", text: "Spela in ljudet med video under de förhållanden där det uppträder", krav: "foto" }, + { id: "forhallanden", text: "Dokumentera hastighet, varvtal och underlag vid inspelningen", krav: "kommentar" }, + ], + }, + { + id: "lokalisering", + rubrik: "Lokalisering", + kontroller: [ + { id: "stetoskop", text: "Lokalisera med stetoskop eller ljudsond", krav: "kommentar" }, + { id: "avlastning", text: "Kontrollera om ljudet ändras vid avlastning eller belastning", krav: "kommentar" }, + { id: "uteslutning", text: "Dokumentera vilka källor som uteslutits och hur", krav: "kommentar" }, + ], + }, + ], +}; + +export const ADAS: Metodik = { + id: "adas", + namn: "Förarassistans och kalibrering", + omrade: "Diagnos", + nyckelord: ["adas", "kamera", "radar", "filhållning", "adaptiv farthållare", "kalibrer", "vindruta", "parkeringssensor", "döda vinkeln", "nödbroms"], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { + id: "funktion", + text: "Vilken funktion felar?", + svarstyp: "val", + val: ["Filhållning", "Adaptiv farthållare", "Automatisk nödbroms", "Döda vinkeln", "Parkeringshjälp", "Backkamera"], + }, + { id: "ingrepp", text: "Har vindruta, kaross eller fjädring åtgärdats nyligen?", svarstyp: "text" }, + { id: "forhallanden", text: "Uppträder felet i visst väder eller ljus?", svarstyp: "text" }, + ], + }, + { + id: "forutsattningar", + rubrik: "Förutsättningar för kalibrering", + beskrivning: + "En kalibrering på fel förutsättningar ger ett fel som ser åtgärdat ut. Dokumentera att kraven är uppfyllda innan den utförs.", + kontroller: [ + { id: "dtc", text: "Läs felkoder ur berörda styrenheter", krav: "foto" }, + { id: "hjulinstallning", text: "Kontrollera hjulinställning — bakaxelns spårning påverkar kameran", krav: "matvarde" }, + { id: "dacktryck", text: "Kontrollera däcktryck och körhöjd", krav: "matvarde" }, + { id: "sikt", text: "Kontrollera kamerans och radarns siktfält för smuts eller skada", krav: "foto" }, + { id: "yta", text: "Dokumentera att kalibreringsytan uppfyller kraven på planhet och ljus", krav: "foto" }, + ], + }, + { + id: "kalibrering", + rubrik: "Kalibrering", + kontroller: [ + { id: "utford", text: "Utför kalibrering enligt tillverkarens metod — fotografera resultatet", krav: "foto" }, + { id: "provkorning", text: "Provkör och verifiera funktionen under de förhållanden felet uppträdde", krav: "kommentar" }, + ], + }, + ], +}; + +export const GENERISK: Metodik = { + id: "generisk", + namn: "Generell strukturerad felsökning", + omrade: "Övrigt", + nyckelord: [], + steg: [ + { + id: "symptom", + rubrik: "Verifiera symptom", + fragor: [ + { id: "reproducerbart", text: "Går felet att reproducera?", svarstyp: "janej" }, + { + id: "nar", + text: "När uppträder felet?", + svarstyp: "val", + val: ["Alltid", "Ibland", "Endast under drift", "Endast vid start"], + }, + { + id: "var", + text: "Var upplevs felet?", + svarstyp: "val", + val: ["Fram", "Bak", "Höger", "Vänster", "Motor/drivkälla", "Kupé/förarplats", "Okänt"], + }, + { + id: "hur", + text: "Hur upplevs felet?", + svarstyp: "val", + val: ["Skakar/vibrerar", "Missljud (knack/gnissel/vinande)", "Rycker", "Tappar kraft", "Stannar helt", "Annat"], + }, + { id: "forlopp", text: "Beskriv förloppet när felet uppstår", svarstyp: "text" }, + { id: "forandring", text: "Har något förändrats nyligen (service, reparation, miljö)?", svarstyp: "text" }, + ], + }, + { + id: "visuell", + rubrik: "Visuell kontroll", + kontroller: [ + { id: "foto_objekt", text: "Fotografera objektet och det berörda området", krav: "foto" }, + { id: "skador", text: "Kontrollera synliga skador, läckage eller lösa anslutningar", krav: "kommentar" }, + { id: "typskylt", text: "Dokumentera typskylt/märkning", krav: "foto" }, + ], + }, + { + id: "grundkontroller", + rubrik: "Grundkontroller", + kontroller: [ + { + id: "matning", + text: "Utför grundläggande mätningar (spänning, tryck, temperatur — det som är relevant)", + krav: "matvarde", + }, + { id: "sakringar", text: "Kontrollera säkringar/skydd", krav: "kommentar" }, + { id: "anslutningar", text: "Kontrollera kontaktdon och anslutningar", krav: "kommentar" }, + ], + }, + { + id: "funktionstest", + rubrik: "Funktionstest", + kontroller: [{ id: "test", text: "Genomför funktionstest och dokumentera resultatet", krav: "kommentar" }], + }, + ], +}; + +// Ordningen styr bara hur de visas. Valet görs på nyckelord, inte på +// position — GENERISK ligger sist eftersom den är fallback. +export const ALLA_METODIKER: Metodik[] = [ + VIBRATION, + BROMSAR, + STYRNING_FJADRING, + ELSYSTEM, + START_LADDNING, + MOTOR_DRIFT, + KYLSYSTEM, + DRIVLINA, + AVGAS_EMISSION, + KLIMAT, + HOGVOLT, + DIAGNOS_NATVERK, + LACKAGE, + MISSLJUD, + ADAS, + GENERISK, +]; diff --git a/felsokning/docs/DEMO.md b/felsokning/docs/DEMO.md index c2a580a..d28dfb8 100644 --- a/felsokning/docs/DEMO.md +++ b/felsokning/docs/DEMO.md @@ -64,7 +64,7 @@ Det ersätter inte teknikern. Det ersätter pärmen, minneslapparna och "fråga | I demon | I produktion | | --- | --- | -| Deterministisk metodikmotor (3 metodiker) | LLM väljer/genererar steg genom samma motorgränssnitt | +| Deterministisk metodikmotor (16 metodiker) | LLM väljer/genererar steg genom samma motorgränssnitt | | Webbläsarens taligenkänning | Leverantörens Voice-to-Text bakom samma gränssnitt | | localStorage + synk vid inloggning | Multi-tenant-backend (migration finns), roller enligt Master Prompt | | Delningslänk kräver synkat ärende | Live Share med behörighetsnivåer kund/intern/partner | diff --git a/felsokning/docs/MVP.md b/felsokning/docs/MVP.md index 4716bd0..2a0cb3a 100644 --- a/felsokning/docs/MVP.md +++ b/felsokning/docs/MVP.md @@ -28,7 +28,7 @@ Demomanus för visning: [DEMO.md](DEMO.md). Knappen **Skapa demoärende** på st | Direktivets kärna | Status i MVP | | --- | --- | | Objektidentifiering först | ✅ **QR-/streckkodsläsning** (`src/felsokning/streckkod.ts`): kameraströmmen läser QR, Code 39/128, Data Matrix och PDF417 via webbläsarens BarcodeDetector. Avläst kod klassificeras innan den används — VIN (17 tecken utan I/O/Q), svenskt regnr (båda serierna) eller serienummer — och identifieraren plockas ut även ur QR-innehåll som URL:er eller `vin=…`-fält; fritext och nakna URL:er avvisas. Saknar webbläsaren API:t (t.ex. iOS/Safari) **fotograferas typskylten** i stället och plattformens bildtolkning läser av den — kameran är gränssnittet oavsett enhet. Manuell inmatning med bekräftelsesteg finns kvar. | -| AI-guidad felsökning | ✅ Deterministisk metodikmotor (en fråga i taget, tre metodiker) **plus Claude-orkestern driven av plattformen**: edge-funktionen `felsokning-ai` äger Claude API-nyckeln (serverhemligheten `ANTHROPIC_API_KEY`) och routar per uppgift — handledning i realtid (Sonnet 5), djupgranskning av hela underlaget via knapp i briefen (Opus 5, hög effort), AI-komplettering av överlämningen med risker & osäkerheter (Sonnet 5) och metodikklassificering av felbeskrivningen (Haiku 4.5). Alla svar är schema-bundna och klassificerade enligt AI-reglerna, med automatisk fallback till Anthropics rekommenderade reservmodell vid avböjd förfrågan; modellen som svarade loggas i varje händelse. Kräver inloggad användare; svaren är interna och delas aldrig i kundvyer. I lokalt läge guidar metodiken ensam. | +| AI-guidad felsökning | ✅ Deterministisk metodikmotor (en fråga i taget, sexton metodiker) **plus Claude-orkestern driven av plattformen**: edge-funktionen `felsokning-ai` äger Claude API-nyckeln (serverhemligheten `ANTHROPIC_API_KEY`) och routar per uppgift — handledning i realtid (Sonnet 5), djupgranskning av hela underlaget via knapp i briefen (Opus 5, hög effort), AI-komplettering av överlämningen med risker & osäkerheter (Sonnet 5) och metodikklassificering av felbeskrivningen (Haiku 4.5). Alla svar är schema-bundna och klassificerade enligt AI-reglerna, med automatisk fallback till Anthropics rekommenderade reservmodell vid avböjd förfrågan; modellen som svarade loggas i varje händelse. Kräver inloggad användare; svaren är interna och delas aldrig i kundvyer. I lokalt läge guidar metodiken ensam. | | Arbetslogg | ✅ Append-only händelselogg med tidsstämpel och användare på varje post. Ingenting skrivs över. | | Tidredovisning | ✅ Kategorier (aktiv felsökning, väntetid, provkörning …) via kategoribyten i loggen; paus räknas inte i total tid. Inaktivitetsfråga efter 20 min utan händelser. | | Dokumentation | ✅ Observationer, mätvärden, foton (nedskalade), **video med ljud** (E3-evidens för det som låter eller rör sig — kort klipp med obligatorisk beskrivning, hård storleksgräns, originalfilen bevaras och visas i logg, rapport och Live Share), kommentarer och hypoteser. Hypoteser märks alltid som ej verifierade och kan aldrig loggas som konstaterade fel. **Avslutet signeras automatiskt** av teknikern (”Felsökning avslutad — signerad av …”), redovisat i kvalitetsgrinden. | @@ -40,7 +40,7 @@ Demomanus för visning: [DEMO.md](DEMO.md). Knappen **Skapa demoärende** på st | Export | ✅ Versionsmärkt JSON-export (version = antal händelser vid exporttillfället, med användare och tidpunkt); exporten loggas själv som händelse. PDF via utskrift. CSV och API i backend-fasen. | | Multi-tenant & roller | ✅ I självhostat läge: registrering skapar organisation + systemadministratör; admin hanterar användare (tekniker/arbetsledare/admin) via UI; all ärendedata organisationsisolerad i API:t; roll + organisation i JWT:n. **Arbetsledarvy** (`/felsokning/oversikt`): organisationens alla ärenden med status, deltagande tekniker och statistik (pågående/avslutade/ledtid) — härlett ur händelseloggen; ärenden kan hämtas till enheten med konfliktfri flätning. **Felorsaksstatistik** (flottdata): orsakskategorierna ur alla felorsaksanalyser aggregeras per organisation och visas som stapelöversikt i arbetsledarvyn. **Ansvarig tekniker** per ärende härleds ur loggen (skapare → överlämning → omfördelning) och arbetsledaren kan omfördela pågående ärenden — loggat som den organisationsinterna händelsen `ansvarig_satt`, aldrig synlig i kund-/partnerdelningar. Integrationstestat mot riktig Postgres (isolering, rollstyrning, append-only, översiktens behörighet och härledningar). | | Backend & synk | ✅ Databas-migration (`supabase/migrations/20260802230000_guidad_felsokning.sql`): ärenden + händelser med RLS, append-only även i databasen (inga update/delete-rättigheter). Synklager i klienten: konfliktfri ihopflätning av händelser per id (testad), push av lokala + pull av kollegors händelser var 15:e sekund. Utan inloggning arbetar appen i lokalt läge; status visas i ärendehuvudet. | -| Metodiker | ✅ Tre: vibration, elsystem/strömförsörjning (relä-exemplet ur visionen) och generisk — vald automatiskt utifrån felbeskrivningen. | +| Metodiker | ✅ **Sexton**, i `src/felsokning/metodiker.ts`: vibration, bromsar, styrning/fjädring, elsystem (relä-exemplet ur visionen), start & laddning, motorgång, kylsystem, drivlina, avgas & emission, klimat, högvolt (elbil/hybrid), felkoder & kommunikation, läckage, missljud, förarassistans (ADAS) — plus generisk. Metodiken väljs på nyckelord ur felbeskrivningen, poängsatt så att det mest specifika ordet vinner (`traktionsbatteri` slår `batteri`); träffar inget väljs generisk, som är strukturellt komplett — ett ärligt "vi vet inte var vi ska börja" i stället för en gissning, varefter orkesterns klassificerare (Haiku 4.5) får försöka. Tre regler är låsta av test: varje kontroll har ett minimikrav, varje metodik börjar med att verifiera symptomet, och där arbetet kan skada någon ligger säkerhetssteget först — högvoltsmetodiken kan inte påbörjas utan dokumenterad spänningsfrihet, urtagen servicebrytare och skyddsutrustning. | | Live Share | ✅ **Delningsgränsen är en tillåtelselista**: händelsetyper räknas upp per nivå (kund/partner/intern) i stället för att nekas en och en, så en ny händelsetyp är intern tills någon aktivt släpper fram den — låst av ett test som kräver att varje typ i domänmodellen är klassificerad. Skrivskyddad livevy per ärende (`/felsokning/dela/:id`): status ✔/🔄/⏳, bilder, mätvärdestabell, tidslinje, rekommenderat nästa steg. Uppdateras automatiskt, interna poster filtreras bort. Publik delningssida (`/felsokning/delad/:kod`) läser via `hamta_delat_arende` utan inloggning och pollar för liveuppdatering; "Kopiera delningslänk" finns i rapportfliken. **Behörighetsnivåer**: återkallbara delningslänkar per nivå — kund (det kunddelbara), extern partner (även hypoteser, märkta ej verifierade), intern (full insyn) — med serverstyrd filtrering, hanterade från rapportfliken i självhostat läge. | | Dashboard | ✅ Enligt direktivet: räknare och filter för Alla/Pågående/Klara plus Starta nytt ärende. | | Ärendestart via arbetsorder | ✅ Primärvägen när ett ärende startas: fota arbetsorderns framsida — orkesterns dokumenttolkning (Claude Sonnet 5, vision) läser kund-, fordons- och verkstadsuppgifter oavsett layout och sätter konfidens per fält. 🟢 ≥95 % godkänns automatiskt, 🟡 80–95 % markeras för genomläsning, 🔴 <80 % kräver aktiv bekräftelse — teknikern granskar bara osäkra fält. Visuell granskning med dokumentet bredvid fälten (klick markerar ungefärlig position), sedan skapas hela ärendet med ett tryck. Tolkningen loggas som organisationsintern händelse (`arbetsorder_skannad`) och delas aldrig i kund-/partnervyer. Manuell inmatning finns kvar som andrahandsväg; i lokalt läge visas en tydligt märkt demo-tolkning. Inloggade användare tillfrågas aldrig om namn — kontot vet redan. | @@ -66,7 +66,7 @@ Demomanus för visning: [DEMO.md](DEMO.md). Knappen **Skapa demoärende** på st - **Händelseloggen är enda sanningskällan.** `src/felsokning/domain.ts` definierar händelsetyperna; poster läggs endast till. - **Alla vyer är projektioner.** `src/felsokning/projektioner.ts` — brief, tidsfördelning, överlämningstext och kundrapport är rena funktioner av loggen och kan alltid regenereras. Testerna i `src/felsokning/__tests__/` låser detta. -- **Metodikmotorn är deterministisk.** `src/felsokning/metodik.ts` — nästa steg härleds ur vad som redan dokumenterats. Det är här den framtida AI:n ansluter, utan att logg eller projektioner ändras. +- **Metodikmotorn är deterministisk.** `src/felsokning/metodik.ts` är motorn (typer, val av metodik, härledning av nästa steg); `src/felsokning/metodiker.ts` är innehållet. Nästa steg härleds ur vad som redan dokumenterats. Biblioteket kan växa utan att motorn ändras, och orkesterns metodikkatalog jämförs mot klientens i test så att listorna inte kan glida isär. - **Ingen slutsats utan evidens.** `src/felsokning/ecm.ts` — regelmotorn (ECM) validerar varje påstående mot händelseloggen: fullbordansregler, evidensnivåer och kvalitetsgrind. Kameran är integrationslagret (visual-first) — det som syns på en skärm eller ett instrument fotograferas och tolkas i stället för att integreras. - **Terminologi.** Produkten beskrivs som ett evidensbaserat diagnossystem/intelligent beslutsstöd — i UI och kundkommunikation används *systemet/analysen/bedömningen/beslutsstödet*, aldrig "AI" om det inte är tekniskt nödvändigt. - **Egen ikongrafik.** `src/felsokning/ikoner.tsx` — enkla industriella linjeikoner (SVG, stroke i aktuell textfärg) i stället för emojis; tillförlitlighets- och statusnivåer visas som färgpunkter. diff --git a/felsokning/services/ai-orkester/server.mjs b/felsokning/services/ai-orkester/server.mjs index 9281a40..4fcc398 100644 --- a/felsokning/services/ai-orkester/server.mjs +++ b/felsokning/services/ai-orkester/server.mjs @@ -58,10 +58,33 @@ const SVARS_SCHEMA = { additionalProperties: false, }; +// Metodikkatalogen. Måste vara identisk med app/src/felsokning/metodiker.ts — +// testet "orkestern känner till exakt samma metodiker som klienten" faller +// om listorna glider isär. Beskrivningen är klassificerarens enda underlag, +// så den ska säga vad symptomet är, inte vad felet tros vara. +const METODIK_KATALOG = [ + ["vibration", "vibrationer, skakningar eller obalans under körning"], + ["bromsar", "bromsverkan, bromspedal, skevhet, gnissel vid inbromsning, ABS"], + ["styrning_fjadring", "styrning, ratt, glapp, stötdämpare, hjulinställning, fordonet drar åt sidan"], + ["elsystem", "elektriska fel — reläer, säkringar, spänning, belysning, kablage, kontaktdon"], + ["start_laddning", "fordonet startar inte, startmotor, generator, batteriet laddar ur"], + ["motor_drift", "motorgång och effekt — rycker, misständer, ojämn tomgång, tappar kraft"], + ["kylsystem", "överhettning, kylvätska, termostat, kylare, värme i kupén"], + ["drivlina", "växellåda, koppling, automatlåda, drivknutar, kardan, differential"], + ["avgas_emission", "avgassystem och emissioner — partikelfilter, AdBlue, katalysator, lambda, EGR"], + ["klimat", "klimatanläggning — kyler inte, kompressor, köldmedium, imma, lukt i kupén"], + ["hogvolt", "högvoltsystem i elbil eller hybrid — traktionsbatteri, laddning, räckvidd"], + ["diagnos_natverk", "felkoder, kommunikationsfel, ingen kontakt med styrenhet, CAN/buss"], + ["lackage", "läckage — olja, vätska, vatten som tar sig in i fordonet"], + ["missljud", "missljud — knack, gnissel, vinande, brummande, skrammel"], + ["adas", "förarassistans och kalibrering — kamera, radar, filhållning, parkeringssensorer"], + ["generisk", "allt annat, eller när det är oklart"], +]; + const METODIK_SCHEMA = { type: "object", properties: { - metodikId: { type: "string", enum: ["vibration", "elsystem", "generisk"] }, + metodikId: { type: "string", enum: METODIK_KATALOG.map(([id]) => id) }, }, required: ["metodikId"], additionalProperties: false, @@ -180,10 +203,10 @@ const ORKESTER = { modell: "claude-haiku-4-5", maxTokens: 256, system: `Du klassificerar en felbeskrivning från en verkstad till EN felsökningsmetodik: -- "vibration": vibrationer, skakningar eller obalans under körning. -- "elsystem": elektriska fel — reläer, säkringar, spänning, batteri, belysning, givare, strömförsörjning. -- "generisk": allt annat, eller när det är oklart. -Gissa inte: välj "generisk" om beskrivningen inte tydligt hör till en specifik metodik.`, +${METODIK_KATALOG.map(([id, beskrivning]) => `- "${id}": ${beskrivning}.`).join("\n")} + +Valet är en frågeordning, inte en diagnos — du avgör var teknikern ska börja leta, inte vad som är fel. +Gissa inte: välj "generisk" om beskrivningen inte tydligt hör till en specifik metodik. "generisk" är ett fullgott svar och alltid bättre än en gissning.`, schema: METODIK_SCHEMA, }, // Ärendestart: teknikern fotograferar arbetsordern; vi läser dokumentet diff --git a/felsokning/supabase/functions/felsokning-ai/index.ts b/felsokning/supabase/functions/felsokning-ai/index.ts index cfc28af..e5826b2 100644 --- a/felsokning/supabase/functions/felsokning-ai/index.ts +++ b/felsokning/supabase/functions/felsokning-ai/index.ts @@ -56,10 +56,33 @@ const SVARS_SCHEMA = { additionalProperties: false, }; +// Metodikkatalogen. Måste vara identisk med app/src/felsokning/metodiker.ts — +// testet "orkestern känner till exakt samma metodiker som klienten" faller +// om listorna glider isär. Beskrivningen är klassificerarens enda underlag, +// så den ska säga vad symptomet är, inte vad felet tros vara. +const METODIK_KATALOG = [ + ["vibration", "vibrationer, skakningar eller obalans under körning"], + ["bromsar", "bromsverkan, bromspedal, skevhet, gnissel vid inbromsning, ABS"], + ["styrning_fjadring", "styrning, ratt, glapp, stötdämpare, hjulinställning, fordonet drar åt sidan"], + ["elsystem", "elektriska fel — reläer, säkringar, spänning, belysning, kablage, kontaktdon"], + ["start_laddning", "fordonet startar inte, startmotor, generator, batteriet laddar ur"], + ["motor_drift", "motorgång och effekt — rycker, misständer, ojämn tomgång, tappar kraft"], + ["kylsystem", "överhettning, kylvätska, termostat, kylare, värme i kupén"], + ["drivlina", "växellåda, koppling, automatlåda, drivknutar, kardan, differential"], + ["avgas_emission", "avgassystem och emissioner — partikelfilter, AdBlue, katalysator, lambda, EGR"], + ["klimat", "klimatanläggning — kyler inte, kompressor, köldmedium, imma, lukt i kupén"], + ["hogvolt", "högvoltsystem i elbil eller hybrid — traktionsbatteri, laddning, räckvidd"], + ["diagnos_natverk", "felkoder, kommunikationsfel, ingen kontakt med styrenhet, CAN/buss"], + ["lackage", "läckage — olja, vätska, vatten som tar sig in i fordonet"], + ["missljud", "missljud — knack, gnissel, vinande, brummande, skrammel"], + ["adas", "förarassistans och kalibrering — kamera, radar, filhållning, parkeringssensorer"], + ["generisk", "allt annat, eller när det är oklart"], +]; + const METODIK_SCHEMA = { type: "object", properties: { - metodikId: { type: "string", enum: ["vibration", "elsystem", "generisk"] }, + metodikId: { type: "string", enum: METODIK_KATALOG.map(([id]) => id) }, }, required: ["metodikId"], additionalProperties: false, @@ -203,10 +226,10 @@ Uppgift: En tekniker lämnar över ärendet. Komplettera överlämningen med det modell: "claude-haiku-4-5", maxTokens: 256, system: `Du klassificerar en felbeskrivning från en verkstad till EN felsökningsmetodik: -- "vibration": vibrationer, skakningar eller obalans under körning. -- "elsystem": elektriska fel — reläer, säkringar, spänning, batteri, belysning, givare, strömförsörjning. -- "generisk": allt annat, eller när det är oklart. -Gissa inte: välj "generisk" om beskrivningen inte tydligt hör till en specifik metodik.`, +${METODIK_KATALOG.map(([id, beskrivning]) => `- "${id}": ${beskrivning}.`).join("\n")} + +Valet är en frågeordning, inte en diagnos — du avgör var teknikern ska börja leta, inte vad som är fel. +Gissa inte: välj "generisk" om beskrivningen inte tydligt hör till en specifik metodik. "generisk" är ett fullgott svar och alltid bättre än en gissning.`, schema: METODIK_SCHEMA, }, // Ärendestart: teknikern fotograferar arbetsordern; vi läser dokumentet