# AI ile self-review — neyi hızlandırıyor, nerede yetmiyor

> 'Niye' değil 'ne kadar' yazısı: tool workflow'a hangi katmanlarda giriyor, hangi bug pattern'lerini yakalıyor ve nerede sınırına dayanıyor.

- Yayın: 2026-05-28
- Kategori: Günlük
- Etiketler: Araçlar, Git, Go
- Okuma süresi: 7 dk okuma
- Kaynak: https://www.muhammetsafak.com.tr/blog/ai-ile-self-review-neyi-hizlandiriyor-nerede-yetmiyor/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
[Önceki yazıda](/blog/kendi-diffimi-bir-tool-a-soruyorum-commitbrief/) CommitBrief'i niye yazdığımı anlatmıştım: kendi diff'ime mesafe alamamak, mevcut AI araçlarının diff seviyesinde düşünmemesi, terminalden çıkmadan ikinci bir göz ihtiyacı. Bu yazı *"niye"* değil *"ne kadar"* yazısı. Üç ayın sonunda workflow'a hangi katmanlardan girdiğini, hangi rakamlarla hız kazandırdığını, hangi tip hataları tekrar tekrar yakaladığını ve nerede yetmediğini somutlaştırmak istiyorum.

Önce bir hatırlatma: bu araçların değer ürettiği yer "AI yazsın" değil "AI ikinci bir göz olsun" — [daha önce yazdığım gibi](/blog/yapay-zeka-caginda-kod-yazmanin-degisen-el-becerisi/) üretim ucuzladıkça muhakeme pahalılaşıyor. Bir tool'un değeri o pahalı muhakemeye ne kadar iyi yardım ettiği. Aşağıdakiler benim ölçtüğüm kadarı.

## Doğru leverage point: dosya değil, değişiklik

İlk hafta yanlış soyutlamayla başladım: bir dosyayı AI'a verip *"bunu review et"* demek. Çıktı uzun, jenerik ve büyük ölçüde alakasızdı. Çünkü bir reviewer'ın bakacağı şey dosya değil, **o dosyaya gelen değişiklik**. CommitBrief'in tasarım birimi diff olunca üç şey aynı anda iyileşti: token bütçesi 10× düştü, severity ataması anlamlı hale geldi (artık *"bu fonksiyon iyi yazılmış mı"* değil, *"bu değişiklik soruna yol açıyor mu"* sorusuna cevap aranıyor), false positive bandı küçüldü.

Pratikte bunun anlamı: bir PR'ın *"yapay zeka tarafı"* dört-beş saniyeye sığabilir. Bu da onu pre-push refleksi haline getirebilecek kadar hızlı yapıyor.

## Üç entegrasyon katmanı

CommitBrief'i workflow'a sokmanın üç katmanı var; her birinin farklı bir hız profili.

| Katman | Komut | Hız profili | Tipik kullanım |
|---|---|---|---|
| **Manuel** | `commitbrief` | 4-5 sn, $0.02-0.04 | Push'tan önce kendi gözünün üstüne bir göz |
| **Pre-push hook** | `commitbrief install-hook --hook=pre-push --fail-on=critical` | Push'u kritik bulguda iptal eder | Solo geliştirici / küçük takım |
| **CI step** | `commitbrief --fail-on=high` | PR pipeline'ında soft/hard gate | Takım PR'larında ortak çıta |

Üçü birden değil, **birini seç ve aklında tut.** Hepsini aynı anda kurmak workflow disiplinini değil, bildirim gürültüsünü artırır. Ben solo akışta manuel komut + pre-push hook kullanıyorum; CI step'i takım projelerinde tutuyorum.

Pre-push hook'un bir inceliği var: önce kurduğum sürüm gerçekte `--staged` çalıştırıyordu — yani push anında index genelde boş olduğu için sessizce no-op'a düşüyor, push geçiyordu. *"CI gate kurduğunu sanıp aslında hiçbir şey kurmamak"* — kendi audit'imde bu hatayı yakaladım, v1.0'da `pre-push` artık git'in stdin protokolünü okuyup `commitbrief diff <remote>..<local>` çalıştırıyor. Tool'un kendi sınırlarına çarptığı yerlerde dürüst olmak gerekiyor.

