Commit Graph

615 Commits

Author SHA1 Message Date
Claude 8aae3a2a97 Regelverk, ärendetyper och säkerhetssvar på engelska — med arv där data byter språk
ecm.ts bar regelverkets rådtexter: undantagsorsaker, orsakskategorier,
underlagskällor, evidensgrader och de meningar som säger vad som fattas.
Cirka hundra strängar, nu på engelska tillsammans med serverns
ecm-regler.json — klienten och regelpaketet måste säga samma sak, annars
är det inte samma regel.

Tre av dem var inte text utan DATA, och där gjordes bytet med arv i
stället för rakt av.

ÄRENDETYPEN ligger i loggen och slår upp regelpaketets extra krav. Ett
gammalt garantiärende vars typ heter "Garanti" hade inte matchat
"Warranty", fått noll extra krav, och släppts igenom grinden med FÄRRE
krav än när det öppnades — utan att någonting i gränssnittet visade det.
ARENDETYP_ARV normaliserar typen vid uppslaget, aldrig i loggen.

GALLRINGSTIDEN slås upp på samma nyckel, och det var värre. Ett
garantiärende hade fallit ur tabellen och tagit standardtiden 36 månader
i stället för 120 — alltså raderat garantiunderlaget sju år i förtid,
tyst och oåterkalleligt. Ett uppslag som missar ska ge det försiktigaste
utfallet; här gav det det farligaste. Två tester låser det.

SÄKERHETSSPÄRREN avgörs av en textsträng. När knappen bytte från "Ja"
till "Yes" gick klient och server isär: klienten skrev "Yes", servern
jämförde mot "Ja". Utfallet blev fail-closed — högvoltsärenden gick inte
att avsluta alls — vilket är rätt riktning för ett fel att falla åt, men
det var en slump och inte en konstruktion. `arJakande` känner igen ett ja
på alla språken. Att en säkerhetsspärr avgörs av fritext är i sig felet;
rätt lösning är ett booleskt fält, och att arvet står synligt i koden är
en påminnelse om det.

Pre-diagnostikens kvitteringar känns igen på sin text och har fått samma
behandling: gamla ärenden hade annars visat en ogjord kontroll för arbete
som faktiskt utförts, och teknikern hade kvitterat en gång till — två
kvitteringar för samma sak i en append-only logg.

Genomgången drev gränssnittet på svenska knappnamn och gick sönder på
rätt sätt: den hittade "+ Dokumentera felorsak", "Registrera besked" och
kundkanalerna "Telefon"/"E-post", som alla missats av de tidigare
svepen. Fyra av fyra ärenden avslutas igen.

609 tester, 186 integrationskontroller mot riktig Postgres, genomgång,
portalspärr, typkontroll och lint gröna. Mutationsprövat: utan
ARENDETYP_ARV faller två tester, utan `arJakande` ett.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 18:05:19 +00:00
Claude 3ea14575f1 Diagnostikgränssnittet på engelska
Portalen var engelsk, men själva arbetsverktyget — det tekniker faktiskt
använder — var svenskt rakt igenom. "Engelska som standard" gällde alltså
skyltfönstret och inte produkten.

Omkring 400 användarsynliga strängar är översatta: etiketter, knappar,
frågor, felmeddelanden, platshållare och de härledda projektionerna
(brief, tidrapport, kundrapport).

Bytet gjordes med en karta och ett skript som bara byter EXAKTA träffar
inom citattecken eller mellan JSX-taggar, aldrig delsträngar. Skriptet
rapporterar dessutom vilka poster som inte fick någon träff — fem
strängar stod som JSX-text efter ett element och syntes därför inte för
mönstret. Utan den rapporten hade de blivit kvar tysta.

Typsystemet fångade det som var farligt. Åtta anrop skickade händelsen
typ: "kommentar" och hade blivit typ: "comment" — en händelsetyp är DATA
i en append-only logg, inte text. Samma sak för `krav === "kommentar"`
och för ArbetsorderGrupp. Det är precis den sortens fel en
massöversättning gör, och precis därför den ska göras i ett projekt som
kompilerar.

Skillnaden mellan etikett och värde är genomgående kodad i domänmodellen
— nycklarna är `godkant`, `hog`, `symptomet_borta`, och det översatta är
_LABEL-posterna. Det var det som gjorde bytet möjligt att göra maskinellt
utan att röra loggen.

En regression från förra commiten är rättad: Slutsats.tsx sållade bort
hypotesbristerna med `text.includes("bemöts inte")`. När granskningen
började svara på engelska slutade jämförelsen tyst att matcha. Den går nu
på nyckeln, som inte byter språk.

Två saker att veta om befintliga installationer: en organisation som
sparat egna objekttyper eller identifieringsmetoder på svenska får
standardlistan tillbaka, eftersom okända värden filtreras bort, och
streckkodsläsarens `typ` matchar nu de engelska metodnamnen. Båda
degraderar till standard i stället för att gå sönder.

Datumen står kvar i ISO-format (sv-SE ger YYYY-MM-DD). Det är inte en
kvarlämnad svenskhet utan det entydiga formatet — en verkstadsrapport
ska inte kunna läsas som 03/04 åt två håll.

Kvar: ecm.ts (regelverkets rådtexter) och metodiker.mjs (metodikernas
steg och kontroller). De tas härnäst.

602 tester, typkontroll och lint rena.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 17:34:27 +00:00
Claude b2c2ce72a3 Språksidan: vad som är översatt, vad som är granskat, och skillnaden
En vanlig språkmeny påstår att produkten finns på tio språk och slutar
där. Sidan i foten redovisar i stället skillnaden mellan att en text ÄR
översatt och att den är GRANSKAD av någon som kan yrket — och visar det
på de strängar där skillnaden betyder något: grindens hinder, alltså de
meningar som nekar en tekniker att avsluta ett ärende.

Att välja just dem är avsiktligt. En spärr ingen förstår är en spärr
utan väg förbi, så det är rätt strängar att döma en översättning efter.
Väljaren byter språk direkt i provet; åtta av tio språk möts därefter av
beskedet att metodiken inte är fackgranskad på språket. Det är ett
obekvämt sätt att presentera sin egen produkt och hela poängen med
sidan: en verkstadschef i Rumänien som får veta det i förväg kan planera
för det, samma chef som får veta det av en tekniker som missförstått en
säkerhetsinstruktion kan inte.

Varningen står UNDER provet, inte över. Den som just läst fem meningar
på sitt eget språk ska mötas av vad de inte garanterar — inte varnas i
förväg och sedan lugnas av att texten ser bra ut.

Sidan ligger i foten och inte i portalens navigation. Den är
dokumentation snarare än ett arbetsverktyg, och portalraden har redan
tio poster.

Språkknapparna ligger i rutnät, inte flexradbrytning. Tio språk bröts av
flex till nio plus ett ensamt, och den ensamma knappen läste sig som en
eftertanke i stället för som ett språk bland tio. Två kolumner på telefon
och fem på skärm gör tio jämnt i båda riktningarna.

Utgåva 3.2 dokumenterad.

602 tester, typkontroll och lint rena. Artefakten byggd och mätt på 390
och 1280 px över femton vyer: inget spill, inga externa begäranden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 16:51:44 +00:00
Claude 322d228c80 ALVA-RULE-200 gällde bara på svenska — nu på tio språk
Slutsatsgranskningen avvisar icke-svar med en ordlista: "klart", "ok",
"trasig". Listan var enbart svensk. En tysk tekniker som skrev
"erledigt" i motiveringsfältet passerade filtret — inte därför att
texten dög, utan därför att filtret bara kände igen "klart". Grinden
släppte igenom avslutet och rapporten såg fullständig ut.

Det var alltså inte en översättningsbrist utan ett hål i den regel som
är hela produktens värde, och hålet fanns på varje marknad utom en.

