Commit Graph

18 Commits

Author SHA1 Message Date
Claude b147694e31 Härdning av hela TÜV-revisionen
Tio av tolv fynd stängda, två reducerade med skälen utskrivna. Varje
stängning prövas av integrationssviten mot riktig Postgres — 144
kontroller, upp från 100.

T-1  Händelsenyckeln är nu (arende_id, id). Det finns inget delat
     namnrum kvar att ockupera, så attacken saknar yta i stället för att
     vara mildrad. Inom ett ärende bedöms en kollision på klientens
     avtryck — en hash av det kanoniserade innehåll klienten skickade,
     taget före serverns egna fält och före krypteringen, eftersom
     varken raden eller nyttolasten går att jämföra. Identiskt innehåll
     är fortfarande idempotent; samma id med annat innehåll ger 409 och
     skriver ingenting alls, inte heller resten av satsen. Samma attack
     en nivå upp — ärende-id är lika förutsägbart — stängs separat: ett
     id som ägs av en annan organisation ger 409 i stället för att tyst
     låta bli, vilket tidigare lämnade offrets ärende oskapat och varje
     senare synk svarande 404.

T-2  Mätdonet slås upp i registret. Beteckning och kalibrering HÄRLEDS
     därifrån och skriver över det klienten skickade. Okänt mätdon ger
     400. Utgånget avvisas inte — mätningen gjordes — men registrets
     datum följer med, så graderingen faller på registrets uppgift. Ett
     mätvärde utan mätdon får sina påstådda uppgifter borttagna.

T-3  Reducerad, inte stängd. Personnycklarna kuverteras under en
     huvudnyckel utanför databasen. En återställd dump ger nycklar som
     inte öppnas — verifierat genom att starta om utan huvudnyckeln. Vad
     som återstår står utskrivet: en backup tagen FÖRE en radering, plus
     huvudnyckeln, återställer fortfarande uppgifterna.

Därtill: gallringen verkställs nu av ett eget jobb och grupperar på det
blindade fordonsindexet så att en delad nyckel inte gallras för tidigt
(T-4) · AI-avlästa mätvärden bär härkomst (T-5) · bcrypt kostnad 12
(T-6) · åtkomstloggen och raderingsregistret är append-only, med en
smalare regel för personnycklarna som måste kunna förstöras (T-7) ·
åtkomstloggen dokumenterad (T-8) · ett externt regelpaket utan signatur
spärrar avslut (T-9) · CORS faller inte längre öppet (T-10) · exp krävs
i token (T-11) · react-router 7 (T-12, med den kvarvarande avvikelsen
motiverad).

Den motspelande hyresgästen som revisionen efterlyste finns nu som
testform och körs i CI.

---- Vad härdningen själv avslöjade -----------------------------------

Två av rättelserna var kortvarigt fel på samma sätt som fynden, och
bägge fångades bara av att jag försökte bevisa dem:

  T-7-testet var grönt mot en TOM tabell. En radnivåtrigger har inga
  rader att fyra på, så delete lyckades och kontrollen mätte ingenting.

  T-6-testet påstod anropet, inte kostnaden. toContain("gen_salt('bf')")
  hade accepterat kostnad 6 för evigt — och gjorde det, så länge det
  fanns.

Bägge är mönstret revisionen namngav: en kontroll som är riktig i sina
egna termer och oprövad vid sin gräns. Det gäller tester lika mycket som
kod.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 13:05:16 +00:00
Claude 0833a573e0 TÜV-revision: bred granskning av hela systemet
Frågan var inte om mekanismerna fungerar — de gör det — utan om ett
underlag från systemet skulle överleva en granskning. Svaret är nej, av
tre skäl, och inget av dem är ett fel i det som de två föregående
revisionerna härdade.

T-1  En organisation kan tyst hindra en annan från att skriva historik.
     Händelse-id sätts av klienten och är förutsägbart, primärnyckeln är
     global, och insert sker med `on conflict do nothing`. Org B kan
     ockupera id på SITT EGET ärende som org A senare kommer att använda.
     Reproducerat: org A:s felorsak försvann, servern svarade 200.
     Append-only skyddar det som skrivs. Ingenting skyddar det som
     hindras från att skrivas.