## Rakamlar — benim akışım

Üç senaryo, üç farklı hız profili.

### Senaryo 1 — Pre-push refleksi (solo)

Tipik bir orta boy PR'ım: ~120 satır eklenmiş, 40 silinmiş, dört-beş dosya. Eski akışım:

- `git diff --staged` ile gözden geçirme: **4-7 dk**
- İki kez daha okuma (anchor bias'a karşı): **+3-4 dk**
- Push, PR aç

Yeni akışım:

- `commitbrief --staged`: **4-5 sn** → çıktıyı oku: **30-60 sn**
- Critical/High varsa düzelt + tekrar çalıştır (cache hit: **13 µs**, **$0**)
- Bilinçli derin okuma (artık ne aradığımı biliyorum): **2-3 dk**
- Push, PR aç

Toplam: **9-10 dk → 3-5 dk.** %55 civarı bir hız, evet — ama asıl kazanç dakikalarda değil; *gerçek hatayı reviewer'a ulaşmadan yakalamak* bu işin en pahalı kısmı.

### Senaryo 2 — Takım PR round-trip

Bir kritik bulgu reviewer'a ulaşmadan yakalandığında PR round-trip iki günden bir güne iniyor. Bu kasıtlı bir mütevazılık: aslında daha da kısalıyor ama ortalamayı bozan *"reviewer'ın yine de fark ettiği başka bir şey"* döngüsü her zaman var. **AI insan reviewer'ı tamamen bypass etmiyor; reviewer'ın gözünü "kolay bulgular" yerine "hard bulgular"a odaklıyor.** Net etki bu.

### Senaryo 3 — Cache hit ekonomisi

CommitBrief'in cache key'i: `SHA256(diff + system_prompt + provider + model + lang + schema_version)`. Diff değişmediği sürece aynı çağrı 13ms sürüyor ve $0 maliyet üretiyor. Pratikte:

- Rebase sonrası tekrar review: bedava
- Push öncesi *"son kez bir bakayım"*: bedava
- Sağlayıcı değiştirip karşılaştırma: bedava değil ama yeni cache key'i, paralel ikinci görüş için cazip

Aylık fatura matematiği: Anthropic Sonnet 4.6 ile ortalama $0.03/review × ayda ~50 PR × cache miss oranı %40 ≈ **$0.60/ay**. Ollama ile sıfır, sadece elektrik. Bir saatlik insan code review zamanının opportunity cost'unun yanında ihmal edilebilir.

## Yakaladığım pattern'ler

Üç ayda CommitBrief'in (ve aynı pipeline'ı paylaşan sağlayıcıların) tekrar tekrar yakaladığı beş paterni saydım. Bir kısmı günlük kullanımımdan, bir kısmı CommitBrief'in v1.0 öncesi self-audit'inden — üç farklı sağlayıcıya kendi proje kurallarımla kendi projemi review ettirdim, ortak bulgu setlerini topladım. Her biri *"diff okumayla yakalanabilir, gözle yakalanması zor"* kategorisinde.

**1. Error wrap duplikasyonu.** `%w` format specifier zaten wrapped error'u içerirken prefix'te aynı mesajı tekrarlamak. Log'da `"auth failed: auth failed: invalid token"` üretir. Statik analiz yakalamıyor çünkü teknik olarak hata değil; semantik bir tekrar. Compiler memnun, log'lar berbat.

**2. NOT NULL kolon migration default'suz.** Boş tabloda sorunsuz, dolu prod tablosunda fail. CommitBrief'in tipik çıktısı: *"Migration fails on any table that already has rows; either backfill in a prior migration or add a DEFAULT before the constraint."* Bu bug staging'de görünmeyip prod'da görünen klasik aileden.