Samma sak åt andra hållet: orsaksorden som visar att en text innehåller
ett resonemang var svenska, liksom evidensorden. Engelskans "photo"
innehåller inte "foto", så "the photo shows the arcing at pin 14"
räknades inte som en hänvisning till underlag. Följden hade varit värre
än ett släppt avslut — en korrekt skriven motivering hade nekats, och en
spärr som nekar rätt svar är en spärr man lär sig kringgå.

Listorna ligger nu i sprak/ord.mjs, per språk, och slås ihop till en
union i stället för att väljas efter inställning. Ett icke-svar är ett
icke-svar oavsett språk — jämförelsen görs mot hela fältet, så en
tekniker som skriver på ett annat språk än organisationens ska inte
kunna passera på den vägen. Orsaks- och evidensorden går åt motsatt
håll: unionen gör kontrollen mer tillåtande, aldrig strängare, och det
är rätt riktning att fela åt.

Medvetet utanför listorna: "inget", "keine", "none". Att ingenting
kvarstår osäkert är ett giltigt och ofta korrekt svar; att göra det till
ett icke-svar hade tvingat fram utfyllnad, och utfyllnad är sämre än ett
kort sant svar. Ett test låser det.

Bristernas texter kommer nu ur katalogen och bär sin nyckel, precis som
grindens hinder. Fältnamnet översätts med resten av meningen —
"Begründung fehlt.", inte "Motivering fehlt.".

Mutationsprövat: med listan återställd till enbart svenska föll nio
tester, ett per språk. Svenska och engelska är genomgångna; övriga
listor är en första uppsättning och står som ogranskade i filhuvudet,
av samma skäl som `granskat` i SPRAK — de är metodik, inte gränssnitt.

597 tester, 186 integrationskontroller, typkontroll, lint och genomgång
gröna.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 16:44:57 +00:00
Claude be10704349 Grinden talar organisationens språk — engelska som standard
Kvalitetsgrinden formulerade sina hinder på svenska, hårdkodat. I en
produkt där engelska är standardspråket betyder det att en spärr kan
neka ett avslut på ett språk teknikern inte läser. Det är en spärr utan
väg förbi: teknikern ser att systemet vägrar men inte varför, och den
enda utvägen blir att ringa någon. Det är då regeln slutar vara en regel
och blir ett hinder man lär sig kringgå.

Varje hinder bär nu både nyckel och färdig text. Nyckeln därför att en
klient som byter språk ska kunna rendera om utan att fråga servern;
texten därför att ett hinder som hamnar i en logg eller en PDF måste gå
att läsa utan katalogen. Hindrets id och nyckel är språkoberoende — det
är bara texten som byter.

Språket är organisationens, inte användarens. En verkstad i Tyskland med
en polsk tekniker ska ha ett gemensamt dokumentationsspråk; rapporten
ska inte byta språk beroende på vem som råkade stänga ärendet. Det
lagras i organisationens inställningar, och en felstavad landskod blir
engelska i stället för ett fel — språkinställningen är en etikett och
ska inte hindra någon från att spara sina objekttyper.

SPARRFRAGOR bär nu nycklar i stället för svensk text. Testet som jämför
serverns lista med klientens jämför nycklar, så listorna kan fortfarande
inte glida isär.

Två tester prövade svenska ord i grindens utdata och gick sönder, vilket
var rätt av dem. De prövar nu nyckeln — texten är översatt och byter
språk med organisationen, och att pröva svenska ord hade gjort dem till
tester av vilket språk som råkar vara standard. Ett nytt test prövar det
som faktiskt betyder något: samma id, samma nyckel, olika text.

Integrationstestet följer språket hela vägen — organisationens
inställning, genom servern, ut i det 409-svar som nekar avslutet: engelska
som standard, tyska efter byte, engelska igen vid okänd kod.

582 tester, 186 integrationskontroller mot riktig Postgres, genomgång och
portalspärr gröna.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 16:36:53 +00:00
Claude 995858174d Språk: engelska som källa, tio EU-språk, och en struktur som inte får översättas
Engelska är standard- och källspråk. Nio översättningar till: tyska,
franska, spanska, italienska, polska, nederländska, portugisiska,
rumänska och svenska.

Två sorters text, behandlade olika. GRÄNSSNITTSTEXT faller tillbaka på
engelska tyst — en engelsk knapp hos en tysk användare är irriterande
men ofarlig. METODIKINNEHÅLL gör det aldrig tyst: det märks som
ogranskat, med språket namngivet. Skälet står i modulhuvudet och är hela
poängen med uppdelningen: engelska SYNS som ett annat språk, medan en
felaktig översättning ser ut som en instruktion. En maskinöversatt
säkerhetsanvisning som ingen fackman läst är därför sämre än en engelsk.
Bara engelska och svenska är `granskat: true`.

Strukturen översätts inte. ALVA-SPEC-001 §2 slår fast att fasnamn och
statusord skrivs likadant i varje land — en revisor ska kunna läsa en
rumänsk och en tysk rapport utan att veta vilket språk verkstaden
arbetar på. Det hade gått att skriva in dem oöversatta i varje katalog
och låsa dem med ett test; det är svagare, för en översättare som ser
"Passed" i den polska filen översätter den, och testet blir en tvist i
stället för en regel. Nycklarna saknas i stället helt i
översättningarna och `t()` hämtar dem alltid ur engelskan. Då finns
ingenting att översätta fel.

Testet räknar inte bara nycklar — det går att få grönt genom att
kopiera engelskan till tio filer. Det prövar fyra saker: att katalogen
är komplett, att strukturen inte är översatt, att inget språk är
engelska i förklädnad (tak på 25 % identiska strängar), och att
variabelhållarna överlevde. {procent} som blir {percent} i den franska
filen ger inget fel — den ger "{percent} % de l'interface" på skärmen,
för alltid.

Mutationsprövat: en borttagen nyckel, en översatt statussträng, en
trasig variabelhållare och en polsk fil som var en kopia av engelskan
gav sex röda tester. Polskan har dessutom en egen anmärkning i
filhuvudet: {sprak} sätter in "Polski" i nominativ, och "w języku
Polski" är fel — meningarna är därför omskrivna så att namnet står som
etikett i parentes.

581 tester, typkontroll och lint rena.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 16:27:45 +00:00
Claude 0566ddadc6 Startsidan: bort med färdplanen, och rapportens frågor i stället för dess disposition
Färdplanen är borttagen. Fyra faser med "Planned" och "Specified" säger
inget om vad man får i dag — den lovar framtid på en sida där läsaren
försöker avgöra om nuet duger.

Kvartalsrapporten stod som en tabell med kolumnerna Section, Content och
Basis: alltså en beskrivning av rapportens DISPOSITION. Det är
dokumentation, inte en startsida — läsaren fick veta hur rapporten är
uppbyggd innan den fått veta vad den svarar på, och "SECTION" upprepat
sex gånger var det mest framträdande på skärmen.

Nu står frågorna. Vilka fel diagnosticerar vi rätt första gången? Hur
ofta visar sig en misstänkt orsak vara den verkliga? Vilka fel kommer
tillbaka? Vilka steg hoppas över, och varför? En verkstadschef känner
igen sina egna frågor; ingen känner igen en innehållsförteckning.

Verifierat mot den byggda artefakten: ROADMAP borta, SECTION-etiketten
borta, 491 tester, artefakten ren.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 16:07:02 +00:00
Claude 934bc2e4bc Staplade tabeller: rubrik i stället för arton etiketter
Den staplade formen upprepade kolumnnamnet före VARJE cell. Sex rader
gånger tre kolumner blev arton etiketter av samma vikt, och innehållet
drunknade i dem — kvartalsrapporten på startsidan var en vägg av
SECTION / CONTENT / BASIS där själva texten var det minst framträdande.

Etiketten för första kolumnen var dessutom rent brus. Den cellen ÄR
radens identitet, och att skriva "SEKTION" ovanför "New validated
diagnostic patterns" säger ingenting som inte redan står där.