T-2  Mätkedjan är självpåstådd. Mätdonsregistret finns, är välbyggt och
     konsulteras aldrig. Reproducerat: en organisation utan ett enda
     registrerat mätdon skickar matdonId "finns-inte-i-registret" och
     kalibrering 2099-12-31 — lagras oprövat, och evidensen graderas E4.

T-3  Raderingen är inte varaktig. Krypto-shreddingens nyckel ligger i
     samma databas som chiffertexten, och återställningstestet slår
     uttryckligen fast att nycklarna följer med en återställning. Testet
     har rätt för katastrofåterställning — det är samma faktum läst åt
     andra hållet som bryter raderingslöftet.

Därtill fyra allvarliga: gallringsdatumet skrivs men läses aldrig av
någon, AI-avlästa mätvärden saknar härkomst, lösenordshashen är bcrypt
kostnad 6 (pgcrypto-standard, verifierat), och åtkomstloggen och
raderingsregistret är de enda underlagen UTAN append-only-skydd.

Gemensamt för de tre kritiska: var och en är osynlig för en grön svit,
och av tre olika skäl. Det är revisionens egentliga utfall, och därför
föreslås en motspelande hyresgäst som testform.

Varje fynd reproducerat mot riktig Postgres och en riktig serverprocess.
Inget rapporteras som inte gick att återskapa.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 12:27:50 +00:00
Claude 3b83fc94e9 Portalen är stängd på riktigt — m-9 stängd
Anmärkningen var att en inloggning som SER ut att autentisera ger
portalen bakom den en auktoritet den inte har. Rättelsen är inte att ta
bort skylten utan att göra spärren verklig där det finns något att
spärra mot.

Med plattformen konfigurerad autentiserar inloggningen mot
/api/auth/logga-in, varje portalväg går genom Portalvakt, och
fakturavyn läser organisationens egna fakturor ur GET /api/fakturor.
Misslyckas hämtningen visas felet — inte exemplet: data som ser äkta ut
men inte är det är värre än ett synligt fel. Utloggningen finns i
portalhuvudet och rensar sessionen på riktigt.

Utan konfigurerad plattform finns ingen session att kräva, och
demonstrationsmärkningen visas exakt i det läget.

---- Varför garantin inte är ett källkodstest ------------------------

Sviten kan bara läsa koden och se att vakten är inkopplad. Släpper den
igenom ändå — fel villkor, fel ordning, ett <Navigate> som aldrig hinner
rendera — ser koden likadan ut. Och en spärr som inte spärrar är precis
det m-9 handlade om.

e2e/portalsparr.mjs bygger därför med plattformen konfigurerad och
tittar var besökaren faktiskt hamnar: fem vägar spärrade utan session,
fem öppna med, utloggning som rensar token och stänger portalen igen.
Mutationstestad — att plocka bort vakten från en enda route fäller den.

Bevisad: 374 enhetstester, typkontroll, genomgången 4/4 ärenden,
portalspärren 14/14.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 12:08:18 +00:00
Claude d1b361573e Faktureringens serverdel — och två fel den grävde fram
Fakturering fanns som modell, vy och tester men aldrig som något en
server kunde utfärda. Nu finns tabellerna, vägarna och gränsen mellan
kund och utfärdare.

Beloppet tas aldrig emot. Det härleds ur organisationens faktiska
tillstånd — de konton som verkligen kan logga in, de moduler som
verkligen är påslagna — och ett anrop som ändå skickar rader eller
totalt avvisas med 400 i stället för att tigas ihjäl. Samma hållning som
mot okända fält i händelseschemat.

Fakturaraden är oföränderlig, skyddad av samma trigger som loggen. Det
får en följd som är lätt att missa: "betald" kan då inte vara en kolumn
som uppdateras. Betalningen är en egen händelse och statusen en
projektion av händelserna. En felaktig faktura rättas inte heller — den
bemöts av en kreditfaktura med omvänt tecken och ett granskbart skäl.

Utfärdaren är inte en användare. Ingen av rollerna i en verkstad är
motpart i avtalet, så en kunds administratör kan varken utfärda sin egen
faktura eller bokföra den som betald; utfärdandet kräver en egen nyckel,
och utan den i miljön utfärdas ingenting alls. Nummerserien är utan
luckor — en sequence hade varit billigare men lämnar hål vid rollback,
och ett underlag med hål i är en lista.