**3. i18n catalog'da key var, kullanılmamış.** Çoklu dil destekleyen projelerde sık: yeni bir prompt için EN/TR key ekliyorsun ama kodda `cat.T(...)` yerine hardcoded string bırakıyorsun. EN'de fark edilmez (string aynı), TR'de fonksiyonel kırılma. Benim kendi projemde bu pattern audit'in en tutarlı bulgularından biriydi — `guard.prompt` ve `setup.welcome` key'leri YAML'de duruyordu, ama gerçek prompt'lar Go kodunda İngilizce literal'di. Üstüne çok ironik bir vaka: Türkçe `[e/H]:` (evet/Hayır) prompt'u render ediliyordu ama parser sadece `y`/`yes` kabul ediyordu — Türk kullanıcı `e` yazınca sessizce *"no"* olarak işleniyordu. *"i18n var"* sandığım yer aslında *"i18n yarım"* idi.

**4. Config knob accepted-but-ignored.** Config schema'da var, `config set` ile kabul ediyor, dokümante etmişsin — ama kod path'inde okunmuyor. Kullanıcı dokümana inanıp ayarlıyor, etki sıfır. CommitBrief'in kendi cache config'inde bunu yaptım: `cache.enabled: false` set'lemek hiçbir şey yapmıyordu çünkü pipeline cache'i sadece `Dir` ve `RepoRoot` parametresiyle açıyordu. Bu pattern özellikle iki ayrı PR'da bölünür — "config tanımla" PR'ında ve "config kullan" PR'ında. AI ikincisinin eksikliğini fark ediyor; insan reviewer iki PR arasındaki zaman aralığında bağlamı kaybediyor.

**5. Boş katmanlar arasında kaybolan ref.** Bir kapı kurduğunu sandığın bir mekanizmanın aslında no-op olması. CommitBrief'in `pre-push` hook'u bunu yapıyordu (yukarıda anlattım). Bu tip bug AI olmadan ya production'da ya da güvenlik incident'inde yakalanır; pattern'i bilen bir reviewer diff'te de görür.

Beşinin ortak özelliği: hiçbiri *"kod yanlış derleniyor"* tipi değil. Hepsi **intent ile gerçeklik arasındaki boşluk**. AI'ın gerçekten katma değer ürettiği yer tam burası — sentaks doğrulamak zaten compiler'ın işi.

## Proje-spesifik kuralın önemi

CommitBrief'i generic AI review araçlarından ayıran en somut nokta: `COMMITBRIEF.md` projenin kök dizininde durur ve system prompt olarak LLM'e gider. CommitBrief'i geliştirirken kullandığım `COMMITBRIEF.md`'den üç madde:

- *"Yeni dependency MIT / Apache-2.0 / BSD / ISC / MPL-2.0 / LGPL-3.0+ olmalı; AGPL veya proprietary kabul edilmez."*
- *"Tüm user-facing string'ler `cat.T(key, ...)` üzerinden gitmeli; hardcoded English / Turkish reddedilir."*
- *"i18n catalog'a yeni key eklendiyse EN/TR parity zorunlu; tek tarafta key olamaz."*

Bunlar generic *"iyi kod"* tavsiyeleri değil; bu projenin kendi politikası. Generic bir AI asistanı *"bu dependency MIT mi GPL mi"* sormaz; benim kuralıma göre review eden bir AI sorar. Bu fark, review'un kullanışlılığını sentaks-seviyesinden mimari-niyet-seviyesine taşıyor — ve aynı tek dosyayı paylaşan bir takımda *"hangi standartlar geçerli"* tartışmasını koddan önce gerçekleştirmiş oluyor.

## Sağlayıcı kararı + maliyet

Dört sağlayıcının (Anthropic, OpenAI, Gemini, Ollama) artı iki CLI-tabanlı sağlayıcının (`claude-cli`, `gemini-cli`) tek bir abstraction üstünde yaşaması iki şeyi mümkün kılıyor: **karşılaştırma ucuz**, **lock-in yok**.

