c334786bb30347e49386c7223de613e3ee348b7e
19 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6665004ec7 |
Härdning: kedjesvep i drift — och svepets första egna fynd
KEDJESVEPET. Verifieringen fanns men anropades bara vid tvist: ett brott kunde stå oupptäckt i åratal och upptäckas i sämsta tänkbara ögonblick. Nu går driften igenom varje kedja och varje försegling i varje organisation — POST /api/kedjesvep för arbetsledaren, `node server.mjs --kedjesvep` för nattlig cron utan server, med felkod vid brott så att larmet är gratis. Endpoint och svep delar EN implementation (kedjestatus): två implementationer av "är kedjan hel?" kommer att svara olika den dag det betyder något — det var T-13/T-14:s rot, tillämpad i förebyggande syfte. SVEPETS FÖRSTA FYND VAR PÅ RIKTIGT. Första körningen mot integrationsmiljön rapporterade TRE brott där testerna saboterat två. Det tredje var en bugg: leverantörshändelser bär `enhet: undefined`, och den kanoniska formen serialiserade nyckeln som null medan databasens rundresa släpper den. Skriv-digest och läs-digest skilde sig — varje leverantörshändelse bröt sin egen kedjelänk. Klienthändelser gick fria av en slump: JSON.parse kan inte producera undefined. Fixat vid roten: kanonisk form är nu exakt den form som överlever rundresan, inte en nästan likadan. Mekanismen fungerade precis som avsett — dag ett, mot sina egna upphovsmän. TRANSPORTEN. Säkerhetshuvuden på varje API-svar: nosniff, no-store (ett API vars svar är personuppgifter får inte bli en cacheträff), frame-ancestors 'none', no-referrer, HSTS. För stor kropp svarar 413 i stället för ett intetsägande 500. Kroppstak 4 MiB och batchtak 500 verifierade som redan på plats — bokfört, inte antaget. En skriptläxa på vägen: cron-svepets felkod är själva poängen, men under `set -e` dödade den testskriptet vid tilldelningen — felkoden måste fångas i samma andetag. Utgåva 3.4. API-specen dokumenterar svepet. TÜV-2-rapporten har bilaga A med samma-dags-härdningen, inklusive svepets eget fynd. 768 enhetstester, 224 integrationskontroller mot riktig Postgres, återställningsprov, genomgång 4/4, portalspärr, typkontroll och lint. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt |
||
|
|
c1c56e60b5 |
TÜV-revision 2: fyra nya fynd — två Major med samma rot
Uppföljning först: alla tolv fynd från första ronden omprövade utan regression. T-4 noteras med gillande — gallringen förstör nycklar, inte rader, och kolliderar därför varken med append-only-triggarna eller den nya kedjan. Mekanismerna komponerar utan specialfall. T-13, MAJOR. Säkerhetstaket räknade varje mätvärde med matdonId som spårbart. Registeruppslaget härleder kalibreringsdatumet men stämplade aldrig OM kalibreringen gällde vid mottagandet. Ett instrument vars kalibrering gick ut 2019 kunde alltså bära taket "hög" — samtidigt som evidensmodellen graderar samma mätning E1, "kalibrering saknas eller utgången". Systemets två omdömen om samma faktum motsade varandra, och det generösare styrde grinden. Den uppenbara fixen — jämföra datumet mot klockan vid grindprövning — är fel: samma logg ska ge samma utfall om tio år. Faktumet fryses i stället när det fortfarande är ett faktum: mätdonsFakta stämplar kalibreradVidMatning vid mottagandet, taket kräver stämpeln, och klientens eget påstående skrivs alltid över. Strikt bakåt: ett ostämplat mätvärde räknas inte — det som inte kan styrkas bär inte hög. T-14, MAJOR. Leverantörsprotokollet gick förbi mätdonsregistret. T-2 stängde teknikerns väg; en leverantörsprofil kunde fortfarande stämpla in vilket matdonId som helst — T-2 återuppstånden genom sidodörren, och efter T-13 hade det opverifierade påståendet dessutom matat taket. Granskarens mönsternotering: kontrollen infördes vid grinden där fyndet gjordes, inte vid resursen den skyddar — andra gången i kodbasen (grinden själv var en gång enbart klient). Åtgärd: varje protokollmätvärde passerar registret. Okänt instrument NEDGRADERAS i stället för att avvisas — en webhook kan inte registrera instrumentet på plats, och att kasta evidensen vore värre än att gradera den ärligt. Värdet behålls, matdonspåståendena stryks, nedgraderingen redovisas i svaret. T-15, minor. Oförseglad drift syntes bara som en loggrad per avslut. Nu varnar tjänsten vid start — en rad vid boot är ett beslut någon fattat, en rad per avslut är brus — och miljövariabeln är dokumenterad. T-16, minor. Återställningsprovet var skrivet före kedjan: det bevisade att rader överlever en dump, ingenting om sekvens, kedjehash eller försegling — en backup som tappar kedjan återställer en logg som aldrig mer verifierar. Provet var grönt medan det mätte fel sak, vilket första ronden två gånger utpekade som den farligaste sortens grönt. Utökat: länkar, ordning och försegling överlever, och omförsegling avvisas även i den återställda databasen. Under arbetet: en sökväg i patchskriptet matchade aldrig därför att avtryckets avskiljare är NUL-bytes — ersättningen rapporterade ok utan att ha gjort något, och bara integrationstestet avslöjade det. Fixen applicerades om med assert på träff. Samma läxa som T-16, i verktygen. 768 enhetstester, 213 integrationskontroller, återställningsprov, genomgång 4/4, typkontroll, lint gröna. docs/TUV-AUDIT-2.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt |
||
|
|
0941e53c50 |
Revision 3: härdningen granskad — fyra fynd i en dag gammal kod, alla åtgärdade
Revisionens föremål är hashkedjan, förseglingen och säkerhetstaket från igår. Skälet att granska det nyaste först: det farligaste ögonblicket för en skyddsmekanism är veckan efter att den byggts, när testerna är skrivna av samma person som skrev mekanismen och provar samma antaganden. K-1, KRITISK. Förseglingen larmade falskt i normal drift. Offline-synk kan lämna in händelser EFTER att ärendet stängts — en sen bild, ett sent kundbesked — och verifieringen jämförde förseglingens rot med kedjans NUVARANDE rot. Varje legitim efterhändelse gav OGILTIG. Reproducerad i integrationsmiljön innan den kallades fynd. En verifiering som larmar falskt avfärdas snart som trasig, och därefter avfärdas även de äkta larmen — falsklarmet är inte en mindre bugg i ett skydd, det är det som dödar skyddet. Åtgärd: förseglingen täcker sitt PREFIX. Den förseglade roten ska vara en länk i den omräknade kedjan; det som kom efter redovisas öppet i `efterForsegling` i stället för att smittas eller smitta. Motvikten är prövad: sabotage INUTI prefixet fäller fortfarande både kedjan och förseglingen — annars vore "täcker sitt prefix" bara ett artigare ord för "täcker ingenting". m-1. Kedjelänken vilade på ett tidsformat som garanterades tre filer bort. Inte utlösbart i dag — alla vägar går genom tillPost — men första nya skrivväg utan millisekunder hade gett en kedja som aldrig verifierar. Normaliseringen bor nu i skrivKedjat, i samma uttryck som länken och databasraden får den ur. m-2. Protokollvägens skrivna/dubbletter räknades med två count(*) runt anropet; en samtidig skrivning från någon annan hamnade i vår siffra. skrivKedjat returnerar nu räkningen ur transaktionen som gjorde jobbet. m-3. Läsordning och kedjeordning var två ordningar. Kedjan ordnas av sekvens; GET, grinden och delningsvyn sorterade på tidpunkt och id — inom en batch kunde id:ts bokstavsordning avgöra vilken händelse som var "senast". Alla läsvägar sorterar nu i kedjeordning. Granskat utan anmärkning, bokfört så nästa revision vet att "hittade inget" betyder "letade": numerisk rundresa genom jsonb (provad med 1e-7 och 0.10000000000000009, inte antagen), dubbletter flyttar inte kedjan, krypto-shredding mot kedjan, signaturens serverägdhet, takets monotoni. Mönstret i alla fyra fynd är detsamma och står i rapporten: testerna som skrevs med mekanismen provade manipulation, som är det man tänker på när man bygger ett skydd. Det som gick sönder var normal drift — sen synk, samtidiga grannar, en batch i samma millisekund. Skydd fallerar oftare genom att larma falskt än genom att missa angrepp. 766 tester, 206 integrationskontroller, genomgång 4/4, portalspärr, typkontroll, lint och artefaktmätning gröna. API-specen dokumenterar prefixsemantiken och efterForsegling. docs/QUALITY-AUDIT-3.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt |
||
|
|
1ba5aaaefa |
Härdning efter panelgranskningen: kedjad logg, förseglat avslut, härledd säkerhetsnivå
Fyra av granskningens fynd åtgärdade, i bevisvärdesordning. HASHKEDJAN (ALVA-SPEC-070). Triggrar skyddar loggen mot applikationen, inte mot den som äger databasen — det var granskningens allvarligaste invändning mot ett system vars hela värde är bevisvärde. Varje händelse bär nu en hash av sitt innehåll och föregående händelses hash, beräknad av servern vid insättningen. All skrivning går genom en enda kedjande funktion; en händelse vid sidan av kedjan är ett hål i beviset, så den bekväma vägen förbi finns inte. Digest tas över den LAGRADE händelsen, efter kryptering: verifieringen ska kunna räkna om den ur databasen för all framtid, och krypto-shredding förstör nycklar, inte rader, så kedjan överlever en radering. Radlås per ärende hindrar att två samtidiga batchar forkar kedjan — en falsk larmande verifiering avfärdas snart som trasig, och då är den värdelös. Integrationstestet provar hotmodellen ordagrant: triggern släpps, en rad ändras med full databasbehörighet, triggern återskapas. Verifieringen pekar ut raden — inte bara att något är fel, utan vilken. FÖRSEGLINGEN. Avslut skriver kedjans rot och en HMAC med en nyckel som aldrig finns i databasen, i samma transaktion som avslutshändelsen. Den som räknar om hela kedjan efter sin ändring stoppas av att förseglingen inte går att räkna om utan nyckeln. Engångs: triggern vägrar ändra en satt försegling. Svaret säger vad det bevisar och inte — innehållet är oförändrat sedan mottagandet, ingenting om tiden före, ingenting om sanningshalten. Den texten följer med in i varje rapport som citerar svaret, för det är precis den skillnad en motpartsjurist annars hittar. SIGNATUREN. Fältet hette signatur men var teknikerns egen text — det inbjöd en jurist att tro något som inte gällde. Det skrivs nu ur verifierad token som övriga härkomstfält och intygar exakt vad det kan intyga: vem som var inloggad när avslutet togs emot. SÄKERHETSNIVÅN (ALVA-SPEC-071). Var teknikerns fria val — ett självskattat värde som ser ut som en mätning. Nu ett tak härlett ur underlaget: hög kräver reproducerat symptom OCH spårbart mätvärde ur mätdonsregistret; enbart observationer bär inte ens medel. Teknikern kan sänka men aldrig höja — asymmetrin är poängen, ärlig osäkerhet är information. Grinden spärrar påståenden över taket på alla tio språken, och gränssnittet visar taket medan arbetet pågår i stället för att spara beskedet till avslutsknappen. "Delvis reproducerat" bär inte hög: delvis är ett annat ord för att felet inte är förstått. Taket bet direkt i två av våra egna testfixturer som påstod hög utan spårbart mätdon — vilket är regeln som fungerar, inte testet som är fel. Genomgången avslöjade följdkravet: vid medel/låg kräver panelen att teknikern anger vilka ytterligare kontroller som skulle stärka bedömningen, och det fältet fylls nu i som en tekniker skulle. Kvar ur granskningens lista, medvetet: extern förankring (RFC 3161), klienthashat foto vid upptagning, gränsvärden som data, OIDC/SAML. 766 tester, 200 integrationskontroller mot riktig Postgres — inklusive sabotage som databasägare — genomgång 4/4, portalspärr, typkontroll, lint och artefaktmätning gröna. Utgåva 3.3, API-specen uppdaterad, åtgärderna bokförda i panelrapportens bilaga A. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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
|
||
|
|
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
|
||
|
|
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
|
||
|
|
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 |
||
|
|
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 |
||
|
|
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
|
||
|
|
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
|
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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
|