Första cellen är därför rubrik utan etikett, resten etiketteras, och
blocken skiljs med ram och bakgrund i stället för med en hårstreckslinje
— ögat ska se var en post börjar utan att läsa. Arton etiketter blev sex
rubriker och tolv små etiketter.

Ändringen ligger i Tabell och gäller därmed varje staplad tabell i
portalen: garantier, försäkring, support, abonnemang, fakturor,
Impressum och utgåvor.

491 tester · genomgången 4/4 · artefakten ren.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 16:03:11 +00:00
Claude 5579006e79 Abonnemang: gratis start, månadsfaktura, och en låsning som aldrig rör historiken
Kontot startar på Free och stannar där tills någon väljer annat. En
provperiod som tyst börjar kosta är samma sorts fälla produkten finns för
att undvika. Fakturan skapas ändå vid registreringen — på noll kronor —
därför att den etablerar serien och visar kunden exakt vad den inte
betalar för.

Fyra nivåer: Free (hela metoden, två konton), Standard, Premium,
Enterprise. Enterprise har inget listpris i stället för ett påhittat.
Basavgift plus per aktiv användare, och nivån är en HÄNDELSE — vilken
nivå som gällde när en faktura utfärdades måste gå att svara på i
efterhand, och en kolumn som skrivits över kan inte svara.

Månadsjobbet är idempotent på perioden: kör det två gånger samma dygn och
den andra körningen fakturerar ingenting. Ett fakturajobb som
dubbelfakturerar vid en omstart är värre än ett som inte kör alls.
Perioden räknas från registreringsdagen, inte från den första i månaden —
den som registrerar sig den 20:e ska inte få en faktura på elva dagar som
sin första upplevelse av produkten.

PDF utan beroenden. Kravet var inga beroenden, och ett PDF-bibliotek drar
in fem till för att rita text i två spalter. PDF är ett textformat;
generatorn är tvåhundra rader som går att läsa. Renderad och verifierad i
Chromium. Kunden hämtar fakturan själv eller anger en adress — bägge
vägar leder till samma dokument, och e-post är ett tillägg, inte den enda
vägen till sitt eget underlag.

---- Låsningen och dess gräns ------------------------------------------

Vi litar på kunden: inget kort, ingen förskottsbetalning, ingen spärr
innan någon fått veta. Förfallen faktura ger synlig nedräkning i 14 dagar
och sedan stopp för nya ärenden.

Men läsning och export är sanna i ALLA tillstånd, och det är inte
generositet. Ärendeloggen är verkstadens underlag i en garanti- eller
försäkringstvist som gäller DERAS kund — en tredje part utan del i vår
obetalda faktura. Att göra det oåtkomligt vore att använda någon annans
rättsliga ställning som påtryckningsmedel. Prövat från flera håll,
eftersom det är en regel som är lätt att tumma på under press.

En nollfaktura kan aldrig låsa någon. Free fakturerar noll, och en
obetald nollfaktura är en bokföringspost, inte en skuld.

---- Tre fynd som testerna grävde fram ----------------------------------

1. En kuverterad nyckel gjorde HELA organisationens övriga ärenden
   oläsbara när huvudnyckeln saknades — nycklarFor laddar alla nycklar,
   och en enda som inte gick att öppna kastade. En delvis migrerad
   organisation blev alltså helt stum av ett fel som gällde ett ärende.
   Nu hoppas den över, med varning i loggen, och fälten maskeras — vilket
   dessutom är rätt utfall i sak: det är precis vad krypto-shredding
   lämnar efter sig.

2. Integrationstestet försökte backdatera abonnemangets registrering och
   stoppades av min egen trigger. Att testet fick böja sig för regeln och
   inte tvärtom är poängen med regeln.

3. Palettestet räknade upp färgerna som en andra lista — samma dubblering
   som M-7 handlade om. Det läser dem nu ur FARG, med ett tak på åtta
   värden som motvikt: en palett som växer förbi det är en färglåda.

491 enhetstester · 179 integrationskontroller · genomgången 4/4 ·
portalspärren 18/18.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 15:55:13 +00:00
Claude 86558120e4 Systembeskrivning: vad ALVA är, vad som finns, vad som inte finns
Underlag för att resonera vidare utan att ha varit med när det byggdes.
Siffrorna är räknade ur källkoden, inte uppskattade: 17 metodiker, 48
händelsetyper, 39 API-vägar, 18 tabeller, 24 testfiler, radantal per del.

Mognadsavsnittet skiljer på bevisat och öppet, och listar det öppna i
klartext — abonnemangsmodellen finns inte, Terraform är beskrivet men
inte applicerat, Impressum har sin struktur men inga uppgifter, T-3:s
backupfönster är inte stängt. En beskrivning som utelämnade det vore
säljmaterial, inte underlag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 15:18:12 +00:00
Claude ae5acbed92 Fotograferad mätarställning, versionshistorik och tysk kravbild i foten
---- Mätarställningen ska fotograferas ----------------------------------

Klienten krävde redan fotot: värdefältet visas först efter bilden. Men
GRINDEN gjorde det inte, och en regel som bara finns i gränssnittet är en
vana — inte en spärr. Det är samma förhållande som QUALITET C-2 gällde,
fast åt andra hållet: här var servern svagare, vilket är värre, eftersom
servern är den auktoritativa.

Skillnaden är hela uppgiftens bevisvärde. En inskriven siffra är
teknikerns påstående om vad som stod på mätaren; ett foto visar vad som
stod där. Mätarställningen avgör garanti- och försäkringsfrågor i
efterhand och är den enda uppgift i ärendet någon kan ha ett intresse av
att skriva fel. Evidensgraderingen följer nu med: fotograferad ger E2,
inskriven ger E1 och märks som inskriven i rapporten.

Undantag finns och måste finnas — slocknad display, oåtkomlig timräknare
— men kräver motivering, som det nekade historiksvaret.

---- Versionen räknades aldrig upp --------------------------------------

Systemet påstod "ALVA 1.0" efter tre revisioner, en fakturamodul och en
stängd portal. Versionen sa alltså ingenting om vad man fick.

Historiken är HÄRLEDD UR VAD SOM FAKTISKT LEVERERATS och varje post pekar
på sin commit. En utgåva som inte går att peka på hör inte hemma i listan
— en påhittad ändringslogg är samma obefogade säkerhet som produkten
finns för att undvika. Första siffran höjs bara när GARANTIERNA ändras,
vilket hänt två gånger: 2.0 när fakturan blev ett härlett dokument, 3.0
när TÜV-härdningen ändrade vad loggen garanterar. Nuvarande: 3.1.

Och ett fynd på vägen: ritningsstämpeln läste versionen ur den AKTUELLA
konstanten, så ett ärende stängt under 1.0 visade 3.1 — precis det
stämpelns egen beskrivning säger att den inte ska göra. Avslutshändelsen
bär numera versionen, och stämpeln läser den därifrån. Äldre ärenden
säger uttryckligen "ej registrerad" i stället för att låna dagens siffra.

---- Tysk kravbild i foten ----------------------------------------------

Listan är tysk därför att § 5 DDG är den strängaste och mest utkrävbara i
EU: klarar man den klarar man de andra marknaderna på köpet.

Två fällor som är aktuella just nu, och bägge ser fortfarande ut som
upplysningar:

  ODR-LÄNKEN SKA BORT. Förordning 524/2013 upphävdes genom förordning
  (EU) 2024/3228 och plattformen stängdes 20 juli 2025. Länken har legat
  i tiotusentals fotnoter sedan 2016 och pekar numera ingenstans. Foten
  saknar den medvetet.

  § 5 TMG HETER § 5 DDG sedan 14 maj 2024.

