HolgerAIGrinden

Grinden

Varje text som en AI-agent vill skicka ut ur huset går genom den här grinden. Svenska personuppgifter stoppas med kontrollsiffra, datum och sammanhang som bevis, inte bara för att siffrorna råkar se rätt ut. Datum, belopp och fakturanummer släpps igenom.

Text

Alla nummer i exemplen är påhittade och räknas fram med rätt kontrollsiffra. Personnumren har födelseår efter 2040 eller är Skatteverkets testnummer, så de kan inte tillhöra någon.

Skyddade namn

Namn i listan är hårda träffar: texten stoppas. I drift läses listan från en fil som bara den lokala modellen får se. Här lever den i din flik tills du stänger den.

Dom


      

Träffar

    Liknade, men föll på kontrollen

      Det här får modellen

      
            

      Så ser agenten det

      Samma text som ett verktygsanrop i Claude Code. Kroken skickar anropet till grinden och stoppar med exit 2 om domen är stopp. Texten nedan är den agenten får läsa.

      Svaret från tjänsten, som JSON (index i kodpunkter, som i Python)
      …

      Självtestet körs.

      Texterna i självtestet

        Regelboken

        Tolv typer. Hårda typer stoppar ensamma. Mjuka typer stoppar först i mängd: fyra kontaktuppgifter i samma text, eller två kontaktuppgifter och fyra namn, ser ut som ett register. Säkerheten är den poäng Presidio får när reglerna körs i drift.

        TypKlassSå kontrolleras denSäkerhet
        PersonnummerhårdTio eller tolv siffror. Luhn över de sista tio, och datumet måste finnas. Fel kontrollsiffra eller 30 februari ger ingen träff.0,95
        SamordningsnummerhårdSom personnummer, men dagen är 61 till 91: dag plus 60. Datumet kontrolleras efter att 60 dragits av.0,95
        OrganisationsnummerhårdTio siffror, Luhn, och siffra tre och fyra minst 20. Under 20 är det en månad, alltså ett datum eller ett personnummer, inte ett bolag.0,90
        BankgirohårdSju eller åtta siffror med bindestreck och Luhn, och ordet bankgiro, bg eller bg-nr inom 28 tecken före. Samma nummer utan ordet är en referens.0,90
        PlusgirohårdTvå till åtta siffror med bindestreck och Luhn, och ordet plusgiro, pg eller postgiro inom 28 tecken före.0,90
        IBANhårdSE följt av 22 siffror, med eller utan mellanslag, stora eller små bokstäver. Hela numret flyttas om och måste ge rest 1 vid division med 97.0,98
        KontonummerhårdClearingnummer och 7 till 12 siffror, med ordet konto, kontonr, clearing eller clnr inom 28 tecken före. Ingen kontrollsiffra finns, så sammanhanget avgör.0,85
        KlientnamnhårdLista med skyddade namn, hela ord, skiftlägesokänslig, minst tre tecken, längsta namnet först. I drift läses listan från en fil; här från rutan ovan.0,99
        E-postmjuknamn@domän med minst en punkt i domänen. Stoppar bara i mängd.0,90
        TelefonmjukSvenskt format: 07x, 08 eller riktnummer, med eller utan +46, mellanslag och bindestreck. Stoppar bara i mängd.0,75
        AdressmjukGatunamn som slutar på gatan, vägen, gränd, torg, allé, leden och liknande, följt av ett nummer.0,80
        PostnummermjukTre siffror, mellanslag, två siffror och en ort med stor bokstav.0,70
        Namn (PERSON)mjukHittas inte i webbläsaren. I drift kommer namn från spaCy sv_core_news_md via Microsoft Presidio, med samma regler som här inlagda som en egen recognizer.0,50+

        Varför inte bara ett mönster?

        Ett regelverk som bara tittar på formen flaggar varje datum och fakturanummer, och missar svenska format helt. Mätt på 2 850 svenska affärsmeningar, hälften med en identifierare och hälften lockbeten som liknar en.

        0 %av identifierarna får rätt typ hos Presidio utan svenska regler. 78 % fångas, men som US_DRIVER_LICENSE eller PHONE_NUMBER.
        44 %av lockbetena flaggas av samma regler: varje datum, varje byggnummer. Med tröskel 0,5 försvinner bruset, och de svenska numren med det.
        100 % / 2,5 %svenska-pii fångar alla identifierare med rätt typ och flaggar 2,5 % av lockbetena, alla verkliga tvetydigheter. Hela mätningen

        Var den sitter

        Grinden är en lokal tjänst på min Mac, 127.0.0.1:4201. Tre saker går genom den: varje utgående verktygsanrop från Claude Code via en PreToolUse-krok, varje modellanrop via routern framför språkmodellerna, och texten till Gemini i en tjänst på Google Cloud Run. Stoppas något får jag en fråga i mobilen; ett ja gäller exakt det anropet, en gång, i 30 minuter.

        I drift kör samma regler inne i Microsoft Presidio tillsammans med spaCy-modellen sv_core_news_md, som hittar namn. Den delen finns inte i webbläsaren, så här hittas inga namn utom de du själv skyddar. Texter kapas vid 200 000 tecken, och skanningstiden mäts: p95 och p50 syns på Kontoret, tillsammans med antalet skanningar och stopp sedan 30 september.

        Den här sidan kör en JavaScript-version av reglerna. Den är testad mot Python-originalet på över 950 texter med samma träffar, dom och maskning, och självtestet ovan kör en del av dem i din webbläsare varje gång sidan laddas. Grinden är stängd som standard: svarar den inte, stoppas anropet. Ett kaosprov dödar den varje natt och kontrollerar att det stämmer, och resultatet publiceras.

        Vad den inte gör: hittar namn i webbläsaren, förstår andra länders identifierare, eller ser ett skript som agenten själv skriver och kör. Den sista luckan står i hotmodellen, tillsammans med vad som är gjort åt den. Postmortem från när en för kort tidsgräns gav tre falska stopp finns på plattformssidan.

        Samma grind sitter framför agenten som svarar på frågor om plattformen: fråga den något, eller försök skicka ett personnummer och se vad som händer.

        Reglerna är öppen källkod: svenska-pii (MIT), ren Python utan beroenden, med Presidio-recognizers som tillval. Godkännandet per anrop finns som agent-permit.