| Sağlayıcı | Tipik review | Güçlü yan | Zayıf yan |
|---|---|---|---|
| Anthropic Sonnet 4.6 | $0.03 | En tutarlı muhakeme, ephemeral prompt cache (5dk) | En pahalı orta seviye |
| Gemini 2.5 Pro | $0.01 | 1M context, cömert ücretsiz tier | Zaman zaman overly verbose |
| OpenAI GPT-4o | $0.02 | Hızlı; ≥1024 token prefix'lerde otomatik cache | Sonnet'ten kısa açıklamalar |
| Ollama (yerel) | $0 | Zero exfiltration, kendi donanımın | Donanım gerekli, modele bağlı kalite |
| `claude-cli` | $0\* | Mevcut Claude Code subscription | Plain text — structured findings yok |
| `gemini-cli` | $0\* | Mevcut Gemini CLI auth | Aynı |

\* Mevcut abonelik var sayılırsa marjinal $0.

Pratikte: günlük akışta Anthropic Sonnet kullanıyorum (tutarlılık önemli). Yüksek hassasiyet gereken PR'larda aynı diff'i Gemini Pro'ya da gönderip iki bulgu setini karşılaştırıyorum — cache mantığı sağlayıcı per-key olduğu için ikisi ayrı entry, ama maliyet hâlâ yuvarlanmış birkaç kuruş. Yerelde kalması gereken kod için Ollama. CLI sağlayıcılarını henüz günlük akışta kullanmıyorum çünkü plain text çıktı `--fail-on` severity gate'ini bypass ediyor; aboneliğin zaten ödeniyorsa hızlı bir "ikinci bakış" için faydalı, CI integration'ı için değil.

## Nerede yetmiyor

Üç ay sonra hâlâ tool'un sınırlarına çarpıyorum. Dürüst liste:

- **Mimari sorgulama yok.** *"Bu özelliği yapmalı mıyım"*, *"bu abstraction doğru mu"* sorularına cevabı yok. Tek bir diff'in sistemin bütünüyle nasıl oturduğunu görmüyor.
- **Intent doğrulama yok.** *"Doğru özelliği mi yapıyorsun"* diyemiyor. Yanlış spec'in mükemmel implementasyonu yeşil çıkar.
- **Cross-file consistency sınırlı.** Tek bir PR'daki dosyalar arası tutarlılık tamam, ama PR dışındaki kod tabanıyla kontrast kuramıyor (*"bu pattern projenin başka yerinde X şeklinde yapılıyor, burada Y kullanmışsın"* gibi). Repo geneli vektörleme yapmıyor; PRD'de bilinçli scope kararı.
- **False positive bandı var.** Genelde `info` seviyesinde ve görmezden gelmek kolay, ama yine de var. `OUTPUT.md` template'iyle info bulgularını filtrelemek mümkün.
- **Prompt injection riski.** Diff'in içindeki saldırgan içerik LLM'i yanıltabilir. CommitBrief'in mitigation'ı: `<project_rules>...</project_rules>` XML wrapper + immutability guard + her review öncesi secret scan. Yine de sıfır risk değil; security-sensitive diff'lere `--no-cache` + dikkatli okuma tavsiye ederim.

Bu sınırların hiçbiri *"araç işe yaramıyor"* sonucuna götürmüyor — sadece **yerini doğru koymak** lazım. CommitBrief lint'in yerine değil, **lint + test'in üstüne, insan review'un altına bir katman.**

## Kapanış

İlk yazıda söylediğim cümleyi tekrar etmek istiyorum: *üretim ucuzladıysa, üretileni denetlemek pahalı kalmamalı.* Üç ayın somut çıkarımı şu: **AI'ın değer ürettiği nokta yargıyı kalibre etmek; yargıyı yerine koymak değil.** Bir tool'un doğru tasarımı bu farkı reddetmek değil; kabul edip iki tarafı birbirine bağlamak.

CommitBrief benim için bu bağlantıyı kuran şey oldu. Sizin için işe yararsa, `COMMITBRIEF.md`'inizi paylaşmanızı isterim — başka projelerin *"iyi kod"* u nasıl tanımladığını görmek, bu işin en öğretici tarafı.

- [github.com/CommitBrief/commitbrief](https://github.com/CommitBrief/commitbrief)
- [commitbrief.com](https://commitbrief.com)
- Portfolyo sayfası: [/portfolyo/commitbrief](/portfolyo/commitbrief/)