Modulen hittar inte på uppgifter. Ett Impressum med påhittad adress är
inte ett halvfärdigt Impressum utan ett vilseledande, och skadan större
än den tomma rutans. Osatta fält redovisas som en åtgärdslista med
rättslig grund, så driften kan spärra en driftsättning på listan i
stället för att upptäcka bristen när brevet kommer.

460 enhetstester · genomgången 4/4 · typkontroll ren.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 15:15:35 +00:00
Claude a94c228cab Garantiregimer, försäkringsvillkor och felanmälan i ärendet
---- Garantier (ALVA-SPEC-040) -----------------------------------------

Skiljelinjen mellan LAGSTADGAT och AVTALAT bär allt annat, och den
förväxlas dagligen åt bägge håll. Överraskande lite av det verkstaden
kallar garanti är lagstadgat:

  nybilsgaranti      avtalad. Ingen lag i EU eller USA kräver den.
  rostskyddsgaranti  avtalad. Ingen lag kräver den, någonstans.
  lackgaranti        avtalad.
  drivlinegaranti    avtalad.
  avgasgaranti       LAGSTADGAD i bägge, och den enda som är det.

Att kalla rostskyddet lagstadgat är fel; att kalla avgasgarantin en
tillverkarutfästelse är fel åt andra hållet, och det andra felet kostar
kunden pengar — en katalysator på en sexårig bil offereras rutinmässigt
som en betald reparation när den inte är det.

Varje lagstadgad post bär källa och kontrolldatum: 2019/771 (2 år,
säljaren — inte tillverkaren), MVBER 461/2010 förlängd till 2028,
715/2007 (5 år/100 000 km), 2024/1257 (8 år/160 000 km, batteri 80 %
vid 5 år och 72 % vid 8), CAA § 207 (2/24 000 och 8/80 000 miles),
Magnuson–Moss § 2302(c), CARB (3/50 000 och 7/70 000), ACC II (70 % SoH
vid 8 år/100 000 miles).

Bedömningen skiljer INOM, UTANFÖR och OKLART. Saknas underlag blir det
oklart, aldrig utanför — att påstå att en garanti gått ut när underlaget
inte räcker är det enda felet här som kostar kunden pengar.

---- Försäkring (ALVA-SPEC-041) ----------------------------------------

Modulen avgör ingenting och kan inte avgöra något. Vad som gäller
bestäms av kundens eget försäkringsbrev och villkoren vid tecknandet —
inte av vad ett bolag skriver i dag och inte av vad vi noterat. Testerna
låser att resultatet inte innehåller något fält som liknar ett utfall,
och att ett fordon utanför samtliga noterade gränser ändå inte får ett
nej: registret kan vara ofullständigt och produkten en annan.

Det som står överst är de sju villkoren som avgör en maskinskadefråga.
Ålder och sträcka är två av dem; de fem andra avgör oftare. Registret
med If, Folksam, Trygg-Hansa, Svedea, WaterCircles och Hedvig ligger
under, med källa och avläsningsdatum per post, och märks som föråldrat
efter 180 dagar i stället för att se aktuellt ut.

---- Felanmälan i ärendet (ALVA-PROC-0050) -----------------------------

En anmälningsknapp som bara finns i en portalvy nås aldrig av den som
står med händerna i en bil. Den ligger därför i varje ärende, och tar
med sitt sammanhang självt: ärende, metodik, plattformsversion och
spår-id. Teknikern minns inte plattformsversionen, och att fråga efter
den är att lägga över vårt problem på verkstaden.

Sammanhanget HÄRLEDS och kan inte smugglas: ett regnr i anropet släpps
inte igenom. En supportanmälan är inte ett skäl att flytta
personuppgifter till ett annat system. Bevisat i integrationstestet.

Anmälan är oföränderlig och statusen en projektion av inläggen — samma
skäl som för fakturan: en anmälan vars historia kan skrivas om är inte
ett underlag när någon frågar hur länge felet var känt. Verkstaden
svarar i sitt eget ärende; status sätts av supporten med egen nyckel.

---- Historikkontrollen -------------------------------------------------

Kravet fanns redan: klienten öppnar inte metodiken förrän
pre-diagnostiken är besvarad, och ett nej kräver skriven motivering.
Det var dock aldrig BEVISAT att spärren håller. Genomgången prövar nu
att metodiken inte går att nå medan historikfrågan står obesvarad — i
det enda ögonblick det går att pröva, eftersom svaret därefter redan är
avgivet.

429 enhetstester · 157 integrationskontroller mot riktig Postgres ·
genomgången 4/4 · portalspärren 16/16.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 14:56:48 +00:00
Claude 6790b60182 Symmetri i huvudet och i knapparna
Navigationen trycktes ihop mot högerkanten med ett tomrum efter
ordmärket. På smal skärm ligger den nu på egen rad och fördelas över
hela måttet — samma fördelning som sidfoten redan använder. Raden får
sin balans av marginalerna i stället för av att posterna klumpas ihop.
Mätt: noll pixlar kvar på bägge sidor. Portalens sex länkar blir på 360
px en tvåkolumnsindex, vilket läser sig som avsikt och inte som spill.

Knapparna var innehållsbreda, så REQUEST ACCOUNT blev dubbelt så bred
som LOGIN. Två knappar bredvid varandra där den ena är dubbelt så bred
läser sig som en huvudåtgärd och en eftertanke, oavsett vad de heter —
och det är inte förhållandet mellan dem. Rutnätet ger dem samma bredd;
vikten skiljs av fyllning mot kontur, som resten av systemet gör.

Lika bredd räckte inte: REQUEST ACCOUNT bryts till två rader och
knapparna blev då olika HÖGA, vilket är samma obalans en rad ned. Bägge
fyller nu sin cell. Mätt: 163x57 mot 163x57.

---- Och ett test som slutade mäta -------------------------------------

Namntestet från förra ändringen matchade markup-formen, inte
invarianten. När <Link> fick en className hittade mönstret noll knappar
— testet slutade mäta i stället för att falla. Det enda som avslöjade
det var kravet att det ska hitta NÅGOT, och det är därför kravet står
där i stället för att tas för givet.

Mutationstestat igen efter rättelsen: bägge testen faller när
"Customer login" läggs tillbaka.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 13:54:37 +00:00
Claude 0cc4f1578c Inloggningen heter Login, inte Customer login
Startsidans knapp hette "Customer login" medan navigationen kallade
samma sida "Login". Två namn på samma destination är förvirrande i sig,
men det här var värre än så: "customer" är i det här systemet FORDONETS
ÄGARE — den som får delningslänken och godkänner en åtgärd. Verkstaden
som loggar in är inte den. Knappen lovade alltså en ingång för fel
person, med produktens eget ord för någon annan.

Två test låser det: varje länk till inloggningen bär navigationens namn
på destinationen, och ingen ingång kallar verkstaden för kund.
Mutationstestade — bägge faller när "Customer login" läggs tillbaka.

Övriga "customer" på ytan står kvar. De handlar om fordonets ägare, och
där är ordet rätt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 13:37:17 +00:00
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 c9fdef27c9 Text som lade sig ovanpå text — och kontrollen som inte såg det
Etiketten AUTHENTICATION är bredare än 96 px och kan inte brytas. Den
staplade mobilformen gav den `w-[96px]`, så texten rann ut ur sin ruta
medan värdet började vid 96 px. Bokstäverna hamnade ovanpå varandra.
`min-w` låter korta etiketter hålla kolumnen och långa knuffa värdet
till nästa rad i stället.

Det allvarligare var att breddmätningen i genomgången inte kunde ha
hittat det här: överspill gör inte dokumentet bredare. Ett första försök
att jämföra elementens rutor rapporterade noll krockar med felet
återinlagt — rutorna skar aldrig varandra, bara bokstäverna gjorde det.
Mätningen jämför därför nu elementets textbredd med dess egen ruta, och
görs över portalens åtta vyer i telefonbredd.