---- Vad som föll ut när sviten faktiskt kördes ------------------------

integrationstest.sh fanns men låg utanför CI, och den föll på andra
raden — i kod som inte hade med fakturering att göra:

C-7  Append-only-triggern på felsokning_arenden förbjöd ALL update. Två
     av radens kolumner är härledda efteråt: gallringsdatumet vid avslut
     och det blindade fordonsindexet. Alltså föll varje avslut med 500,
     efter att kvalitetsgrinden redan godkänt ärendet. Skyddet är nu
     kolumnvis: identitet och ursprung är fortfarande låsta, radering
     fortfarande omöjlig, men de fält systemet självt härleder får
     skrivas.

C-8  Fordonshistoriken sökte i klartext efter en identifierare som
     krypteras i vila. Jämförelsen kunde aldrig träffa: historiken
     svarade tomt på varje fordon, med 200. Det blindade indexet fanns
     just för den frågan och var aldrig inkopplat.

Bägge ligger i backenden till produktens centrala löfte — att ett
avslutat ärende är ett varaktigt underlag — och ingen av dem kunde synas
i en grön enhetssvit, eftersom ingen av dem kan falla utan en databas.
Sviten är därför ett eget CI-jobb nu.

Bevisad: 364 enhetstester, 100+ integrationskontroller mot riktig
Postgres, genomgången 4/4 ärenden. Spärren mot angivet belopp
mutationstestad — borttagen ger den 201 i stället för 400.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 10:54:31 +00:00
Claude 86d553b639 Kör ALVA:s tester i CI, och genomgången som incheckat test
CI körde `npm test` i roten, som delegerar till workspaces. Listan är
apps/mobile, services/api och infra — felsokning/app står inte där.
Pipelinen körde alltså 30 tester från en orelaterad tjänst och inte ett
enda av ALVA:s 311. Varken lint eller typkontroll nådde produkten heller.

Det är inte att testerna föll. Det är att ingenting upprätthöll dem.
Varje garanti som de två revisionerna skrivit som "låst av ett test" —
härkomsten, kvalitetsgrinden, raderingen, mätdonsspårbarheten,
högvoltsspärren, det stängda schemat, driftskydden mellan klient och
grind — låstes av tester som ingen pipeline körde. De höll därför att en
person körde dem för hand före varje commit. Det är en person, inte en
spärr.

Två nya jobb. `alva` kör produktens lint, typkontroll och hela sviten mot
sin egen lockfil. `genomgang` installerar Chromium och kör fyra ärenden
genom det byggda gränssnittet.

Genomgången kontrollerar tre saker: att varje ärende når avslutat läge,
att varje händelse klienten faktiskt producerar passerar det stängda
schemat, och att interaktionerna per ärende håller sig under 90. Bägge
felvägarna är provade, inte antagna — sänkt budget fäller tre fall, och
ett schemafilter som avvisar allt fäller fyra. En kontroll som inte kan
falla är dekoration.

Skriptet bygger appen själv med de två miljövariabler bygget kräver.
Lämnas det åt den som startar kommandot testar genomgången tyst en annan
applikation: utan hash-routing matchar ingen route, och utan
platshållare för den gamla butiksklienten kastar den innan routern
monteras så att sidan blir tom.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 19:41:15 +00:00
Claude 31727a4ea0 Härda enligt revision 2: stäng schemat, ta bort dubbelregeln
C-5. granskaHändelse itererade schemats nycklar och aldrig händelsens,
så okända fält accepterades och sparades ordagrant. Två garantier vilade
på motsatsen: krypto-shreddingen skyddar en fast lista av fältnamn, så
personuppgifter på en vanlig observation krypterades aldrig och överlevde
raderingen — och delningsfiltret är typnivå, så samma fält gick ut i
kundens delningslänk. Schemat är nu stängt, med varje valfritt fält
deklarerat. Det gäller även `kalla`: protokollinläsningen fungerade bara
därför att schemat var öppet. Avslaget är hårt, inte en tyst strykning.
Verifierat mot riktig trafik — samtliga händelser som klienten faktiskt
producerar passerar.

