I juli 2026 skrev Robert C. Martin att han inte längre läser koden som produceras av hans kodningsagenter.
Uttalandet väckte stor uppmärksamhet. Resten av hans inlägg är viktigare för att förstå hur han arbetar. Martin omger agenterna med enhetstester, Gherkin-acceptanstester, QA-processer, mutationstester, täckningskontroller och kvalitetsmått. Koden förtjänar hans förtroende genom att passera genom det systemet.
Han hade gjort en liknande poäng några månader tidigare. Istället för att inspektera implementationen tittar han på testtäckning, beroendestruktur, cyklomatisk komplexitet, modulstorlek och mutationstestresultat. När folk tolkade detta som att han helt gav upp granskning, förtydligade han: "Jag granskar mycket — bara inte koden."
Hans kommentarer beskriver ett praktiskt problem i AI-tung mjukvaruutveckling. Kodningsagenter kan producera förändringar snabbare än människor kan läsa dem. När volymen av AI-genererad kod överstiger teamets granskningskapacitet kan rad-för-rad-inspektion inte längre vara den enda källan till förtroende.
Vi har hanterat samma problem på vm0 de senaste åtta månaderna. Större delen av implementationen i vårt repository skrivs av agenter — vibe-kodning, enligt det populära uttrycket — medan sex ingenjörer fortfarande är ansvariga för vad koden gör i produktion.
Den korta versionen
vm0 är en vibe-kodad kodbas: agenter skriver det mesta av implementationen, och sex ingenjörer äger vad den gör i produktion. Åtta månader in innehåller repositoryt 1,329,170 rader och har sammanslagit 630 pull requests på en vecka. Fem mekanismer bär kvalitetsbördan som rad-för-rad-granskning inte längre kan bära ensam.
- Konvergerade miljöer. Ingenjörer och agenter arbetar i samma utvecklingscontainer, och varje pull request kan få sin egen databasgren. Ett kommando som fungerade för en agent fungerar för en person.
- Exekverbara begränsningar. Strikt TypeScript, cirka 135 typade API-kontraktsmoduler, Oxlint, ESLint och arkitekturregler, med CI som inte accepterar några varningar. En regel som kan kontrolleras maskinellt lämnas inte till granskning.
- Gränsfokuserade tester. En testtrofé snarare än en testpyramid: integrationstester genom publika modulgränser, riktig PostgreSQL och riktiga migrationer, mockar endast vid externa system. Testkod utgör cirka 36 procent av repositoryt.
- Fullständiga återkopplingsslingor. Agenter startar applikationen och databasen, kör migrationer och styr en riktig webbläsare, rapporterar sedan kommandon de körde, vägen de testade och skärmdumpar. Den genomsnittliga pull requesten slås ihop på cirka 53 minuter.
- Kontinuerlig städning. Knip tar bort död kod deterministiskt, dagliga arbetsflöden rensar AI-rester som ingen linter kan namnge, och ett mönster som återkommer ofta nog blir en lintregel eller typbegränsning.
Vad vibe-kodning och agentisk kodning faktiskt betyder
Vibe-kodning är att ge en LLM en prompt för kod, köra vad den producerar, be om ändringar och inte bry sig om den genererade koden. Martin Fowlers definition är avsiktligt snäv, och han lyfter fram frasen "glöm att koden ens existerar." Det passar prototyper, engångsprogram och små verktyg med begränsade konsekvenser.
Agentisk kodning, som Fowler kallar agentic programming, är vad team gör när de förväntar sig att underhålla resultatet. En agent läser repositoryt, redigerar filer, kör tester och arbetar självständigt under en längre period, medan människor behåller ägarskap över struktur och beteende och granskar bevisen en körning producerar: testresultat, kvalitetssignaler, förhandsgranskningar och produktionsbeteende.
Skillnaden är inte hur mycket kod en modell skriver. Det handlar om var mänsklig uppmärksamhet läggs.
| Vibe-kodning | Agentisk kodning | |
|---|---|---|
| Agentens autonomi | Prompt, kör, prompt igen | Läser repositoryt, redigerar, testar, itererar |
| Vem läser koden | Ingen | Människor läser det som innebär risk |
| Vad som verifieras | Om utdata ser rätt ut | Typer, kontrakt, tester, förhandsgranskningar, produktionssignaler |
| Bäst lämpad för | Prototyper och engångsverktyg | Programvara med underhållshorisont |
| Typiskt fel | Kod ingen förstår | Verifiering för svag för volymen |
Agenter som redigerar ett repository är en gren av en bredare förändring; vi tittade på den icke-utvecklande sidan av det separat.
Vi kallar ofta vm0 ett vibe-kodat projekt eftersom det uttrycket blivit vanligt för programvara som huvudsakligen skrivs av AI. I Fowlers termer ligger det närmare agentisk kodning. Våra ingenjörer skriver mindre av implementationen än tidigare, men fortsätter att äga arkitektur, underhållskostnad och produktionsbeteende.
När kodgenerering blev snabbare flyttades mer av ansvaret till utvecklingsmiljön, typsystemet, testsuiten och automatiserade underhållsarbetsflöden.
Åtta månaders tillväxt i en vibe-kodad kodbas
vm0-repositoryt skapades i november 2025. Vid tiden för vår senaste veckorapport om ingenjörsskala var det ungefär åtta och en halv månad gammalt.
Repositoryt innehöll:
| Mätvärde | Antal |
|---|---|
| Icke-tomma logiska rader | 1,329,170 |
| Produktionsrader | 850,913 |
| Testrader | 478,257 |
| Källfiler | 5,549 |
| Testfiler | 1,327 |
| Paket | 44 |
| Commits på huvudgrenen | 14,005 |
Dessa siffror kommer från vår veckorapport för veckan den 20–26, 2026, mätt direkt från monorepot. Testkod utgjorde cirka 36 procent av den uppmätta kodbasen. Det är en andel av kodvolymen, inte en testtäckningssiffra, men ger en uppfattning om hur mycket implementation som ackumulerats kring verifiering.
Under tre nyligen genomförda hela veckor gjorde sex ingenjörer 541, 640 och 631 commits respektive. Under veckan den 20–26 registrerade GitHub 630 sammanslagna pull requests. Sex ingenjörer författade 556 av dem, medan release-automation författade resterande 74.
Medianen från öppning till sammanslagning av en pull request var cirka 53 minuter. 90:e percentilen var ungefär 7.4 timmar.
I denna förändringstakt är mänsklig granskning fortfarande användbar men kan inte bära hela kvalitetssystemet. Vi behöver oberoende signaler vid flera punkter i en förändrings livscykel.
Vår nuvarande metod har fem återkommande teman: konvergerande miljöer, exekverbara begränsningar, gränsfokuserade tester, fullständiga återkopplingsslingor och kontinuerlig städning.
Konvergera utvecklingsmiljön med dev-containrar
Många svårreproducerade fel beror på tillstånd som aldrig syns i en pull request.
En utvecklare kan ha en odokumenterad miljövariabel, ett globalt installerat verktyg, en gammal konfigurationsfil eller en databas som körts i månader. Människor vänjer sig vid dessa detaljer. Agenter ser dem oftast inte.
Vi slutade gradvis att behandla värddatorn som standardutvecklingsmiljö. Ingenjörer och agenter arbetar i en dev-container. Utvecklingsbilden inkluderar projektets verktygskedja, PostgreSQL, pgvector, Chromium och webbläsarautomationsverktyg.
CI kör versionerade verktygsbilder byggda från samma multi-stage Dockerfile-familj. Utvecklings- och CI-bilderna har olika syften, och produktion har sin egen distributionsform. Den användbara egenskapen är konvergens: verktygsversioner, beroenden och antaganden om körmiljö är explicita och versionshanterade.
Detta ger oss en tydlig förväntan. Kommandon som en agent kör ska kunna reproduceras av en ingenjör i samma utvecklingscontainer. Kontroller som passerar under utveckling ska köras under en närbesläktad verktygskedja i CI.
Vi tillämpar en liknande idé på data. Varje pull-request-förhandsgranskning kan ha sin egen databasgren och köra riktiga migrationer och seed-steg. En agent kan skapa data, ändra den och upprepa destruktiva tester utan att låna en utvecklares befintliga databas eller ärva tillstånd från en annan pull request.
Miljöändringar går via repositoryt. Verktygsuppgraderingar, webbläsarversioner och databasutökningar granskas och sprids på samma sätt som applikationskod.
Göra ingenjörsstandarder exekverbara i typer och lintregler
Skrivna standarder hjälper människor att förstå designbeslut. De garanterar dock inte att varje förändring följer dessa beslut, särskilt under långa agentsessioner.
Vi lägger stabila regler i typsystemet, linters och CI när regeln kan uttryckas tillförlitligt.
vm0 använder strikta TypeScript-inställningar, inklusive strict och noUncheckedIndexedAccess. Vissa paket aktiverar ytterligare kontroller för oanvända värden och implicita returvärden.
API:t använder ett schemaförst-typat REST-kontraktslager byggt med tRPC:s typmaskineri och Zod-scheman. Drizzle kopplar databasåtkomst till TypeScript-typer. Vid denna granskning innehöll repositoryt cirka 135 kontraktsmoduler.
Dessa val fångar inte felaktiga produktbeslut. De synliggör dock gränsdrift tidigt. När ett fält eller svar ändras tenderar relaterade anropare att misslyckas under statisk analys. Det resulterande felet är oftast tillräckligt specifikt för att en agent ska kunna använda det i nästa iteration.
Lintning täcker en andra grupp regler. Plattformen kör Oxlint, typmedvetna kontroller och ESLint, tillsammans med projektspecifika arkitekturregler. CI accepterar inga varningar. Varningar som kan ligga kvar på obestämd tid tenderar att bli bakgrundsbrus, och bakgrundsbrus är lätt för både människor och agenter att ignorera.
När ett problem upprepas överväger vi var kontrollen hör hemma:
- Kan typsystemet uttrycka det?
- Kan en linter eller strukturellt verktyg upptäcka det korrekt?
- Kräver det semantisk bedömning över repositoryt?
De två första ger snabb, deterministisk återkoppling på varje förändring. Vi hanterar den tredje gruppen med återkommande arbetsflöden som beskrivs senare i artikeln.
Begränsa felbenägna mönster i AI-genererad kod
Vissa språkfunktioner har legitima användningsområden och förekommer också ofta i skör agentgenererad kod.
try/catch kan sudda ut en felfördelning. När en agent stöter på ett fel är det enkelt att lägga till ett catch-block och fallback för att hålla nuvarande väg igång, men då förloras det ursprungliga felet. Att blanda Promise .then() och .catch() med async/await kan sprida kontrollflödet över flera stilar.
React's useEffect skapar ett liknande problem i tillståndshantering. Det används ofta för att kopiera tillstånd, synkronisera två sanningar eller koda ett ordningsberoende som är svårt att se från datamodellen.
Kärnwebbplattformen begränsar dessa mönster som standard. Ett motiverat undantag kan finnas kvar, med en tydlig förklaring bredvid.
Produktionskoden i kärnwebbplattformen innehåller för närvarande inga useEffect. Vi använder ccstate och andra effektlösa mönster för att modellera beroenden och bieffekter mer explicit. Ett fåtal produktionsanrop till useEffect finns fortfarande kvar i monorepot, främst i delad UI- och desktopkod, så påståendets omfattning är viktig.
Dessa regler växte fram ur återkommande fel i detta repository. När ett mönster upprepade gånger skapar samma underhållsproblem flyttar vi det från granskningsvägledning till en exekverbar begränsning.
Testa vid modulgränser: en testtrofé, inte en pyramid
vm0 följer inte en konventionell testpyramid. Vår testguide beskriver en testtrofé: statisk analys i botten, integrationstester som dominerande lager och ett fåtal end-to-end-tester för kritiska användarflöden.
Enhetstester är relativt ovanliga. Vi använder dem selektivt för säkerhetskritisk logik, algoritmer och tillståndsmaskiner. De flesta affärsbeteenden testas genom en moduls publika gräns.
API-tester anropar den riktiga applikationen genom dess kontrakt. Testdata förbereds via produktionsendpoints där det är praktiskt, och assertioner görs genom publikt beteende. Tester undviker att nå direkt in i en intern tjänst eller modifiera databastabeller, eftersom det kopplar dem till nuvarande implementation.
Intern infrastruktur förblir verklig där kostnaden är rimlig:
- PostgreSQL och pgvector
- databas-migrationer
- filsystemet
- interna tjänster
- mockar vid externa systemgränser
Dessa integrationstester körs långsammare än isolerade enhetstester och kräver en mer komplett miljö. De minskar också gapet mellan "testet passerade" och "applikationen kan utföra denna operation mot en riktig databas."
Gränstester lämnar utrymme för stora interna omstruktureringar. En agent kan organisera om moduler, dela upp en tjänst eller ändra dataåtkomstlagret medan det publika beteendet förblir skyddat.
Uncle Bob föredrar en annan blandning, med tung användning av enhetstester, Gherkin och mutationstester. Den gemensamma principen är oberoende verifiering. Processen som genererade koden ska inte vara den enda källan som hävdar att koden fungerar.
Ge kodningsagenter en komplett återkopplingsslinga
Våra tidiga kodningsagentkörningar slutade ofta med en bekant rapport: koden ändrades och TypeScript passerade; vänligen starta applikationen och kontrollera sidan.
Det lämnar halva utvecklingsslingan till ingenjören. Någon måste fortfarande förbereda en databas, köra tjänsterna, öppna en webbläsare, skapa data, observera felet och beskriva det tillbaka till agenten.
Agenter har nu tillräckligt av utvecklingsmiljön för att utföra mer av det arbetet. De kan starta applikationen och databasen, köra migrationer, skapa testdata, besöka en pull-request-förhandsgranskning och utföra riktiga webbläsarinteraktioner.
Webbläsarverifiering fångar en klass av problem som typkontroller och API-tester inte täcker väl: trasig navigering, laddningstillstånd som aldrig slutförs, behörighetsfel som bara syns i ett komplett flöde och visuella regressioner.
I slutet av en körning rapporterar agenten vilka kommandon den körde, vilken väg den testade och vad den observerade. För användargränssnittsändringar kan den inkludera skärmdumpar. En ingenjör kan granska dessa bevis innan hen bestämmer sig för att öppna förhandsgranskningen själv.
En skärmdump är inte ett test och bevisar inte frånvaro av andra fel. Den minskar dock kostnaden för att återskapa agentens kontext. För en liten gränssnittsändring är reproducerbara steg och en slutlig skärmdump mycket mer användbara än ett meddelande som säger att ändringen "borde vara fixad."
Kvaliteten på en agents arbete beror starkt på den återkoppling den kan få utan att vänta på en människa.
Hålla grenar korta med trunk-baserad utveckling
Snabb kodgenerering kan skapa ett stort lager av grenar.
Långlivade funktionsgrenar samlar på sig mergekonflikter, duplicerat arbete och föråldrad kontext. När pull requests växer blir granskningen svårare och långsammare. Vi använder trunk-baserad utveckling för att hålla grenar korta och integrera kontinuerligt kring main.
Våra huvudgrensregler kräver:
- pull requests för ändringar
- linjär historik och squash-merges
- en merge-kö
- Turbo-, Rust- och säkerhetskontroller
- ingen rutinmässig kringgång av obligatoriska grindar
Automatisering följer samma väg. En agent kan skapa en pull request, och vissa lågrisk-underhållsuppgifter kan möjliggöra automatisk sammanslagning, men ändringen går ändå genom CI och merge-kön.
Storleken och livslängden på pull requests förklarar hur 630 av dem kunde slås ihop på en vecka. En liten ändring har mindre kontext, är lättare att verifiera och mindre benägen att krocka med produktarbete eller en annan automatisk reparation.
Knip som repository-garbage collection: ta bort död kod
Kodgenerering lägger naturligt till filer och abstraktioner. Radering kräver ofta en separat prompt.
Efter en omstrukturering kan gamla filer ligga kvar i repositoryt. Att ta bort en funktion kan lämna exports, beroenden och entry points kvar. Dessa artefakter bryter sällan tester, men gör kodbasen svårare att navigera över tid.
Vi använder Knip för att hitta oanvända filer, exports, beroenden och entry points. TypeScript kan bekräfta att koden är giltig; Knip frågar om den fortfarande deltar i systemet.
Resten har en extra kostnad för kodningsagenter. Repositoryt är en av deras viktigaste kontextkällor. En föråldrad hjälpfunktion eller övergiven implementation kan se ut som ett godkänt mönster för nästa agent som läser den. Att hålla den kontexten ren är den oglamorösa halvan av kontextteknik: vad en agent läser från repositoryt är lika mycket en input som prompten den fick.
Att ta bort död kod förbättrar också inputen till framtida körningar. Knip hanterar den deterministiska delen av det arbetet tillräckligt snabbt för att bli en regelbunden kvalitetskontroll.
Återkommande AI-slop-städningsarbetsflöden
Knip och ESLint har tydliga gränser. Många former av försämring kräver projektkontext och semantisk bedömning.
Vi använder "AI-slop" som en praktisk etikett för dessa rester: onödiga fallbacks, duplicerade abstraktioner, tester som kringgår en publik gräns eller defensiva grenar för omöjliga tillstånd. Varje instans kan verka harmlös. Tillsammans gör de repositoryt svårare att förstå och ger framtida agenter dåliga exempel att följa.
Flera återkommande vm0-arbetsflöden söker efter dessa mönster enligt schema.
En daglig AI-slop-städning letar efter nya rester och väljer ut ett litet antal högkonfidens, lågrisk-fixar. Andra arbetsflöden inspekterar API-tester som når in i interna tjänster, React- och ccstate-antimönster och teknisk skuld som kan hanteras säkert.
Varje arbetsflöde håller sina ändringar smala. Det öppnar en pull request och förlitar sig sedan på normala typkontroller, lintregler, tester och merge-kö. En pull request konfigurerad för automatisk sammanslagning måste ändå passera samma grindar.