Bevisad: med `w-[96px]` återinlagt faller genomgången med exitkod 1 och
pekar på kunskapskällor och Authentication. Med `min-w` grön igen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 10:35:57 +00:00
Claude b457543ede Fakturering i systemet — och ingen betalleverantör
ALVA säljs inte över disk. Aktiveringssekvensen på webbplatsen har hela
tiden sagt det: ansökan granskas, faktura utfärdas, betalning
registreras, organisationen aktiveras. Ändå laddade sidan Stripe.

Stripe. `@stripe/stripe-js` injicerar sitt skript redan vid import, inte
när någon ska betala, så ALVA hämtade en betalleverantör vid varje
sidvisning trots att produkten aldrig tar emot en betalning. Bakom
artefaktens CSP blockerades anropet och syntes som ett fel i konsolen på
ett system som inte har en kassa. Importen går nu mot `/pure`, som är
samma modul utan sidoeffekten. Butikens kassa fungerar som förut, men
bara när någon faktiskt öppnar den. Externa begäranden på ALVA-ytan:
noll.

Faktureringen. Beloppet måste komma någonstans ifrån, och det enda
hållbara stället är organisationens faktiska tillstånd: aktiva konton,
licensperiod, påslagna moduler. En summa någon skriver in kan säga emot
verkligheten — en härledd kan inte det. Samma resonemang som
sammanfattningen. Varje rad bär sitt underlag, så en granskare ser varför
summan blev den den blev utan att fråga någon.

Beloppen räknas i öre, momsen på nettot och inte per rad, och en utfärdad
faktura ändras aldrig: en felaktig faktura krediteras med en post som
pekar tillbaka och kräver ett skäl. Samma regel som för händelseloggen.

Prislistan ligger på ett ställe och är märkt som platshållare — den ska
sättas per marknad. Mekanismen är oberoende av siffrorna.

Ingen betalningshantering, inga kortuppgifter, ingen extern tjänst.
Betalning registreras av en administratör när pengarna kommit in;
systemet påstår aldrig att något är betalt utan att en människa sagt det.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 09:38:52 +00:00
Claude 9533a90b7b Skriv om demonstrationsmärkningen så den inte går att missförstå
Första formuleringen sa "Applications are handled outside this
demonstration". Det läses lika gärna som att ansökningar tas emot någon
annanstans, av ett riktigt system. Det gör de inte — det finns ingen
mottagning alls. En läsare frågade vad meningen betydde, vilket är
svaret på om den var tydlig.

Värre var att produktens beskrivning av avsedd handläggning stod direkt
under: två meningar bredvid varandra där den ena säger att ingenting
händer och den andra beskriver en granskningsprocess. De upphävde
varandra. Den senare är nu märkt "Intended operation:".

Inloggningens ruta hänvisade till att den riktiga autentiseringen finns
i plattformstjänsten, vilket inte hjälper någon som står på sidan. Den
säger nu vad besökaren ska göra: skriv vad som helst, lösenordet
kontrolleras inte, inget konto behövs.

En märkning som inte går att missförstå säger två saker — att ingenting
sker, och vad läsaren ska göra i stället. Fyra tester låser båda.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 04:31:16 +00:00
Claude 3ffedcd78e Märk de ytor som inte gör något (QUALITY-AUDIT-2 · m-9)
Inloggningen autentiserar ingenting: vilken organisation och vilket
användarnamn som helst släpps in, och lösenordet kontrolleras inte.
Kontoansökan skickar ingenting, och referensen på kvittenssidan bildas i
webbläsaren. Portalens siffror är fasta exempelvärden.

Bägge ser ändå ut som att de gör något, och två personer i rad har
försökt använda dem på riktigt innan de frågade. Det är precis vad
fyndet förutsade: en yta som ser färdig ut planerar man efter.

Integrationssidan tillämpar redan den här måttstocken på sig själv — en
profil står `draft` tills den körts mot leverantören, med motiveringen
att en lista där allt ser färdigt ut är den snabbaste vägen till ett
misslyckat införande. Samma regel gäller nu resten av ytan.

Rutan säger vad som INTE sker, inte vad som ska komma. Ett löfte om
framtida funktion vore samma fel i ny form, och ett test avvisar
formuleringar av den sorten.

Det här stänger inte m-9 helt. Den ärliga slutfixen är att låsa
portalrutten bakom den riktiga plattformssessionen, vilket är ett beslut
om vad portalen ska vara — men tills dess vilseleder den inte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 04:24:20 +00:00
Claude 66762629df Bäddad typografi, tätare spärrning, räta hörn och ritningsstämpel
Fyra saker som alla svarar på samma sak: ALVA såg fortfarande inte ut som
det den påstår sig vara.

Snittet som fil. Fallkedjan säkrade ordningen men inte utfallet — utan
DIN installerad föll ytan ned till vad enheten råkade ha, Helvetica på en
iPhone och Roboto på en Android. Ett system som beskriver sig som en
standard får inte se olika ut beroende på var det öppnas. IBM Plex Sans,
specens tredje tillåtna snitt, bakas därför in: latinsk delmängd, tre
textvikter och två för monospace, drygt 100 kB. Licensen följer med.

Vite bakar in woff2 som data-URI. Det är inte en optimering utan ett
krav: ALVA publiceras bland annat som en självbärande sida bakom en CSP
där varje extern begäran blockeras, och en @font-face mot en assetfil
hade tyst fallit tillbaka till enhetens eget snitt — alltså precis det
inbäddningen ska avskaffa. Bara woff2; värdapplikationens bilder är
megabyte stora och förblir egna filer.

Spärrningen ett steg tätare genomgående. DIN-satta OEM-dokument är tätare
än vad ytan var, och med rätt bokstavsform tål den det.

Räta hörn i felsökningen. 69 förekomster av rundad radie, alla ur
Lovable-arvet. Ett verkstadssystem har räta hörn.

Ritningsstämpel sist i rapporten: beteckning, regelpaket, evidensmodell,
plattformsversion, status och utgåvedatum. En granskare måste kunna se
vilka versioner som gällde när ärendet stängdes, inte vilka som gäller
den dag rapporten läses.

Fyra tester låser inbäddningen, inklusive att ingen @font-face pekar mot
en extern värd.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 03:08:30 +00:00
Claude 9668cc256b Ge ALVA-ytan sin egen typografi enligt ALVA-SPEC-001
ALVA satte inget eget snitt och ärvde därför värdapplikationens
`Crimson Text` — en antikva. Specens paragraf 6 föreskriver DIN 2014,
med FF DIN och IBM Plex Sans som tillåtna alternativ.

Skillnaden är inte kosmetisk. Bokstavsformen är det första som säger
vilken tradition ett verktyg tillhör, och dokumentet beskrev ett tyskt
industrisystem medan skärmen visade en bokstavsform ur en helt annan.
På en telefon, där ingenting annat konkurrerar om intrycket, var det i
praktiken allt man såg.

Fallkedjan är därför inte godtycklig: en organisation som licensierat DIN
får DIN, övriga faller ned genom grotesker som delar dess karaktär, och
aldrig till en antikva. Beteckningar och mätvärden sätts med fast
teckenbredd och tabellsiffror — en beteckning jämförs oftare än den läses.

Reglerna gäller bara ALVA-ytan; butiken lämnas som den är. Fyra tester
låser snittet, kaskaden och siffrorna, inklusive att fallkedjan aldrig
slutar i en antikva.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 21:21:45 +00:00
Claude 07b6713245 Gör ALVA läsbart på telefon
Portalens tabeller sköt ut dokumentet till 842 px på en 390 px-skärm.
Sidan gick att dra i sidled och texten kapades i högerkanten.

Tre orsaker, tre olika svar.

Tabellerna. En sexkolumnstabell på en telefon har två utfall och bägge är
dåliga: antingen tvingas hela sidan i sidled, eller så scrollar tabellen
inuti sig själv och läsaren ser tre tecken av varje kolumn. Under 640 px
blir varje rad därför en grupp namngivna fält — kolumnrubriken som
etikett, cellen som värde. Samma form som Falt redan använder, och samma
princip som resten av ytan: ett instrumentpanelsblad läses uppifrån och
ner. Bägge formerna renderas och växlas med bredd, inte med JavaScript.

