PinAppAI

← Blog

Bir reviewer kendi ana sayfamızda görünmez bir butonu pin'ledi. Çözüm, istediği çözüm değildi.

Dış geri bildirim döngüsünü kapatan bir araç yaptık, sonra kendi ana sayfamızı ondan geçirdik: bir pin, bir change request, PR #122 ve dürüst hesap.


Ana sayfamızın hero bölümünde iki buton var. Birincisi dolu kırmızı bir eylem çağrısı (#E30A17). İkincisi, “Read the docs”, ince çerçeveli bir ghost buton. Neredeyse beyaz olan hero gradyanında (#f9fafb’ten #ffffff’e) bu çerçeve yaklaşık 1.2:1 kontrasta denk geldi. Görünmez. Doygun kırmızı bir butonun yanında, hiçbir kenarı olmayan, havada asılı bir metin gibi okunuyordu.

İşin can yakan kısmı şu. Butonun çerçevesi eksik değildi. Bir çerçevesi vardı ve kural en baştan beri oradaydı:

.btn-ghost { border-color: var(--pp-border); }  /* #e5e7eb */

var(--pp-border) bizim en ince çizgi (hairline) token’ımız. Ayıraçlar, kart kenarları, header alt çizgisi, footer çizgisi için var; yani neredeyse görünmezliğin bizzat amaç olduğu her yer için. İki panel arasındaki 1px’lik bir çizgi için tam da doğru, parlak bir arka planda kendi şeklini koruması gereken bir kontrol içinse tam da yanlış. Yani kusur hiçbir zaman “çerçeve yok” değildi. Kusur, “başka bir iş için yapılmış bir token’ı ödünç alan bir çerçeve” idi. Bir linter bunu dümdüz geçirir. Bir design-token denetimi de geçirir, çünkü her kural yerinde ve her değer geçerli. Hiçbir şey bozuk değil. Sadece okunmuyor.

Bunu CSS’i yeniden okuyarak yakalamadık. Biri onu pin’leyerek yakaladı.

Döngüyü çalışırken izle

Baştan sona nasıl göründüğü aşağıda. Bir reviewer canlı siteyi açıp ghost butonu pin’liyor, tek bir workflow inbox’ı boşaltıp bir pull request açıyor, ve bir insan değişikliği yayına girmeden önce preview üzerinde onaylıyor. Her kare gerçek ürün durumu. Hiçbir şey kurgulanmadı; ajanın kendi çalışma süresi dışında hiçbir yer hızlandırılmadı, o da çalışırken ekranda işaretli.

Bu kayıt, aşağıda anlatılandan daha sonraki bir çalıştırma: aynı buton, ama biz adını değiştirdikten sonra. Change request #9, pull request #258, yaklaşık 19 dakika. Burada anlatılan hikaye ilki, yani CR #2 ve PR #122. İkisini de tuttuk, çünkü ikinci çalıştırma “yazıdan sonra da çalışmaya devam ediyor mu” sorusunun dürüst cevabı.

Çalıştırma

Geri bildirimin dış döngüsü dediğimiz şeyi kapatan bir araç yapıyoruz; o halde yapabileceğimiz en az şey onu kendimize doğrultmaktı. Bu, tek bir çalıştırmanın yazısı: bir reviewer, bir pin, bir change request, bir pull request, duvar saatiyle yaklaşık 13 dakika.

Bir reviewer gerçek, canlı sayfayı açtı ve pin’i gerçek öğenin üstüne bıraktı. Ekran görüntüsü değil, Slack mesajı değil. Pin “Read the docs” butonunun üstüne gitti ve not dobra dobraydı:

Bu buton, kırmızı butonun yanında görünmez. Ona gerçek bir çerçeve ver.

O pin; CSS seçicisini, sayfa URL’ini, cihazı ve viewport’u taşıyan yapılandırılmış bir change request’e dönüştü. Bizimki CR #2 idi.

Kodlama ajanımız CR #2’yi bir MCP sunucusu üzerinden okudu (Claude Code, Cursor ya da Codex ile çalışır). Ekmeğini işte burada kazandı. Çerçeveyi koyulaştırıp işini bitmiş saymadı. Mevcut kuralı buldu, hairline token’ı çektiğini gördü ve özensiz bir çözümün yanlış yapacağı üç muhakeme kararı verdi:

Butonun işaret ettiği token’ı değiştirdi, token’ın kendisini değil. .btn-ghost’u --pp-border’dan --pp-ink’e, yani butonun kendi metin rengine yeniden yönlendirdi; böylece çerçeve, yeni ve tek seferlik bir gri yerine tutarlı tek bir buton gibi okundu. --pp-border’ın kendisini yeniden hedeflemek, butonu “düzeltirken” sitedeki her ayıracı ve kart kenarını kalınlaştırırdı. Kusur, butonun token seçimindeydi, token’da değil.

Pin’lenen pikseli değil, bileşeni düzeltti. .btn-ghost, pazarlama sayfaları ve onların Türkçe kopyaları boyunca on dört çağrı noktası olan paylaşımlı bir sınıf ve bunların her biri aynı görünmez çerçeveyi taşıyordu. Hero’ya özel bir override, reviewer’ın pin’lediği tam pikseli düzeltirdi ve bileşeni sessizce fork’lardı. Sınıfı düzeltmek on dördünü birden düzeltti.

Tahmin etmek yerine ölçtü. Hero’ya karşı kontrast 1.2:1’den 14.05:1’e çıktı; göz kararıyla değil, tarayıcıda getComputedStyle ve WCAG oranıyla doğrulandı.

Ardından gerçek bir pull request açtı, PR #122, fix(marketing): give .btn-ghost a visible border (CR #2). Pin’lenmiş olan tam noktada yeşil bir “Applied” işareti belirdi ve CR #2 InReview’a geçti; böylece reviewer, bir diff okumadan notunun üzerine işlem yapıldığını görebildi. Reject edersen Inbox’a geri döner; bir sonraki çalıştırma onu kaydedilmiş önceki/sonraki anlık görüntüden geri alır.

Pin’den change request’e, uygulanan çözüme, PR’a, yeşil işarete: yaklaşık 13 dakika.

Pin’in taşıdığı şey ve püf nokta neden bu

Bütün bunların ayakta kalmasının sebebi, sinyalin geldiği biçim. “İkinci buton tuhaf görünüyor” hem doğru hem işe yaramaz. Aktarılırken ölür, seçicisi olmayan ekran görüntüsünde ölür, kimse hangi buton olduğunu hatırlamayana kadar bekleyen ticket’ta ölür. Bir pin sorunu başka sözcüklerle anlatmaz, onu konumlandırır: öğe, sayfa, cihaz, viewport; bir insanın önce onu bir ticket’a çevirmesine gerek kalmadan bir ajanın işlem yapabileceği şekilde paketlenmiş halde.

Bir reviewer o pin’i dört yolla bırakabilir ve hiçbiri reviewer’dan bir şey kurmasını ya da kod bilmesini istemez: Figma linki gibi gönderdiğin, kurulum gerektirmeyen bir review link, kendi sitene gömebileceğin bir widget, giriş ardındaki sayfalar için bir Chrome eklentisi ya da yerel bir macOS uygulaması. Not, numaralı bir change request olarak bir Inbox’a düşer, ajan Inbox’ı tek bir çalıştırmada boşaltır ve her şey birleşmeden önce InReview’dan geçer. İnsan asla devre dışı kalmaz. Geliştirici PR’ı yine de inceler. Değişen şey, geri bildirimin doğrudan uygulanabilir halde gelmiş olması.

Bu örüntü genelleniyor

Bu çalıştırma tek bir CSS token’ıydı. Örüntü buna bağlı değil. Açıkça söyleyelim: aşağıdaki üç madde, örüntünün birer örneği; size gösterdiğimiz gerçek change request’ler değil. Bunlar, gerçek bir site yayına girdiğinde Inbox’a düşen türden şeyler:

  • Bir müşteri hero’yu pin’ler: “bu başlık, görselin yanında fazla silik.”
  • Bir PM fiyatlandırma kartını pin’ler: “burada mobilde hala $12 yazıyor.”
  • Bir paydaş, yeniden tasarım sonrası bir bölümü pin’ler: “kayıt butonu gözden kayboldu, eskiden ilk gördüğün şey oydu.”

Bunların hiçbiri klasik anlamda bir bug değil. Hepsi, “yapay zeka siteyi kurdu” ile “site gerçekten doğru” arasında birikip duran şeyler ve normalde hepsi, bir geliştiricinin koda dokunmadan önce çözmesi gereken muğlak bir metin olarak dolaşır. Konumlandırılıp yapılandırıldığında, bir ajanın üzerinde işlem yapabileceği ve bir insanın onaylayabileceği bir şeye dönüşürler.

Kısaca tez

İç döngü hızlandı. Bir dosyayı okuyan, düzenleyen, testi çalıştıran bir ajan: bu döngü saniyelerle ölçülüyor ve hala kısalıyor. Dış döngü ise kımıldamadı. Dış döngü, gerçek ve canlı bir sitedeki gerçek bir insanın bir şeyin ters gittiğini fark edip o sinyali, kodun üzerinde işlem yapabileceği bir biçimde kod tabanına geri getirmesidir. İç döngü sıfıra doğru çökerken, dış döngü toplamda baskın gelmeye başladı.

Bu boşluk araştırmalarda adı konmuş bir şey, bizim uydurmamız değil. Verification Horizon çalışması, ele aldığı ödül kurgularından biri olarak doğrulayıcı-olarak-kullanıcıyı (user-as-verifier) sıralıyor; SWE-bench yazarlarının kendi pozisyon makalesi, darboğazın insan-ajan etkileşimine kaydığını savunuyor ve özellikle “visual previews and interactive summaries”, yani görsel önizlemeler ve etkileşimli özetler istiyor. Makalelerde tanınmış, sahaya çıkan harness’larda yok. Bugün herhangi bir ajan harness’ini aç ve geliştirici olmayan bir kişinin döngüye yapılandırılmış sinyal geri verebilmesi için kaç arayüz olduğunu say. PinAppAI, o arayüzü kurmanın bir uygulaması. Doğru uygulama olmayabilir.

Hesap defteri: atlamandansa okumanı tercih ederiz

İşte tam olarak neyi iddia edip neyi edemeyeceğimiz; çünkü küçük ama gerçek olan, büyük ama uydurma olandan daha değerlidir.

Bu, kontrol ettiğimiz bir sitede, kendi istediğimiz bir geri bildirimle yürütülmüş tek bir değişiklikti. Bu bir demo, bir ölçüm değil ve akışın kaydedilmiş her versiyonu hızlandırılmış. Üç gerçek dış kullanıcımız ve bir gerçek dış projemiz var; bu bir müşteri tabanı değil ve bunu bir müşteri sonucu olarak okumamalısın. Kendimiz dışında kimse için dış döngü süresinde bir azalma ölçmedik ve kendini ölçmek, var olan en zayıf kanıttır.

Sözünü etmeyi sevdiğimiz “haftalardan saatlere” sıkışması, savdan çıkan bir öngörü ve sav yanlış olabilir. Belki darboğaz sadece yer değiştirir. Belki reviewer’lar pin’lemez ya da kötü pin’ler. Belki bir ajanın, bir insana kıyasla daha sık, kendinden emin ama yanlış bir değişiklik uygulaması, gözden geçirme adımındaki kazancı yiyip bitirir. Bir sayıya değer bir ölçekte çalıştırdığımızda öğreneceğiz. Ve PR #122 yayına girmedi. Açıldı. Onu bir insan inceliyor, tıpkı diğer her PR gibi.

Ölçecek müşterilerimiz olduğunda, o sayıları yayımlayacağız; bizi güzel göstermeyenler dahil. O zamana kadar dürüst iddia, küçük ve gerçek olan: bir reviewer görünmez bir butonu pin’ledi, bir ajan onun yanlış token’ı ödünç aldığını çözdü, diğer on dört çağrı noktasını mahvetmeyen çözümü seçti, sonucu ölçtü ve PR #122’yi açtı. Gidip ona bakabilirsin.