M-7. Klienten upprepar inte längre grindens regel utan anropar grinda()
och visar dess egna hinder. Villkoret hade glidit isär två gånger utan
att något test märkte det.

Det avslöjade omedelbart ett verkligt fel i grinden: den krävde
textresultat även på kontroller vars krav är foto — trots att
gränssnittet märker fältet "Observation (valfritt)". Servern hade alltså
nekat avslut på nästan varje riktigt ärende, och det syntes inte så länge
klienten hade ett eget och mildare villkor. Evidens graderas nu efter
kontrollens eget krav.

M-8. Protokollinläsningen svarar med utfall per händelse i stället för en
siffra, 207 vid delvis lyckad inläsning, innehållshärledda id:n i stället
för klockan, och en transaktion runt hela importen.

M-9. En genererad webhookhemlighet lämnas ut en gång vid skapandet.

m-8. Profilens vägslagning begränsas till egna egenskaper.
m-10. Ett mätvärde som kommer ur en kontroll redovisas en gång.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 18:19:11 +00:00
Claude e6b57d59e5 Leverantörsrevision 2 av ALVA
Granskar det som byggts sedan revision 1 stängdes: ALVA-metoden och
designsystemet, slutsatsen (ALVA-RULE-200), driftmåtten (ALVA-REP-0100),
den härledda sammanfattningen (ALVA-PROC-0030) och integrationsytan
(ALVA-SPEC-020/021).

Ett kritiskt fynd. Händelseschemat är öppet — granskaHändelse itererar
schemats nycklar, aldrig händelsens — så okända fält accepteras och
sparas ordagrant. Två garantier som revision 1 stängde vilar på
motsatsen: personuppgifter på en vanlig observation krypteras aldrig och
överlever därför raderingen, och delningsfiltret är typnivå, inte
fältnivå, så fälten når kundens delningslänk. Reproducerat mot de delade
modulerna, inte påstått. Komplikationen är att öppenheten är bärande:
protokollinläsningen hänger `kalla` på varje händelse, och `kalla` finns
inte i schemat.

Tre allvarliga. Klientens avslutsvillkor har glidit från grinden två
gånger sedan C-2 stängdes, och ingen av gångerna fångades av 293 tester
— bara av att köra tio ärenden hela vägen. Protokollinläsningen tappar
händelser tyst på tre sätt. Genererade webhookhemligheter går aldrig att
få ut, så leveranssignaturen kan aldrig verifieras.

Tre mindre, varav ett är mitt eget från i dag: ett mätvärde som kommer
ur en kontroll redovisas två gånger i rapporten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 18:04:14 +00:00
Claude 03fbea8fac Revisionen: m-4 och m-6 — de två som bara går att stänga delvis
m-6 · Tillgänglighetstester med axe på verkstadsgränssnittets
grundkomponenter: knapp, textfält, panel och bild. Gränssnittet var
genomtänkt för handskar, buller och solljus men obevisat — ingenting
kontrollerade att en knapp har ett tillgängligt namn eller att ett
formulärfält har en etikett.

Att bilder bär alternativtext är i den här produkten inte bara ett
tillgänglighetskrav: bilden *är* bevisningen, och beskrivningen är det
som säger vad den visar.

Ungefär en tredjedel av WCAG går att kontrollera maskinellt. Testet
säger det rakt ut, och den manuella granskningen står kvar som öppen —
automatik hittar inte om ett gränssnitt är användbart, bara om det är
felformat.

m-4 · Paritetstestet mellan orkesterkopiorna jämför nu innehåll i
stället för att kontrollera att strängar förekommer: grundreglerna ord
för ord, metodikkatalogens id i ordning, och modellvalet per uppgift.
Ett substrängtest hade inte fångat att en grundregel ändrats i ena
kopian.

Den riktiga åtgärden är att avveckla Supabase-vägen. Det är ett
driftbeslut, inte en kodändring, och står kvar som öppet.

Revisionsdokumentet har fått en avdelning med utfall per fynd, så att en
omgranskning kan verifiera i stället för att lita på ordet. Två punkter
är ärligt öppna och ingen av dem är kod: personuppgiftsbiträdesavtalet
med konsekvensbedömning, och avvecklingen av den äldre orkestern.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 13:48:06 +00:00
Claude cdb3320c4a Kvalitetsrevision ur en OEM-kunds perspektiv
En genomgång av koden — inte av dokumentationens påståenden — med den
granskning en fordonstillverkares leverantörskvalitet skulle göra.
Dokumentet säger uttryckligen att det är en intern övning med Volkswagen
AG som referenskund, inte en revision utförd av eller på uppdrag av dem.