Att köra agenter enligt schema är inte gratis, och vi har skrivit separat om hur man håller dessa kostnader nere. Arbetsflödena försöker inte rensa all teknisk skuld i ett svep. En liten daglig batch är lättare att verifiera och mindre störande än en stor städning var några månader.
När ett återkommande arbetsflöde hittar samma mönster ofta nog överväger vi att flytta kontrollen till ESLint, Knip eller typsystemet. Det semantiska arbetsflödet fungerar som en plats att observera och förfina regeln innan den blir en billigare deterministisk kontroll.
Förvandla flakiga testfel till automatiska reparationer
En annan grupp arbetsflöden utgår från GitHub Actions-fel.
När ett test misslyckas på huvudgrenen eller i merge-kön läser ett arbetsflöde loggarna, letar efter tecken på flakighet och tittar på omstarter, timing och miljöfaktorer. Om bevisen stöder en specifik reparation uppdaterar det testet eller implementationen, öppnar en pull request och kör hela CI-flödet igen.
Att passera vid en omstart gör inte det ursprungliga felet ofarligt. Team som förlitar sig på retry-knappen tappar gradvis förtroendet för röda byggen. När det händer blir misslyckade kontroller ytterligare en form av bakgrundsbrus.
Ett automatiserat reparationsarbetsflöde förvandlar ett intermittent fel till en spårbar kodändring. Diagnos, patch och verifiering förblir synliga i pull requesten. Ingenjörer kan granska högriskändringar, medan smala fixar med starka bevis kan gå vidare genom merge-kön.
Vårt kvalitetssystem har för närvarande tre breda lager:
| Steg | Mekanismer | Typiska frågor |
|---|---|---|
| Vid skrivning | TypeScript, kontrakt, Drizzle, ESLint | typfel, gränsdrift, kända kodmönster |
| Före sammanslagning | Knip, integrationstester, riktiga databaser, förhandsgranskningar, merge-kö | död kod, modulbeteende, kompletta körtidsresultat |
| Efter sammanslagning | schemalagda och händelsestyrda vm0-arbetsflöden | AI-slop, semantiska antimönster, flakiga tester, arkitekturdrift |
Lagren matar varandra. Problem som hittas av arbetsflöden kan bli statiska regler. Fel som hittas i CI eller produktion kan bli tester och ny ingenjörsvägledning.
Var mänsklig uppmärksamhet läggs vid granskning av AI-genererad kod
vm0-ingenjörer läser fortfarande kod, särskilt vid arkitekturförändringar, säkerhetskänsligt arbete, betalningar och datamigrationer. Vi har inte gjort "aldrig läsa koden" till en teamregel.
Det som har förändrats är fördelningen av uppmärksamhet vid kodgranskning. Kodläsning är en signal bland kontrakt, testgränser, förhandsgranskningsbeteende, skärmdumpar, kvalitetsmått och arbetsflödesdiagnostik.
Flera beslut kräver fortfarande erfaren bedömning:
- om kravet är komplett
- var modulgränser ska ligga
- vilka fel som är återhämtningsbara
- hur stor affärspåverkan ett fel kan skapa
- om en säkerhetsmodell är lämplig
- vilket nytt felmönster nuvarande regler missar
En liknande förändring skedde på designsidan, där design-as-code flyttade visuella beslut till samma repository och samma granskningsväg. Ingenjörer underhåller också miljön runt agenterna. När ett problem upprepas bestämmer vi om vi ska lägga till en typbegränsning, lintregel, test eller återkommande arbetsflöde. Utvecklingssystemet har blivit en viktig ingenjörsartefakt i sig.
Läsbar kod är fortfarande viktig. Nästa läsare kan vara en ingenjör eller en annan agent. Trasslig kod förbrukar mer kontext, utökar omfattningen av framtida ändringar och gör verifiering mindre tillförlitlig.
Säkerhet och de förändringar som inte går snabbare
Hastigheten är inte jämnt fördelad. vm0 håller en kort lista över ändringar som går i sin egen takt: säkerhetskänsligt arbete, betalningar, datamigrationer och arkitekturbeslut. En ingenjör läser dessa rad för rad, oavsett vem eller vad som skrev dem.
Säkerhetsrisken med AI-genererad kod, enligt vår erfarenhet, handlar mindre om exotiska sårbarheter och mer om trovärdig kod som ingen äger. De kontroller som spelar roll är vanliga, tillämpade konsekvent:
- Enhetstester, som vi annars använder sparsamt, används medvetet för säkerhetskritisk logik, algoritmer och tillståndsmaskiner.
- Tester mockar endast vid externa systemgränser. Intern infrastruktur förblir verklig, så en ändring som bryter ett internt kontrakt misslyckas i CI istället för i produktion.
- Agenter arbetar i dev-containern mot en databasgren per pull request, inte på utvecklarens maskin och inte mot en delad databas.
- Merge-kön och obligatoriska kontroller har ingen rutinmässig kringgång, även för en pull request som en agent öppnat och markerat för automatisk sammanslagning.
try/catchär begränsad som standard, så ett fel är mindre benäget att sväljas av en fallback som en agent lagt till för att hålla en väg igång.
Hantering av autentiseringsuppgifter är ett separat designproblem med sin egen lösning: vi beskrev broker-mönstret som håller tokens borta från agentens händer i en egen artikel.
Inget av detta gör genererad kod säker i sig. Det begränsar mängden ändringar där ett mänskligt beslut är den enda kontrollen, och gör den mängden explicit.
Vad dessa siffror inte visar
Veckorapporten visar repositoryts skala och leveranshastighet. Den visar inte i sig produktionsstabilitet.
Att utvärdera effekten på körtidskvalitet kräver tillgänglighet, produktionsfel, incidentantal, förändringsfel, rollbackfrekvens och medeltid till återställning. Ett grönt CI-flöde beskriver en del av leveransprocessen.
Vi fortsätter att samla dessa utfallsmått. Ingenjörspraxis förklarar hur ett system hanterar risk; produktionsdata visar hur väl den hanteringen fungerar.
FAQ
Vad är vibe-kodning? Vibe-kodning är att ge en LLM en prompt för kod, köra vad den returnerar, be om ändringar och inte läsa den genererade koden. Martin Fowlers definition är avsiktligt snäv: utvecklaren ska "glömma att koden ens existerar." Det passar prototyper, engångsprogram och verktyg med begränsade konsekvenser.
Vad är agentisk kodning? Agentisk kodning är en längre AI-assisterad utvecklingsform där en agent läser ett repository, redigerar filer, kör tester och itererar självständigt under en längre period. Människor äger fortfarande arkitektur och beteende, och de granskar bevisen en körning producerar snarare än varje rad den skrev.
Vad är skillnaden mellan vibe-kodning och agentisk kodning? Uppmärksamhet, inte författarskap. I vibe-kodning inspekteras aldrig koden. I agentisk kodning arbetar agenten självständigt medan ingenjörer granskar bevisen runt den: testresultat, kvalitetssignaler, förhandsgranskningar och produktionsbeteende. vm0 beskrivs oftast som vibe-kodat; i Fowlers termer är det agentisk kodning.
Vad är AI-slop? AI-slop är resterna AI-genererad kod lämnar efter sig: onödiga fallbacks, duplicerade abstraktioner, tester som kringgår en publik gräns, defensiva grenar för omöjliga tillstånd. Varje instans ser harmlös ut. Tillsammans gör de ett repository svårare att förstå och ger nästa agent dåliga exempel att följa.
Hur granskar ni AI-genererad kod vid 630 pull requests i veckan? Inte rad för rad. På vm0 går mänsklig granskning dit omdöme krävs: arkitektur, säkerhetskänsligt arbete, betalningar, datamigrationer. Allt annat bärs av mekanismer: strikta typer och kontrakt, integrationstester vid modulgränser, riktiga databaser i per-pull-request-förhandsgranskningar, webbläsarverifiering, Knip och en merge-kö som ingen ändring rutinmässigt kringgår.
Vilka är bästa praxis för vibe-kodning i stor skala? Fem håller över åtta månader på vm0: konvergera utvecklingsmiljön så att agenter och människor kör samma kommandon; gör standarder exekverbara i typer, linters och CI istället för dokument; testa vid modulgränser mot riktig infrastruktur; ge agenter en komplett återkopplingsslinga inklusive webbläsare; och städa kontinuerligt istället för vid stora engångspass.
Vilka är säkerhetsriskerna med AI-genererad kod?
Den vanliga risken är inte en exotisk sårbarhet utan trovärdig kod som ingen äger. vm0 håller säkerhetskänsligt arbete, betalningar och datamigrationer på mänsklig granskning, använder enhetstester medvetet för den logiken, håller intern infrastruktur verklig i tester, begränsar mönster som try/catch som sväljer fel och tillåter ingen rutinmässig kringgång av obligatoriska kontroller.
Skapar AI-genererad kod teknisk skuld? Den skapar en specifik typ: kod som fortfarande kompilerar och passerar tester men inte längre deltar i systemet, plus semantiska rester som ingen linter kan namnge. Knip tar bort den deterministiska delen. Återkommande arbetsflöden hanterar resten i små dagliga batcher, och ett mönster som återkommer ofta nog blir en lintregel eller typbegränsning.
Hur mycket av vm0-kodbasen är skriven av AI? Större delen av implementationen. Sex ingenjörer författade 556 av de 630 pull requests som slogs ihop under veckan den 20–26, 2026, med release-automation som författade resten, och agenter skrev huvuddelen av koden i dessa pull requests. Det ingenjörerna äger är arkitekturen, begränsningarna och produktionsbeteendet.
Vad är en testtrofé, och varför inte en testpyramid? En testtrofé sätter statisk analys i botten, integrationstester som dominerande lager och ett fåtal end-to-end-tester på toppen. vm0 använder det eftersom tester skrivna genom en moduls publika gräns fortsätter att skydda beteende medan en agent omorganiserar implementationen under, vilket ett stort lager av enhetstester inte gör.
Hur hittar ni död kod i ett AI-skrivet repository? Kodgenerering lägger till filer och abstraktioner; radering kräver oftast en separat prompt. vm0 kör Knip som en regelbunden kontroll för att hitta oanvända filer, exports, beroenden och entry points. TypeScript bekräftar att koden är giltig; Knip frågar om den fortfarande deltar i systemet, vilket är den fråga som är avgörande för död kod.
Är vibe-kodad kod säker att köra i produktion? Det beror på vad som verifierar den snarare än på vem som skrev den. De signaler vi kräver har inte ändrats: typer och kontrakt, tester genom publika gränser, riktig infrastruktur och en pipeline som måste vara grön. Siffrorna i denna artikel beskriver repositoryts skala och leveranshastighet. Tillgänglighet, felfrekvens och förändringsfel är de mått som besvarar produktionsfrågan, och vi håller fortfarande på att samla in dem.
Åtta månader in
Åtta månader är för tidigt för att utropa en slutgiltig metod. Modeller, agentverktyg och repositoryt fortsätter att förändras, och våra regler och arbetsflöden förändras med dem.
En förändring är redan tydlig. När kodgenerering blev snabbare tog miljön, begränsningarna, testerna och återkopplingssystemet över mer av kvalitetsbördan. Ingenjörer lägger mindre tid på att skriva implementation och mer tid på att definiera beteende, designa gränser och förbättra verifiering.
vm0-kodbasen kommer att fortsätta växa. Knip tar bort deterministiska rester. Statiska regler blockerar felmönster vi redan förstår. Integrationstester skyddar modulbeteende. Återkommande arbetsflöden hanterar försämring som vi ännu inte kan uttrycka maskinellt.
Kod är fortfarande viktig. Bästa praxis i denna artikel handlar inte om att skriva mindre kod, utan om att avgöra vad som måste vara sant innan en ändring hör hemma på huvudgrenen. Vi använder nu mer maskinexekverbara bevis för att avgöra om en ändring hör hemma på huvudgrenen, och om dess implementation ska finnas kvar i repositoryt.