Navigationen. Portalens fem länkar bröts inte utan breddade dokumentet.
Raden bryts nu, med tätare mellanrum på smal skärm.

Fasindikatorn. Kolumnerna saknade min-w-0 och kunde därför inte krympa
under sitt innehåll. Ett första försök lät namnen brytas, men
"LOCALIZA/TION" mitt i ordet är inte tydligare än inget namn. Under
640 px bär bokstaven och statussymbolen informationen — vilket är precis
vad A·L·V·A är till för — medan raden ovanför namnger den aktiva fasen
och dess syfte i klartext. Namnet finns kvar för skärmläsare.

Mätt vid 390 och 360 px: samtliga sju ALVA-vyer, ansökans kvittens,
ärendelistan och ärendesidans tre flikar håller sig nu inom skärmbredden.
Fyra tester låser konstruktionerna. Designtestet fångade förresten mitt
eget brott mot 8-px-rutnätet på vägen — py-1 — och koden rättades, inte
testet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 20:24:46 +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 45967d086e Lås inte in ärenden där åtgärden dokumenterades före förslaget
När kundbeskedet blev ett avslutsvillkor i klienten uppstod en fälla:
knappen "Lämna åtgärdsförslag till kund" visades bara när ingen åtgärd
var dokumenterad, och beskedsrutan bara när ett förslag fanns. En
tekniker som skrev åtgärden först hade därmed ingen väg att registrera
beskedet, och ärendet gick inte att stänga.

Grinden avvisade redan sådana ärenden vid synk — villkoret i klienten
flyttade bara upptäckten. Men ett spärrvillkor utan väg ut är ett fel
även när spärren i sig är riktig.

Förslagsknappen står kvar tills ett förslag faktiskt lämnats. Ordningen
förslag → besked → arbete är fortfarande den panelen föreskriver, och
loggen är append-only med tidsstämplar, så ett besked som registreras i
efterhand syns som just det.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 17:44:26 +00:00
Claude 8daeb41ba1 Kräv kundens besked även i klienten innan avslut
Grinden på servern har alltid krävt kundbeskedet när arbete faktiskt
utförts. Klientens kanAvslutas gjorde inte det, och glappet syntes först
när tio ärenden av olika karaktär kördes hela vägen genom gränssnittet:
samtliga tio gick att stänga på skärmen med utfört arbete och utan att
kunden hade sagt ja.

Det är samma sorts fel som slutsatsen hade, på ett annat villkor — och
det värre av de två, eftersom ett utfört arbete utan registrerat besked
är precis vad en tvist handlar om.

Hindertexten namnger nu kundbeskedet, och ett test speglar klientens
avslutsvillkor mot grindens hela åtgärdskedja så att nästa villkor som
läggs till i grinden inte kan glömmas i klienten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 17:41:45 +00:00
Claude 6fa7953012 Logga metodikens mätkontroller som mätvärden
En kontroll vars krav är "matvarde" loggade bara kontroll_utford. Det
gällde 56 av metodikernas 153 kontroller — drygt en tredjedel — och fick
två följder som bägge upptäcktes när tio ärenden kördes igenom
gränssnittet:

Felorsaksanalysen nekade "Mätresultat" som underlag med motiveringen att
underlaget inte finns i loggen, trots att teknikern just hade matat in
mätvärdet som kontrollen krävde. Enda vägen förbi var att mata in samma
siffra en gång till via dokumentationspanelen.

Evidensprofilen i analysvyn underskattade systematiskt hur mycket som
faktiskt mäts, eftersom mätningarna aldrig fanns som mätvärden.

Mätningen loggas nu som det den är. Utan känt mätdon graderas den E1 och
inte E4 (QUALITY-AUDIT M-1) — ett avläst tal utan spårbart instrument är
inte en spårbar mätning.

Tre tester låser förhållandet mellan metodikernas kravtyper och den
evidens de producerar, så att en ny kravtyp inte kan införas utan att
någon tar ställning till vad den ska ge för evidens.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 17:35:26 +00:00
Claude f0f5cc670e Håll ALVA-ytan fri från butikens driftmeddelanden
Betalningsbannern satt i App och undantog bara /felsokning, så den
renderades ovanför ALVA-huvudet: "Skarpa betalningar är inte
konfigurerade." En verkstad som ser ett driftmeddelande från en annan
produkt läser det som att den tittar på något halvfärdigt. Det är ett
trovärdighetsproblem, inte ett kosmetiskt.

Undantaget jämför nu hela sökvägssegment i stället för prefix, så att
/alvarlig inte råkar räknas som ALVA.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 16:29:12 +00:00
Claude 590fab3a70 Spärra avslut utan slutsats även i klienten (ALVA-RULE-200)
Kvalitetsgrinden på servern krävde en slutsats, men klientens
avslutsknapp gjorde inte det. Ett ärende gick därför att stänga på
skärmen utan ett varför, och teknikern fick beskedet först vid synk —
den sämsta tänkbara tidpunkten, eftersom bilen då har lämnat verkstaden.

Klienten anropar nu granskaSlutsats() — samma funktion som grinden, inte
en klientkopia av regeln — och avslutsknappen är spärrad tills den är
ren. Slutsatspanelen visas så fort underlaget är helt, inte bara när
metodikens sista steg är avbockat, så att frågan kommer när den går att
besvara och inte som ett hinder efteråt.

Hindret säger vad som fattas i stället för att bara konstatera att kraven
inte är uppfyllda: först underlaget, sedan de enskilda bristerna i
slutsatsen.

Fyra tester jämför verdikt mellan klient och grind för samma logg, så att
de två ändarna inte kan glida isär igen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 16:20:27 +00:00
Claude cd6b2caca5 Sammanfattning och slutsats i rapport och Live Share; API dokumenterat
Sammanfattningen ligger först i både kundrapporten och Live Share.
Mottagaren är oftast inte tekniker — det är kunden, en
försäkringshandläggare eller en flottansvarig — och de ska få bilden på
fem sekunder och sedan kunna gå djupare, inte tvärtom.

I Live Share härleds den ur det NIVÅFILTRERADE underlaget. Det betyder
att sammanfattningen aldrig kan avslöja något som delningsnivån döljer:
filtret ligger före projektionen, inte efter.

Slutsatsen visas som ett eget avsnitt före underlaget. En handläggare
läser skälet först och kontrollerar det sedan — den ordningen är hela
poängen med att fältet finns.

Sju nya vägar dokumenterade i OpenAPI och låsta av paritetstestet:
sammanfattning, protokollinläsning, statistik, integrationskategorier,
prenumerationer, radering och mätdon. Ett API som inte är dokumenterat
är inte ett API någon kan koppla in sig mot — och specen valideras
maskinellt så dokumentationen inte kan glida från servern.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 15:55:31 +00:00
Claude 3ec25dea9c ALVA: analysvy, sammanfattning och integrationsgränssnitt
---- Statistiken är ett produktbeslut ----------------------------------

Vilka siffror som visas avgör vad organisationen optimerar, så tre mått
är uteslutna med avsikt och låsta av test: ärenden per tekniker,
genomsnittlig ledtid och aktivitet. Alla tre belönar den som hoppar över
kontroller, och ett svårt fel SKA ta längre tid.