Fyra kritiska fynd, varav två underminerar produktens kärnlöfte:

Servern tar emot anvandare och tidpunkt från klienten och kontrollerar
bara att de är strängar respektive sanningsvärda. JWT:n bär redan den
verifierade identiteten men används inte på den vägen. En append-only
logg vars författare och tidpunkt sätts av anroparen är inte en
revisionskedja.

Kvalitetsgrinden finns bara i webbläsaren. Ett ärende kan avslutas utan
evidens genom ett anrop till API:t, och rapporten presenterar det som
komplett. Dokumentationen säger att systemet aldrig kan skriva en
slutsats ECM inte godkänt; det stämmer inte vid API-gränsen.

De två övriga är rättsliga: append-only utan raderingsväg går inte att
förena med dataskyddsförordningens artikel 17, och överföringen av
kunduppgifter och VIN till modell-API:t saknar dokumenterad grund.

Sex allvarliga fynd, bland dem att mätvärden rankas som hög evidens utan
att bära vilket instrument som mätte eller om det var kalibrerat, och
att högvoltsteget går att svara nej på och ändå fortsätta.

Dokumentet listar också det som håller — och varför det bör skyddas i
åtgärdsarbetet. En revision som bara räknar fel ger en falsk bild.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 22:13:09 +00:00
Claude 031d6d5a3d All produktdokumentation på engelska som källa
De återstående dokumenten — VISION, MVP, DEMO, DRIFT och MASTER-PROMPT —
får engelska versioner, och de svenska blir översättningar med samma
notis som systembeskrivningen redan hade. DRIFT.md heter nu
OPERATIONS.md; ett svenskt filnamn på ett engelskt dokument hade varit
inkonsekvent.

Dokumentationen är därmed 33 filer: sexton dokument med engelska som
källa, sexton svenska syskon, och systembeskrivningen dessutom på tyska,
danska och norska.

Två fel hittades under översättningen, båda rättade i bägge språken:

DRIFT.md pekade ut .github/workflows/ci.yml som Guidad Felsöknings CI
och sa tre rader längre ned att samma fil tillhör Semantika och inte
rörs. Det stämde innan CI flyttades till egen Gitea; rätt fil är
.gitea/workflows/felsokning.yml.

MVP.md kallade styrdokumentet Master Prompt v1.0 men länkade till v2.0.

Att översätta ett dokument är den grundligaste läsning det får. Båda
felen hade överlevt flera genomgångar av samma text på svenska.

Kodidentifierare, miljövariabler, sökvägar och UI-etiketter står
oöversatta i de engelska versionerna. Att skriva "Create demo case" i
demomanuset hade gjort manuset obrukbart — knappen heter "Skapa
demoärende".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 20:25:45 +00:00
Claude 86efbaaca5 Moduldokumenten på engelska som källa
De åtta moduldokumenten och exempelflödet får engelska versioner.
Kataloger och filnamn följer med: moduler/ → modules/, exempel/ →
examples/, och de svenska filnamnen ersätts av engelska. Ett engelskt
dokument i moduler/arendebrief.md hade varit inkonsekvent.

Bytet gjordes med git mv så historiken följer med, och interna länkar i
de svenska versionerna pekar nu på svenska syskon i stället för på
filnamn som inte längre finns.

Kodidentifierare och JSON-exempel står oöversatta även i de engelska
versionerna — falt, hemlig, uppslag och svarsfalt är fältnamn i
integrationer.json, inte prosa.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 20:19:47 +00:00
Claude 9035dfebc9 Engelska är nu systembeskrivningens källa
Filerna byter namn så att basnamnet är den engelska versionen:
SYSTEM-DESCRIPTION.md är dokumentet, övriga språk är suffixade. Bytet
gjordes med git mv så historiken följer med.

