Modelltest:femton språkmodeller mot två av våra egna arkitekturproblem
Vi testade inte modellerna på en benchmark. Vi gav dem två problem vi faktiskt står inför, där vi redan hade en egen lösning att jämföra mot. Varje modell fick exakt samma text och fick aldrig se någon annans svar. Facit skrevs innan svaren lästes, och en enda rättare gick igenom allihop — annars mäter man rättarens humör i stället för modellen.
Varje modell är ett intervall av resultat, inte en punkt
Samma modell ger olika resultat på olika problem. Bandet visar hur långt en modells två utfall ligger isär; snittet är bara mittpunkten mellan dem. Störst spridning: GPT-5.6 luna, 20% mellan sitt sämsta och sitt bästa utfall. En rangordning som byggs på snittet döljer precis det.
Utanför rangordningen: GPT-6 (webb, omätt identitet) (OpenAI, flaggskepp) · Claude Fable 5.1 High (Anthropic, annan prompt) · Muse Spark 1.3 XHigh (Meta, granskare) — deltog inte i provet.
Priset skiljer 64 gånger. Kvaliteten 2,1.
Frågan är därför inte vilken modell som är bäst, utan vad merpriset ger. Vågrätt: uppmätt styckkostnad per körning, logaritmiskt. Lodrätt: andel av facit. Uppe till vänster är billigt och träffsäkert.
Utan mätbar styckkostnad: Grok 4.7 XHigh · Claude Opus 5 · Grok 4.6 · Grok (budget) · GLM 5.3 Thinking · Nemotron 3 Ultra — abonnemang, webbgränssnitt eller ospårad taxa. De saknas i diagrammet, inte i provet.
Två riktiga problem, inte en benchmark
Varje utmaning är ett arkitekturproblem vi faktiskt står inför, med en lösning vi redan hade. Facit skrevs innan svaren lästes. Välj en utmaning för att se profilerna, facitmatrisen och fynden.
Robert kör 10–15 AI-sessioner samtidigt i samma kodbas. De vet ingenting om varandra. Två av dem har redan redigerat samma filer parallellt och skrivit över varandras arbete — det tog en hel dag att förstå vad som hade hänt. Vi har ett verktyg som kan reservera filer, men det måste startas för hand, och därför används det aldrig: en enda reservation var öppen mot 15 körande sessioner. Modellerna fick vår föreslagna lösning — kör en automatisk kontroll vid sessionsstart — och ombads granska den.
Lösningen är inte förbättringsbar, den är felställd. Vid sessionsstart vet ingen vilka filer sessionen kommer att röra — uppgiften är inte formulerad än. En modell som bara förbättrar starthooken har missat provet. En som säger att hookpunkten är fel har klarat det.
Profilen, inte summan
- T1 · GrundfeletSer modellen att uppgiften är felställd? (2 rader)
- T2 · LivscykelVad händer när en session dör utan att städa upp? (2 rader)
- T3 · TystnadMärks det när skyddet inte fungerar? (2 rader)
- T4 · SamtidighetVad går sönder när 15 sessioner gör samma sak samtidigt? (3 rader)
- T5 · TäckningshålVad kan smita förbi skyddet? (4 rader)
- T6 · Praktisk driftHåller lösningen i verkligheten? (4 rader)
Alla radarer har samma orientering, så formerna går att jämföra direkt. Under varje: + modellens starkaste dimension, − dess svagaste.
Vilka rader som faktiskt skiljer
| GPT-6 Astra | GPT-5.6 sol | GPT-6 Sol | Grok 4.6 | Claude Opus 5 | GLM 5.3 Thinking | GPT-6 Luna | DeepSeek Flash | GPT-5.6 luna | Gemini 3.1 Pro | DeepSeek V4-Pro | Nemotron 3 Ultra | Gemini 3.8 Flash | Grok (budget) | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 17 | Verktyget ägs av någon annan — v1 rör det inteT6 · insider, räknas ej | 1/14 | ||||||||||||||
| 12 | PID-bindning som grund för städningT2 | 2/14 | ||||||||||||||
| 10 | Mätetalet: täckningsgrad, inte antal öppna banorT3 | 3/14 | ||||||||||||||
| 15 | Thundering herd: 15 starter ger 15 processerT4 | 3/14 | ||||||||||||||
| 7 | Git-worktree per session — fysisk separation slår bokföringT5 | 4/14 | ||||||||||||||
| 6 | Uppstart fail-open, men mutation fail-closed — olika kravT6 | 5/14 | ||||||||||||||
| 11 | Delad tillståndsfil korrumperas vid samtidiga skrivareT4 | 5/14 | ||||||||||||||
| 16 | Prestandan mätt, inte antagenT6 | 5/14 | ||||||||||||||
| 13 | Flaskhalsfiler köar och dödar parallellitetenT6 | 6/14 | ||||||||||||||
| 9 | Deploy behöver ett eget låsT5 | 8/14 | ||||||||||||||
| 14 | Agenten kan strunta i instruktionen — promptskydd bristerT5 | 8/14 | ||||||||||||||
| 5 | TOCTOU-race: kontroll följd av registrering är inte atomärT4 | 11/14 | ||||||||||||||
| 2 | Registrera lat, vid första skrivningen, inte vid startT1 | 12/14 | ||||||||||||||
| 8 | Shell-mutationer går förbi filhookarT5 | 12/14 | ||||||||||||||
| 4 | Fail-open blir fail-silent — falsk trygghetT3 | 13/14 | ||||||||||||||
| 1 | Skrivmängden är okänd vid sessionsstart — fel hookpunktT1 | alla | ||||||||||||||
| 3 | Zombiebanor när sessionen dör utan att stängaT2 | alla |
Rad 17 räknas inte med. „Verktyget ägs av någon annan — v1 rör det inte“ — Kräver kunskap om vårt ägarskap som aldrig stod i prompten. Bara den som redan känner ekosystemet kan träffa raden. Den räknas inte i huvudpoängen.
Fynd utanför facit 27 st
Det värdefullaste en modell kan göra: se något som ingen annan såg och som inte stod på listan. Dessa ger inga poäng — de är därför den enda delen av testet som mäter något facit inte kan mäta. Peka på en rad för att stoppa den.Tryck på en rad för att stoppa den.
PRISMA-SCENARIOT: två agenter med disjunkta claims kör båda `npx prisma migrate dev` via Bash. Verktyget skriver en TREDJE, delad sökväg som ingen av dem reserverat. Ingen Write/Edit registreras, systemet tror det är säkert, och den ena migrationen skriver över den andra
Kommandot skriver packages/shared/prisma/schema.prisma … B committar sin version som skriver över A:s migration, deploy kör inkonsistent schema.
COMMITGRINDEN FÅR INTE FRÅGA EFTER LEVANDE BANOR. En död session blockerar då en levande gren, och merge blir beroende av timing och TTL. Använd ett varaktigt manifest per gren i stället
Att blockera på "annan öppen bana just nu" gör merge beroende av timing och 30 min TTL. Död session blockerar levande branch.
Hookpolicyn måste vara CENTRALT förvaltad, inte per-repo opt-in — agenten kan redigera både repots .claude/settings.json och ~/.claude
redigerbar `.claude/settings.json` per repo och `~/.claude` som agenten kan ändra gör B till friktion.
SessionStart-hookar KAN inte blockera — exit 2 gäller bara PreToolUse och Stop, och interaktiva sessioner kör SessionStart i bakgrunden. Halva den föreslagna lösningen var tekniskt omöjlig
på SessionStart fortsätter sessionen oavsett … den kan heller aldrig gated något.
Sessions-ID är inte stabilt över resume och clear — en reservation bunden till det blir en zombie i samma sekund
Session-ID är inte stabilt eller tillgängligt i hooken.
Filbaserade lås är inte atomära över en NFS- eller molnsynkad repo-rot — hela skyddet faller tyst på var katalogen ligger
Om claim inte är flock-atomär över NFS/iCloud-synkad repo-root.
Sokvagsnormalisering som last barande yta: symlankar och skiftlagesokanslighet gor att tva olika strangar kan peka pa SAMMA fil. Ingen facitrad tacker det, och det ar skarpt hos oss — macOS ar skiftlagesokansligt, VPS:en ar det inte, och banor uttrycks som globmonster.
Normalisera sokvagar, inklusive symlankar och skiftlagesregler.
Kedjan redovisas med var garantin SAKNAS, inte bara var den finns: upptäckt (ingen) → registrering (ingen) → enforcement (hård) → Bash-lucka → commit (hård)
upptäckt (ingen) → registrering (ingen) → enforcement B (hård för Write/Edit) → filändring (Bash-lucka) → commit C (hård lokalt)
FENCING-TOKEN vid reservation — skyddet mot en låshållare som dödförklarats men kommer tillbaka. Ingen annan modell nämnde det
Returnera fencing-token.
Bash-skrivningar kan aldrig HINDRAS utan sandbox eller proxy — bara sättas i KARANTÄN före nästa mutation eller commit. Ärlig gräns i stället för ett löfte
Bash kan bara ge karantän före nästa mutation/commit, aldrig hindra den lokala skrivningen utan sandbox/proxy.
exit 2-blockering har dokumenterade buggar där deny ignoreras för Edit — använd JSON permissionDecision deny med exit 0 i stället
exit 2-blockering har haft verifierade buggar där deny ignoreras för Edit
Konflikter utanför filsystemet — byggsteg, databasmigrationer, portar — fångas aldrig av filreservationer
Fil-lås löser inte runtime-/miljökrockar.
Muterande ytor utanför verktygets hookar: MCP-skrivningar, subagenter utan samma hookar, headless-läge
MCP-write, subagent utan samma hooks, editor utanför Claude Code, `claude -p` utan hooks.
Ett utgånget lease får INTE ensamt frigöra banan. Den gamla processen måste först förlora skrivbehörigheten — annars skriver den vidare parallellt med den nya ägaren. Facitrad 12 efterfrågar PID-städning; detta är invändningen mot att städning överhuvudtaget räcker.
Frigör inte en bana enbart för att heartbeat upphörde. Den gamla processen måste först förlora skrivbehörigheten, annars kan den fortsätta parallellt med den nya ägaren.
PostToolUse på Bash med git status --porcelain före och efter, och retroaktiv claim på det som ändrades — och ärligt om att det bara förkortar tiden till upptäckt, aldrig förhindrar
(1) förkortar bara tiden till upptäckt.
Delad arbetskopia delar .git/index.lock och ocommitterat tillstånd — PostToolUse läser då ett index andra redan smutsat, och kommer dessutom för sent
PostToolUse[Bash] kommer för sent och `git diff --cached` läser ett index andra redan smutsat.
Fällde sin egen design med vår egen mätning: föreslog 150 ms timeout och konstaterade sedan att den är för kort mot uppmätt p95 på 1,38 s
150 ms timeout är för kort på kallt lane.py-anrop (p95 1.38 s) → hooken "lyckas" men registrering misslyckas tyst.
Kommandohookar har 600 s standardtimeout — en hängd kontroll stoppar VARJE skrivning i tio minuter i alla femton sessioner
en hängad lane.py-check stoppar varje skrivning i 10 minuter i alla 15 sessioner
Delad .git-katalog: risken är index-korruption, inte bara filöverskrivning
Ingen mjukvarulåsning i världen skyddar fullt ut mot Git-index-korruption.
Kontrollen måste ha en latensbudget — en Python-CLI på 1,38 s får aldrig ligga i den heta vägen
Claim tar millisekunder; Python-CLI:n med 1,38 s får inte ligga i hot path.
Globtvetydighet ska tolkas fail-closed. Kan två mönsters överlapp inte bevisas vara tomt ska de behandlas som överlappande — annars blir varje osäker glob ett tyst klartecken.
Glob-mönster vars överlapp inte säkert kan uteslutas behandlas som överlappande.
core.hooksPath för central hookinstallation — konkret svar på hur man slipper per-repo opt-in över sexton projekt
Installerat centralt via core.hooksPath.
flock fungerar bara om alla sessioner delar värd. Över containers eller maskiner blir det split-brain med dubbelägande — och absolut sökväg bryts av worktrees
I olika containers/maskiner/CI får ni split-brain med dubbelägande.
lane.py open ska vara idempotent — no-op om banan redan finns. Liten detalj, men ingen annan modell sa det
Gör `lane.py open` till **no-op om lane redan finns** (idempotent).
SessionEnd har bara 1,5 s budget — stängning är best-effort, vilket gör TTL till bärande mekanism och inte kosmetik
TTL: bana utan heartbeat på 15 min dör automatiskt. Detta är kärnmekanismen, inte kosmetik.
Efterhandsrevision mot git diff som oberoende mätning — uttryckligen klassad som diagnostik, inte som skydd
Efterhandskontroll av `git diff` är endast diagnostik.
TTL-fönstret är en felkälla åt båda hållen — för kort dödförklarar en levande session och frigör dess filer mitt i arbetet
En agent som tänker i 50 minuter dödförklaras och dess filer blir fria.
Våra AI-agenter minns ingenting mellan sessioner. Allt de vet står i dokumentation som laddas in vid varje start och behandlas som sanning. Problemet är att dokumentationen åldras utan att ändra utseende. En tabell över produktnamn stod fel i fem månader, och en agent höll på att rätta en live kundsida till ett produktnamn som inte längre fanns — i god tro. En regel skrevs in i fyra filer över sex dagar utan att beteendet ändrades alls; en spärr i mjukvara löste samma sak på en eftermiddag. Och läsbekräftelser tar bort ärenden ur synfältet utan att de är gjorda.
Varje uppenbart svar är redan motbevisat med kvitto i prompten: mer dokumentation (402 filer finns redan), upprepning av regler (fyra försök, noll effekt), instrumentpaneler (110 olästa larm) och läsbekräftelser (producerar falskt grönt). Modellen måste komma med något som inte står på den listan.
Profilen, inte summan
- D1 · ProblemformuleringSer modellen mekanismen under symtomen? (3 rader)
- D2 · Kanon och reglerGörs text till en exekverbar mekanism? (4 rader)
- D3 · ÅtagandenByggs 'lovat men inte gjort' bort? (4 rader)
- D4 · LarmBlir larm blockerande i stället för notiser? (3 rader)
- D5 · MätbarhetGår det att mäta att designen misslyckats? (5 rader)
- D6 · SkalningVad brister först vid 40 agenter? (3 rader)
Alla radarer har samma orientering, så formerna går att jämföra direkt. Under varje: + modellens starkaste dimension, − dess svagaste.
Vilka rader som faktiskt skiljer
| GPT-6 Astra | GPT-5.6 sol | GPT-6 Sol | Grok 4.7 XHigh | Claude Opus 5 | GLM 5.3 Thinking | GPT-6 Luna | GPT-5.6 luna | Grok 4.6 | Gemini 3.1 Pro | Gemini 3.8 Flash | DeepSeek Flash | Nemotron 3 Ultra | DeepSeek V4-Pro | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 19 | Mått på designens egen friktion och överblockeringD5 | 2/14 | ||||||||||||||
| 18 | Aktiv felinjektion som mätmetodD5 | 4/14 | ||||||||||||||
| 10 | Ett brev med fyra uppgifter blir fyra spårbara objektD3 | 5/14 | ||||||||||||||
| 20 | Brister först: verifierar- och policytäckningenD6 | 5/14 | ||||||||||||||
| 21 | Brister först: människans tidD6 | 5/14 | ||||||||||||||
| 14 | Övervakningen måste själv övervakasD4 | 6/14 | ||||||||||||||
| 16 | Förutsättningen är binär determinismD5 | 7/14 | ||||||||||||||
| 1 | Styrningen namnges som en öppen reglerloopD1 | 8/14 | ||||||||||||||
| 7 | Täckningsregel: ta bort, generera eller sätt en vaktD2 | 8/14 | ||||||||||||||
| 15 | Förutsättningen är bypass-frihetD5 | 8/14 | ||||||||||||||
| 22 | Vakterna själva bryter vid samtidighetD6 | 9/14 | ||||||||||||||
| 17 | Misslyckandemåttet är falskt grönt, mätt ur loggarD5 | 10/14 | ||||||||||||||
| 2 | Tre skilda kategorier lagras som samma auktoritativa textD1 | 11/14 | ||||||||||||||
| 6 | Motsägelser mellan regler fångas maskinelltD2 | 11/14 | ||||||||||||||
| 8 | Brev ersätts av arbetsobjekt i en tillståndsmaskinD3 | 11/14 | ||||||||||||||
| 11 | 'Lovat men inte gjort' får en explicit representationD3 | 11/14 | ||||||||||||||
| 13 | Upprepade larm dedupliceras till en incident med räknareD4 | 11/14 | ||||||||||||||
| 3 | Text saknar exekveringskraft; korrekthet får inte vila på prosaD1 | 12/14 | ||||||||||||||
| 4 | Kanon genereras ur verkligheten; overifierat exponeras inteD2 | 13/14 | ||||||||||||||
| 12 | Larm görs blockerande i stället för en notisD4 | 13/14 | ||||||||||||||
| 5 | Regler implementeras vid handlingsgränsen, som hookD2 | alla | ||||||||||||||
| 9 | Bara en oberoende maskinell verifierare får sätta klartD3 | alla |
Fynd utanför facit 31 st
Det värdefullaste en modell kan göra: se något som ingen annan såg och som inte stod på listan. Dessa ger inga poäng — de är därför den enda delen av testet som mäter något facit inte kan mäta. Peka på en rad för att stoppa den.Tryck på en rad för att stoppa den.
ÄVEN DEN PUBLIKA SIDAN KAN VARA FEL. Observationen får inte tyst skriva över avsikten — en avvikelse betyder att EN av dem är fel, inte att kanon är det
Kopiera inte automatiskt HTML till registret – även den publika sidan kan vara fel.
Ärlig gränsdragning: en hook kan inte avgöra vad en agent tänker eller säkert klassificera godtycklig text. Få modeller erkände mekanismens tak
Påstå inte att en hook kan avgöra vad en agent "tänker".
Spärrens omfattning måste vara SMAL — blockera den berörda handlingsklassen, inte hela produkten. En ägare överlever inte ett helproduktstopp och stänger då av mekanismen
blockera namnpublicering, inte allt arbete på produkten. En ägare överlever inte helproduktstopp.
En enda källfil blir en SKRIVFLASKHALS vid skala — 40 agenter som alla behöver uppdatera sanningen ger merge-konflikter på samma fil
`sources.yaml` blir enskild skrivflaska … skapar skrivkonflikter och merge-konflikter på *en* fil.
Brev utan definierbar sond RADERAS, arkiveras inte — ett ogiltigt ärende ska inte kunna återuppstå som arkeologi
saknar de definierbar sond märks de ogiltiga och rensas, inte arkiveras.
Skalningsgränsen är ägarens tid — systemet blir robust men förlorar rörligheten som var hela poängen
Ägaren kommer att spendera 100 % av sin tid med att skriva testskript.
Regelefterlevnad får en nämnare: träffar delat med matchande verktygsanrop — inte lästa filer
Mät efterlevnad som `gate_hits / matching_tool_calls`, inte som lästa filer.
Täckningskrav på loggningen själv: ett ologgat anrop räknas som en rymning
varje ologgat anrop räknas som escape
En binär på disk bevisar inte en fungerande tjänst — modellnamn måste kontrolleras mot ett verkligt anrop, inte mot en fil
modellnamn kontrolleras mot ett fungerande modellanrop, inte bara en fil på disk.
TAUTOLOGIHÅLET: en verifierare måste ha varit RÖD mot världen FÖRE arbetet. En som redan var grön, eller alltid är grön, bevisar ingenting när den säger grönt efteråt
Den gav exit 1 mot världen före arbetet. Annars bevisar den inget. … Alltid-grön verifierare, eller en som redan var grön, kan inte stänga.
Separation of duties i binären: den som utför får inte äga verifieraren eller ledgern, och stängning vägras om samma skrivare äger båda
En binär vägrar stängning om före-loggen saknas eller om samma skrivare äger båda.
Sondfel måste skiljas SEMANTISKT: infrastrukturfel (hämtningen gick inte) är inte samma sak som innehållsavvikelse (världen matchar inte kanon) — bara det senare får bli larm
infrastrukturfel (hämtningen misslyckades) returnerar annan status än innehållsavvikelse … bara det senare är ett larm.
Aktiv felinjektion som mätmetod, med noll tolerans
Tröskel för misslyckande: escape rate > 0 %.
Vakterna själva kapplöper vid skala; hastighetsgränser hos tredje part ger falska underkännanden
Agent A:s vakt underkänner en deploy för att Agent B just ändrade databasen millisekunden innan.
Vid rött byts raden inte bara ned — agenten får VÄRLDENS uppmätta värde i stället för tabellens
byts till `UNTRUSTED: <värde från världen>` … agenten får världsvärdet, inte den ruttna tabellen.
Tregradig status med konsumtionsspärr — agenter får bara läsa fält som är verified, aldrig unverified eller stale
Agenter får bara konsumera fält med status `verified`.
Noll fångade fel är bara ett godkänt prov om riktigt arbete faktiskt slutfördes under perioden — annars är provet ogiltigt, inte godkänt
Noll passerade fel när inga riktiga arbeten slutförts är ett ogiltigt prov, inte ett godkänt system.
Grinden måste köra som ANNAN OS-identitet. Samma användare plus skrivbara hookfiler är ingen grind — agenten har skal och kan redigera sin egen spärr
Samma användare och skrivbara hook-filer är ingen grind: Claude Code har skal.
OMVÄND KANARIE: för FÅ blockeringar är misslyckandesignalen. En vakt som aldrig utlöser går inte att skilja från en vakt som är avstängd — mät därför golvet, inte taket
Om `verify_block_rate` < 0,5% under 7 på varandra följande dagar → designen har misslyckats … Förväntat vid felfritt system: 2–5% blockeringar.
Röta är inte ett fel — det är standardtillståndet för en cache som aldrig invalideras. Dokumentation som inte ommäts ÄR trasig som utgångsläge
Röta är inte ett fel i systemet – det är standardtillståndet för en cache som aldrig invalideras.
Vem vaktar vakten — ett kontrolljobb som slutat köra är ett fel i sig
Övervakningen måste själv ha en watchdog.
Två motstridiga regler kraschar inte — de ger en TYST VINNARE, den som råkar matcha nästa verktygsanrop. Det förklarar varför 0,22 procent kunde uppstå utan att någon märkte något
Två motstridiga rader ger inte krasch; de ger en tyst vinnare.
Åldersstämplad nedgradering i renderingen i stället för radering — påståendet finns kvar men slutar vara auktoritet
OVERIFIERAT 47 DYGN — ANVÄND INTE SOM AUKTORITET
Vaktfärskhet som primärmått: andel vakter körda senaste dygnet under 95 procent = designen har misslyckats
om denna andel är under 95 % efter 30 dygn har designen misslyckats
Ett test som agenten själv nyss ändrat duger inte som bevis — tautologihålet, men via testmodifiering i stället för via en alltid-grön vakt
Agentens egen beskrivning eller ett test den själv just ändrat räcker inte.
Force-clear ÄR en bypass. Under brusiga orakel börjar ägaren rensa spärrar för hand, och då faller hela designen — inte på tekniken utan på den mänskliga utvägen
Ägaren börjar force-cleara. Force-clear är en bypass. Då faller punkt 3.
Verifiera före LÄSNING, inte bara före skrivning — annars kan agenten fortfarande resonera utifrån rutten kanon
anropar `verify.py` innan `Write`, `Edit`, `Bash`, `Task`, `Read` körs.
Falskt rött är farligare än falskt grönt: upprepade falska larm tränar alla att ignorera exit 1, och då finns ingenting kvar att stå på
När en gång exit 1 tappar auktoritet har ni inget kvar, eftersom hela designen står på att den signalen är helig.
Mått på designens egen friktion: uppgifter som fastnar i en loop av underkännanden
fastnar i IN_PROGRESS i mer än 48 timmar … överstiger 15 %
Vakten kan peka på FEL VÄRLD och returnera grönt — staging i stället för live, utan kanonisk URL-katalog per produkt
Job-acceptance som träffar 'publik sida' utan kanonisk URL-katalog per produkt blir fel värld, fel grönt.
Fail-closed som standardbeteende vid allt som är oklart — overifierat, utgånget, motsägelsefullt eller utan evidens
Om något är overifierat, utgånget, motsägelsefullt eller saknar evidens: fail closed.
Leverantörsmärkena är typografiska monogram, inte leverantörernas logotyper. Ingen leverantör står bakom detta test.