Medtagna, var och en handlingsbar:

  VERIFIERINGSGRAD   Andel avslut med fastställd orsak. Det enda mått
                     ett försäkringsbolag egentligen bryr sig om. Att
                     den inte är 100 % är friskt.
  REPRODUKTIONSGRAD  Låg siffra förutsäger återkommande fordon — man kan
                     inte åtgärda det man inte sett.
  OMARBETNING        Samma fordon tillbaka med samma orsakskategori inom
                     ett fönster. Det dyraste felet i en verkstad och det
                     enda ingen mäter, eftersom det kräver att två
                     ärenden kopplas ihop. Här är kopplingen gratis.
  UNDANTAGSFREKVENS  Vilka kontroller som hoppas över, per steg och fas.
                     Ett steg högt i listan är antingen felskrivet eller
                     kräver utrustning som saknas — bägge åtgärdbara.

Ett mått utan underlag visas som NOT APPLICABLE, aldrig som noll.
Skillnaden avgör om någon fattar beslut på en siffra som inte finns.

---- Sammanfattningen är härledd, inte genererad -----------------------

Frestelsen är att låta modellen skriva den. Det vore fel av tre skäl:
den blir en del av ett beslutsunderlag och måste därför gå att lita på
utan att granskas mot loggen varje gång; samma ärende måste ge samma
text om två år; och verkstadsgolvet har dålig täckning.

Den är alltså en projektion som briefen och rapporten. Den innehåller
inget som inte står i loggen och säger uttryckligen när något saknas i
stället för att utelämna det. Ett test kräver att den aldrig skriver
"felet konstaterat" när orsaken inte fastställts.

---- Integration utan påhittade endpoints ------------------------------

Jag känner inte Beonodes, ServiceCams eller CABAS faktiska gränssnitt.
En uppfunnen endpoint som ser färdig ut är sämre än en tom: den ser ut
att fungera tills någon försöker.

Därför ett profildrivet gränssnitt. En profil beskriver vad en KATEGORI
av system förväntar sig, och märks validated först efter att den körts
mot leverantören. Tills dess står den som draft, och det syns i
gränssnittet — en integrationslista där allt ser färdigt ut är den
snabbaste vägen till ett misslyckat införande, eftersom verkstaden
planerar efter den.

Kategorier: diagnosprotokoll, DMS, videooffert, fordonsdata,
skadekalkyl (CABAS är nordisk standard), garanti och försäkring.

Skadekalkyl går åt båda håll. Det ALVA tillför en kalkyl är inte fler
poster utan beviskedjan bakom dem: vad som kontrollerades, vad som
uteslöts och varför. Det är den enda del av en kalkyl som i dag inte går
att granska i efterhand.

Inkommande protokoll blir evidens, inte bilagor, med härkomsten bevarad
i varje post — ett värde som kommit utifrån får aldrig se ut som något
teknikern själv mätt. Saknas instrumentets identitet nedgraderas värdet
till E1 enligt samma regel som gäller manuella mätningar.

Utgående leveranser signeras med HMAC över tidsstämpel och kropp;
tidsstämpeln ligger inne i signaturen så en fångad leverans inte går att
spela upp i morgon. Verifieringsfunktionen exporteras så mottagaren kan
använda exakt samma kod — de flesta integrationsfel uppstår i glappet
mellan två implementationer av samma signatur.

Prenumerationer går genom samma SSRF-gräns som leverantörsuppslagen, och
leverans sker efter att loggen skrivits: en mottagare ska aldrig kunna
se en händelse som inte finns i loggen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 15:51:30 +00:00
Claude 01189ae42a ALVA-RULE-200: ett ärende stängs aldrig utan ett varför
Kravet är enkelt att formulera och lätt att bygga fel. En obligatorisk
fritextruta blir "klart" på tredje ärendet, och då har vi bara gjort
dokumentationen långsammare utan att göra den bättre.

Därför fyra frågor med olika adressat i stället för ett fält:

  MOTIVERING   Varför följer slutsatsen av evidensen? Detta är raden som
               saknas i varje verkstadsprotokoll. Underlaget säger vad
               som mättes, slutsatsen vad som är fel — ingenting säger
               varför det ena medför det andra, och det är precis det
               steget en försäkringsbedömare granskar.
  UTESLUTET    Vad övervägdes och varför föll det bort?
  ÅTGÄRDSVAL   Varför denna åtgärd och inte en annan?
  KVARSTÅENDE  Vad är fortfarande osäkert? Får vara "inget" — men aktivt.

Kvalitetsgranskningen är riktad mot hur någon med bråttom faktiskt
skriver: en katalog över icke-svar (klart, åtgärdat, trasig, se ovan,
vet ej), minsta längd, och kravet att texten bär ett orsakssamband eller
refererar konkret evidens. Den som skriver "12,4 V vid stift 14"
hänvisar till en mätning utan att säga ordet — regeln får inte tvinga
fram ett språkbruk som inte är teknikerns.

Den regel som gör underlaget användbart för ett försäkringsbolag härleds
ur loggen: en hypotes som dokumenterats och inte blivit slutsatsen MÅSTE
bemötas. Utan den är en felsökning en gissning som råkade stämma.

Den ärliga vägen finns: orsaken kunde inte fastställas är ett giltigt
utfall, ofta mer användbart än en påhittad orsak — men varför den inte
kunde det är fortfarande ett varför.

Slutsatsen är kunddelbar. Den besvarar "varför kostade det här vad det
kostade" och är den enda rad en bedömare behöver. Att bygga funktionen
och sedan hålla den intern vore att bygga den förgäves.

I gränssnittet granskas fälten medan man skriver, inte efter Spara, och
obemötta hypoteser listas — teknikern ska aldrig behöva gissa vad som
fattas. Det är skillnaden mellan ett krav som respekteras och ett som
kringgås.

---

Typkontrollen avslöjade under arbetet en riktig bugg i mitt eget
grindarbete: schemat och grinden skrevs mot antagna fältnamn i stället
för mot domänmodellen. atgard_utford heter beskrivning och utford, inte
text. Följden var värre än ett typfel — grinden såg utförd åtgärd som
utebliven och krävde därför aldrig kundbesked eller kvalitetskontroll.
Det syntes inte, eftersom testfixturerna hade samma antagande.

Rättat i schema, grind och fixturer, och låst av två nya test: varje
fält i schemat måste finnas i domänmodellen, och varje händelse
demoärendet producerar måste passera serverns validering. Ett schema som
avvisar riktig trafik är värre än inget schema.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 15:20:27 +00:00
Claude baa5288add ALVA-modellen synlig i guiden
Fasindikatorn ovanför metodikpanelen: var i metoden arbetet befinner
sig, vilken fas det aktuella steget hör till, och vad fasen uttryckligen
inte gör.

Fasen härleds ur steget via den delade klassificeringen, så indikatorn
kan aldrig visa något annat än vad metodiken faktiskt gör. En indikator
som sätts separat blir förr eller senare fel, och då är den värre än
ingen — den påstår att arbetet är i verifiering när det fortfarande
lokaliserar.

Ärendets beteckning står i samma rad. Ett id ur loggen är en
ogenomskinlig sträng; ALVA-CASE-00007 är det som sägs i telefon och
skrivs i ett protokoll.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 14:59:45 +00:00
Claude a8fdc9ebcc ALVA: webbplats, portal och kunskapskällor
Webbplatsen och plattformen är ett system. Samma komponentbibliotek,
samma rutnät, samma ord — besökaren lämnar aldrig marknadswebben när den
loggar in, eftersom den inte gör det. När apparna kommer återanvänder de
samma bibliotek.

Det som saknas på startsidan är lika avsiktligt som det som finns: ingen
hjältebild, ingen gradient, ingen animation, inga kundlogotyper, ingen
uppmaning att boka demo. En sida som försöker övertyga läser som
marknadsföring; en sida som redovisar läser som dokumentation. Den
senare är vad en teknisk chef fattar beslut utifrån.

Kunskapskällorna är byggda som Operational Knowledge Infrastructure:
leverantörsoberoende gränssnitt där organisationen ansluter det den har
licens till. Det gör att produkten aldrig behöver marknadsföras med "vi
stödjer X". En betainstallation fungerar på enbart egna dokument.