Auktoritetskedjan vänds: engelskan säger att den är gällande version och
räknar upp översättningarna; svenska, tyska, danska och norska pekar nu
på engelskan i stället för på svenskan. Två dokument som båda påstår sig
gälla blir i praktiken två sanningar, så exakt ett måste vara källan.

Svenskan blir därmed en översättning bland de andra. Den behåller en
egen not: kodidentifierarna är oöversatta även där, men där syns det
inte eftersom koden är svensk — värt att veta för den som jämför med en
annan språkversion.

Engelskans ingress säger uttryckligen att dokumentets språk inte ändrar
vad koden heter. Det är den missuppfattning som annars uppstår när ett
engelskt dokument beskriver ett svenskt kodbas: läsaren börjar söka på
översatta namn och hittar ingenting.

Alla 48 numrerade avsnitt finns kvar i varje version, verifierat
maskinellt, och inga länkar pekar på de gamla filnamnen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 15:15:18 +00:00
Claude 3c5752898b Systembeskrivningen på engelska, tyska, danska och norska
Fyra översättningar av hela dokumentet — inte sammanfattningar. Alla 48
numrerade avsnitt finns i varje språkversion, verifierat maskinellt.

Kodidentifierare är inte översatta. Händelsetyper, funktionsnamn,
fältnamn, filsökvägar och konfigurationsnycklar är svenska i själva
koden; ett dokument som döper om dem till engelska blir oanvändbart mot
repot. De står därför ordagrant, med förklaring på målspråket där
betydelsen inte är uppenbar. Ett skript kontrollerar att 38 sådana
identifierare överlevde översättningen i alla fem filer.

Varje översättning säger i ingressen att den svenska versionen är
källan och gäller vid avvikelse. Två dokument som påstår sig vara lika
auktoritativa blir i praktiken två sanningar.

Avsnittet om nyckelordsstammar har fått ett tillägg per språk: att
"partikelfilter" inte matchar "partikelfiltret" är en egenskap hos
svensk böjning, och tyska sammansättningar respektive dansk och norsk
bestämd form ger samma klass av problem. Ett lokaliserat nyckelordsset
måste valideras mot samma test, inte översättas ord för ord.

Ordlistan går från svenska till målspråket och är därmed mer användbar
i översättning än i originalet — den blir nyckeln mellan koden och
läsaren.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 15:12:28 +00:00
Claude e90cbf99e9 Fullständig systembeskrivning i ett dokument
Ett självständigt referensdokument som beskriver hela systemet utan att
repot behöver vara tillgängligt: principer, domänmodell, metodikmotor,
ECM, tjänster, säkerhet, infrastruktur, testning och repostruktur.

Innehållet är hämtat ur koden, inte ur planer. Där något inte finns står
det uttryckligen — inklusive ett avsnitt om kända begränsningar och
öppna punkter, eftersom ett dokument som bara beskriver det som fungerar
är svårare att resonera kring än ett som säger var kanterna går.

Ett eget avsnitt samlar designbesluten med sina motiv. Motivet är oftare
det som behövs vid en diskussion än beslutet i sig.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 14:25:01 +00:00
Claude 1bb40319d8 Metodikbiblioteket: 16 metodiker som täcker fordonets system
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 14:17:38 +00:00
Claude 69a519be75 Observation: se var tiden går, utan ett enda nytt beroende
CloudWatch gav loggar och mätvärden men svarade inte på frågan man
faktiskt har när något är långsamt: var tog tiden vägen.

Tjänsterna har medvetet nästan inga beroenden — plattformen har
pg-drivrutinen, orkestern har Claude-klienten. Att dra in ett
OpenTelemetry-SDK med trettio paket för att mäta fyra saker vore fel
avvägning. I stället två standarder som båda bara är text på stdout:

W3C Trace Context. Klienten startar spåret och traceparent följer med
genom plattformen till orkestern, så en teknikers handling går att följa
hela vägen till modellsvaret i stället för att bli två orelaterade spår.

CloudWatch EMF. Strukturerad JSON som CloudWatch själv extraherar
mätvärden ur — ingen agent, ingen SDK, inget som kan sluta fungera tyst.

Varje anrop ger en loggrad med nedbrytning av tiden per del: databasen,
modellanropet, objektlagringen, kundens leverantör. Det svarar direkt på
om ett långsamt ärende beror på S3 eller på Opus-granskningen, i stället
för att någon ska korrelera fem loggrader.

