CommitBrief'e flaky-test dedektörü: AI'ın yazdığı kararsız testleri commit'te durdurmak
CommitBrief'e deterministik bir flaky-test süzgeci ekledim: sabit sleep'leri ve seed'siz rastgeleliği commit'te, modelsiz yakalıyor.
CommitBrief bugüne kadar tek bir şey yapıyordu: kendi diff’imi, kimse görmeden, bir LLM’e inceletmek. İlk yazıda niye işe yaradığını, summary ve remote yazısında ekibe nasıl taşındığını anlatmıştım. Hepsinin ortak noktası: bulguyu model üretiyordu.
Bu yazıdaki ekleme o noktayı bilerek kırıyor. CommitBrief artık modeli çağırmadan önce, değişen test dosyalarını deterministik bir statik süzgeçten geçiriyor — kararsızlığa (flaky) en sık yol açan kalıpları yakalamak için. Niye bu ekleme LLM’e bir madde daha eklemekle yapılmadı; asıl yazı o.
Kararsızlığın neden AI çağında patladığını ve neden retry/quarantine’in bir koşu bandı olduğunu sade.dev’de ayrı yazdım: Kararsız Testler: Retry Çözüm Değil. Bu yazı o tezin araç tarafı.
Kolay yol LLM’di — onu seçmedim
CommitBrief baştan sona LLM-güdümlü bir araç. En kolay yol belliydi: prompt’a “test dosyalarında sabit sleep, kırılgan selector, seed’siz random ararsan işaretle” diye bir rubrik daha eklemek. Bir akşamlık iş.
Sorun, bu çözümün olasılıksal olması. Modele bağlı, çalıştırmadan çalıştırmaya kayabilir ve — daha önemlisi — farklılaşmıyor: herhangi bir LLM review aracı aynı prompt’la aynı şeyi yapabilir. Oysa kararsızlığın asıl can sıkıcı tarafı, çözümün deterministik olmasını istemen: aynı diff her zaman aynı sonucu versin, model olmadan da çalışsın, commit aşamasında bir saniyede dönsün.
O yüzden statik yolu seçtim. Yeni bir paket (internal/flaky), değişen test dosyalarının yalnızca eklenen satırlarını tarıyor, bilinen anti-pattern’leri muhafazakâr regex’lerle yakalıyor ve standart bir bulgu üretiyor. Aynı diff → aynı bulgu. Model yok, network yok.
Ne yakalıyor
İlk sürümde iki yüksek-isabetli kural var. İsabet, recall’dan önce geliyor: commit aşamasındaki gürültülü bir kapı yok sayılır, yok sayılan kapı da hiç olmamasından kötüdür.
- Sabit bekleme / sleep (
medium):time.Sleep,Thread.sleep,Task.Delay,asyncio.sleep,*.waitForTimeout, sayısalcy.wait(2000),usleep,sleep(<n>)— Go, Java/Kotlin, C#, Python, JS/TS, Cypress, PHP. - Seed’siz rastgelelik (
low):Math.random, Pythonrandom.*, Gomath/randgloballeri (rand.Intn, …).
Test dosyasını yoldan tanıyor (*_test.go, *.test.*/*.spec.*, test_*.py, *Test.java, *_spec.rb, __tests__/e2e/cypress dizinleri…). Bulgu metni en/tr yerelleşiyor. Çıktı, modelin bulgularıyla aynı kart:
● medium worker/job_test.go:41
Test senkronizasyon için sabit bir bekleme (sleep) kullanıyor
Sabit beklemeler testi zamana bağımlı kılar: hızlı makinede geçer, CI
yükü altında patlar; süite olan güveni aşındıran flaky sonuçlar üretir.
→ Sabit gecikmeyi koşula dayalı bir beklemeyle değiştir…
Modelin bulgularıyla nasıl birleşiyor
Statik bulgular, filtreden sonra hesaplanıp LLM bulgularıyla merge ediliyor — render, --fail-on ve --copy’den önce. İki kural:
- Her LLM bulgusu korunur. Statik süzgeç hiçbir şeyi bastırmıyor.
- Aynı
file:line’da çakışma olursa statik bulgu eklenmiyor — modelin o satır için zaten söyleyecek sözü varsa, ikinci kez söylemiyoruz.
Güzel bir yan etki: model bozuk JSON döndürüp degrade olsa bile statik bulgular hayatta kalıyor. Deterministik kısım, olasılıksal kısma bağımlı değil.
Ve JSON şeması v1 değişmedi. Statik bulgular mevcut render.Finding şeklini kullanıyor; yeni alan yok, yeni exit-code yüzeyi yok. --fail-on=medium artık sabit bir sleep’te de kapıyı kapatıyor — ekstra bir flag öğrenmene gerek kalmadan.
Kullanımı
API/mock sağlayıcılarda varsayılan açık. Kapatmak istersen:
commitbrief # flaky pre-pass açık (varsayılan)
commitbrief --no-flaky # bu çalıştırmada atla
commitbrief config set review.flaky false # kalıcı kapat
Öncelik --no-flaky > review.flaky > yerleşik (true). CLI-tabanlı (claude-cli/gemini-cli) sağlayıcılar düz metin ürettiği için bu yolda şimdilik devre dışı — onu ayrı bir adımda ele alacağım.
”Yerini almak” değil, yine “önünden gitmek”
Bu ekleme de serinin aynı cümlesinin etrafında: üretim ucuzladıysa, üretileni denetlemek pahalı kalmamalı. AI test yazmayı bedavalaştırdı; o testlerin bariz kararsızlığını yakalamak da bedava olmalı — bir model çağrısı, bir CI dakikası harcamadan, commit’in olduğu yerde.
Burada model bir lükse dönüşüyor, zorunluluğa değil: bariz olanı deterministik kısım topluyor, modelin dikkatini gerçekten muhakeme isteyen şeylere saklıyorum.
Sınırlar — yine dürüst liste
- İsabet-öncelikli. Bariz anti-pattern’leri yakalar; kendi kodunun içine gömülü bir race condition’ı değil. Akıllı kararsızlığı kaçırır ve tahmin etmesine izin vermiyorum.
- CLI sağlayıcı yolu kapsam dışı. Düz metin üreten sağlayıcılarda merge henüz yok; takip adımı.
- Statik, AST değil (henüz). Regex tabanlı; kapsamı/semantiği görmüyor. Brittle selector, over-mock ve zaman-bağımlı assertion kuralları sıradaki additive eklemeler.
- Tespit emniyet ağı, çözüm değil. Asıl çözüm testi en baştan deterministik yazmak — onu sade.dev yazısında anlattım.
Denemek için
Bir test dosyasına sabit bir sleep koyup commitbrief’i çalıştırın — modelden önce, deterministik olarak yakalandığını görün. Hangi anti-pattern’i bir sonraki sürümde görmek istediğinizi yazarsanız, sıraya koyarım.
Bu konudaki deneyler
Uygulama ile sağlayıcı arasında duran, tek OpenAI uyumlu API sunan ve isteğe RAG bağlamını kendisi ekleyen self-hosted Go gateway.
Şu an ne yapıyor
Uygulamanın tek bir OpenAI uyumlu uca konuşmasını, isteğin hangi modele gideceğini ve — bir doküman havuzu bağlıysa — hangi dokümanlardan bağlam alacağını projenin ayarının belirlemesini sağlıyor. Sağlayıcı anahtarını uygulamalara dağıtmak istemeyen ve harcamayı proje başına sınırlamak isteyen herkes kendi sunucusunda çalıştırabilir.
Dile özgü serileştirme yerine dondurulmuş bir JSON zarfı; polyglot kuyruk standardı BabelQueue'ya dönüştü.
Şu an ne yapıyor
Dondurulmuş JSON zarfı dört dilde — PHP, Python, Go, Node.js — aynı baytları okutuyor; sidecar ya da broker eklentisi gerekmiyor. Polyglot kuyruk kuran ekipler spesifikasyonu ve SDK'ları bugün kullanabilir.
Yorumlar
Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.