Livscykeln har fem tillstånd med avsikt. Configured och Connected är
inte samma sak — en nyckel kan vara ifylld och ändå fel — och Validated
skiljer sig från Connected: anslutningen svarar, men har den data för de
fordon organisationen faktiskt arbetar med? Det är den frågan som avgör
om källan är till nytta.

Portalens nyckeltal visas som NOT APPLICABLE i stället för som tomma
grafer. Att visa noll vore att lova något som inte finns; att dölja
raderna vore att dölja riktningen.

Ett test läser den faktiska källkoden och låser disciplinen: inga
gradienter, ingen animation, inga emojier utanför ✓ ○ □ →, ingen färg
utanför paletten, inga marknadsföringsord. Ett designsystem som bara
finns i ett dokument blir urvattnat på tredje sidan någon lägger till.

Testet avslöjade att min egen kod använde py-3 — 12 px — och alltså bröt
8 px-rutnätet på sju ställen. Jag rättade koden, inte testet. Ett rutnät
med undantag är inget rutnät.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 14:01:24 +00:00
Claude 610bb9eca6 ALVA: metoden i kod — faser, nomenklatur, statusspråk, komponenter
ALVA är inte en omdöpning utan en annan produktklass. Skillnaden mellan
en assistent och en metod är att metoden går att granska, och därför
ligger den i kod och i test, inte i marknadsföringen.

Språkgränsen är den bärande avgränsningen: ALVA:s STRUKTUR är engelsk
och oföränderlig — fasnamn, statusord, dokumenttyper, identifierare
skrivs likadant i varje land, precis som DIN 2014 heter DIN 2014 på
svenska. ALVA:s INNEHÅLL är på arbetsspråket: frågan till teknikern och
kontrollpunktens text är svenska i en svensk verkstad. Att översätta
VERIFICATION till Verifiering hade gjort ALVA till ett ord för samma sak
i varje land i stället för samma sak i varje land.

Faserna är tillämpade på metodikbiblioteket, inte påklistrade: alla 31
steg-id i de 16 metodikerna är klassificerade i data. Gränsen mellan L
och V är den enda svåra och bär hela metoden — att mäta spänning vid en
komponent avgränsar var felet finns, att mäta spänningsfall under last
fastställer varför. Regeln: ett steg är Verification när det kan avfärda
en kandidatorsak.

Ett test kräver att faserna kommer i ALVA-ordning inom varje metodik. Ett
annat slår fast att en metodik inte behöver innehålla alla fyra —
läckagemetodiken slutar med lokalisering, och att fylla ut modellen med
ett konstruerat Action-steg hade varit att tillämpa den slarvigt.

Statusspråket är en uttömmande katalog, låst av test: inga utropstecken,
inget tilltal, varje rad slutar med punkt. Bedömning uttrycks som ett tal
— Confidence level: 92% — aldrig som Jag tror. Skillnaden är produktens
existensberättigande: det ena är en person som gissar, det andra ett
mätvärde som går att ifrågasätta.

Komponentbiblioteket är ett, för både webbplats och portal. 8 px-rutnät
utan undantag, nästan monokromt, ALVA Blue bara för aktivt steg och
verifierad status. Fyra ikoner: ✓ ○ □ →. Ingen animation — rörelse som
inte bär information är brus i ett utrymme där teknikern redan har för
mycket.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 13:55:15 +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 fbc034a280 Revisionen: C-3, C-4, M-1, M-4, M-5, M-6, m-3, m-5 och m-7 åtgärdade
C-3 · Dataskydd genom krypto-shredding. Identifierande fält krypteras
med en nyckel per ärende; radering sker genom att nyckeln förstörs.
Loggen förblir intakt och hashverifierbar — det som blir oåtkomligt är
identifieringen, inte protokollet över vad som kontrollerades. Ett
raderat ärende visar fortfarande att lufttrycket mättes till 2,4 bar
klockan 08:42, bara inte längre vems bil det gällde.

Vad som inte krypteras är lika viktigt: mätvärden, observationer och
kontrollresultat är verksamhetsdata. Krypteras allt raderas beviset
tillsammans med personuppgiften.

En raderingsbegäran gäller ett fordon, inte ett ärende — men
identifieraren är krypterad och går inte att söka på. Därför ett blindat
index: HMAC av den normaliserade identifieraren, samma fordon ger alltid
samma värde, värdet går inte att vända tillbaka utan nyckeln.

Gallringsdatum sätts vid avslut utifrån ärendetypen. Ett ärende utan
datum gallras aldrig — för tidig gallring går inte att ångra.

C-4 · Modellanropen kan stängas av per organisation. Flaggan bärs i
token så orkestern kan neka utan databasåtkomst. Metodikmotorn fungerar
ensam; en verkstad som inte kan acceptera överföringen till
modelleverantören kan ändå använda produkten.

M-1 · Mätvärden bär vilket mätdon som användes och när det var
kalibrerat. Utan spårbart instrument nedgraderas värdet från E4 till E1
— det är teknikerns observation av en siffra, inte en mätning.
Kalibreringen bedöms vid mättillfället, inte i dag. Demoärendet fick
kalibrerade instrument: det ska visa den praxis produkten kräver.

M-4 · Läslogg. Varje skrivning loggades redan; ingen läsning gjorde det.
M-5 · Återställningstest i CI. Larmet visade att backup sker, inte att
den går att återställa. Testet kontrollerar det som faktiskt brukar
tappas: att append-only-triggarna följde med och fortfarande biter.
M-6 · Regelpaketet verifieras mot HMAC. Ogiltig signatur spärrar avslut;
saknad nyckel ger granskningsläge i stället för driftavbrott — det är så
säkerhetsfunktioner blir avstängda.
m-3 · EXIF-borttagningen är nu avsiktlig och låst av test. Den höll av
en slump, och en ändring i stil med "bevara originalkvaliteten" hade
tyst börjat publicera var kundens bil stod.
m-5 · SBOM och sårbarhetsskanning i CI.
m-7 · Promptversionen binds till varje svar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 13:44:37 +00:00
Claude e73decd3f5 Revisionen: C-1, C-2, M-2, M-3, m-1 och m-2 åtgärdade
De fyra fynd som underminerade bevisvärdet sitter i samma kodväg och
åtgärdas därför tillsammans.

C-1 · Härkomsten sätts av servern. anvandare kommer ur den verifierade
token och tidpunkt ur serverns klocka. Klientens tidsstämpel kastas inte
— vid offline-arbete är den det enda som finns — utan bevaras som
registrerad_tidpunkt bredvid mottagningstiden, så glappet blir synligt i
stället för osynligt.

C-2 · Kvalitetsgrinden flyttad till services/gemensam/grind.mjs och
utvärderas nu på servern vid arende_avslutat. Ett avslut som inte
passerar får 409 med de faktiska hindren. Metodikdatan flyttades till
services/gemensam/metodiker.mjs och klientens metodiker.ts är en typad
återexport, så det finns fortfarande exakt en sanning.

M-2 · Högvoltsspärren är ett hinder. Ett nekande svar på behörighets-
eller spänningsfrihetsfrågan stoppar metodiken i stället för att räknas
som besvarad, och spärrar avslutet på servern. Ett obesvarat
säkerhetskrav spärrar också — tystnad är inte ett ja. Reglerna ligger i
data så nästa farliga metodik bara behöver en rad.

M-3 · Händelser valideras mot schema före skrivning. Loggen är
append-only, så en felaktig post kan aldrig rättas — kontrollen måste
ske innan, efteråt är det för sent för alltid. Okänd typ avvisas.

m-1 · Delningskoden använder förkastningsurval i stället för modulo.
m-2 · Id-kollisioner räknas i stället för att passera tyst.

21 nya tester låser varje regel. Ett skräddarsytt test kräver dessutom
att varje typ i händelseschemat är klassificerad i delningslistan — en
ny typ kan alltså varken läcka eller tappas bort.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-05 13:32:00 +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