Vägen normaliseras innan den blir dimension, och organisation, ärende-id
och spår-id blir aldrig dimensioner — varje unik kombination är en egen
tidsserie som kostar. De ligger som vanliga fält, sökbara i Logs
Insights. Ett test låser det, eftersom det är precis den sortens sak som
smyger in senare.

Tre larm på det teknikern märker: svarstid p95 över tre sekunder
(medelvärdet döljer att var tjugonde tekniker väntar orimligt länge),
serverfel med spår-id i loggraden, och att modellen avböjer — det senare
tyder på att underlaget innehåller något oväntat, inte på ett driftfel.

Modulen är delad mellan tjänsterna i stället för duplicerad.
Byggkontexten flyttas därför till felsokning/services, och en symlänk gör
att testerna och integrationstestet kör mot samma fil som bilderna.

Verifierat: 106 vitest-tester (10 nya för spårning, EMF-format och att
dimensionerna hålls få), typkontroll, eslint på klient och tjänster,
rotens CI, terraform fmt och referenskontroll på båda lagren, samt
integrationstest mot riktig Postgres där spårraderna syns live.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 13:36:47 +00:00
Claude e94a97715a Kartan och driftshandboken stämmer med AWS igen
Infrastrukturen byttes ut men dokumentationen beskrev fortfarande den
gamla världen: kustomize, Argo CD, nginx-ingress, Postgres i klustret,
GHCR och tre databaslägen. En inaktuell karta är sämre än ingen — den
lurar den som litar på den.

Infrakartan är omritad mot AWS: tjänsterna och var de ligger, den egna
bygg- och driftkedjan från commit till kluster, gränserna inklusive
IRSA-bindningen, nätets tre lager och de fyra sakerna som återstår innan
skarp drift. Ärendets flöde är oförändrat — produkten är densamma, det är
grunden under den som bytts.

DRIFT.md beskriver nu de två Terraform-lagren och varför de är två,
Aurora med PITR i ett subnätlager utan routing ut, hemligheterna i
Secrets Manager där Terraform aldrig ser värdena, och CD-kedjan över
Gitea med egna runners. MVP.md har fått en rad för AWS-driften.

Kartan säger också rakt ut vad som INTE verifierats: terraform validate
kunde inte köras eftersom registry.terraform.io var blockerad, så det
som kontrollerats är formatering och statisk referenskontroll. Det står
först i listan över vad som ska göras innan skarp drift.

Verifierat: 96 vitest-tester, rotens lint och format:check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 13:11:58 +00:00
Claude 301c477e25 Merge main: Guidad Felsökning flyttar ur roten till felsokning/
Main är sedan den här grenen skapades en helt annan produkt — Semantika,
en mobilapp med egen CDK-infrastruktur. Den äger nu repots rot: en
npm-workspaces-monorepo med apps/mobile, services/api och infra.

För att båda ska rymmas i samma repo flyttar Guidad Felsökning in i en
egen katalog i stället för att göra anspråk på roten:

  felsokning/app        webbklienten (Vite, egen package.json och
                        eslint-/vitest-konfiguration)
  felsokning/services   plattformstjänsten och AI-orkestern
  felsokning/infra      Terraform och databasschemat
  felsokning/docs       vision, moduler, drift
  felsokning/supabase   edge-funktion och migrationer

Merge:n hade tagit bort 128 filer som Guidad Felsökning bygger på —
värdapplikationens komponenter, Supabase-klienten, tillgångar — eftersom
main raderat dem och den här grenen inte råkat ändra just dem. De är
återställda på sin nya plats. Utan dem gick varken bygget eller
testerna: ai.ts och synk.ts importerar Supabase-klienten.

Semantikas rotfiler är orörda: package.json, eslint.config.js och
.github/workflows/ är deras. Guidad Felsökning har egna motsvarigheter i
sin katalog.

CI flyttar samtidigt från GitHub Actions till .gitea/workflows — samma
syntax, egna runners. .github/workflows/ tillhör Semantika härefter.

Verifierat på den nya platsen: 96 vitest-tester, typkontroll, eslint på
både klient och tjänster, bygge, och integrationstest mot riktig Postgres.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 12:22:49 +00:00