AIREITER

329 Komutun 128'i Hâlâ Yok: Migrasyonu Modelle Değil, Küme Matematiğiyle Mutabıklaştırın

Son Güncelleme: 2026-07-31 07:49:12

Eski dildeki bir fonksiyonu modele verip yenisine çevirmesini istersiniz. Ortaya adlandırma kurallarına da uyan, temiz ve idiomatik kod çıkar; test de geçer. Bunu iki yüz kez tekrarlayıp işi kapatır, migrasyonun bittiğini ilan etmek kolaydır.

Asıl sorun burada başlar: “çevrildi” ile “migre edildi” aynı şey değildir. Tek bir fonksiyonun doğru çevrilip çevrilmediğini değerlendirmek modelin güçlü olduğu alandır. Ancak tüm sistemin gerçekten taşınıp taşınmadığı bambaşka bir sorudur. Bu, bir küme işlemidir; modelin dokunmaması gereken ve sizi yanıltma ihtimalinin en yüksek olduğu işlerden biri de budur.

Gerçek bir Go-to-Python migrasyonundan çıkan tablo aşağıda. Bu tablonun neden bir betikle kapatılması, modelin ise yalnızca farkları açıklaması gerektiği de burada netleşiyor.

Önce üç sayıyı netleştirin

Eski Go kayıt defterinde 23 platform ve 329 komut vardı. Yeni Python tarafında argparse bildirimlerinden türetilen komut kümesinin eski kayıt defteriyle kesişimi tam olarak 201 komut. Dolayısıyla 128 komut yalnızca eski tarafta bulunuyor; ne Python’a taşınmış ne de stub olarak bırakılmış.

329 = 201 + 128. Bu çıkarma işleminin teknik açıdan derin bir tarafı yoktur, ama migrasyonun bitip bitmediğini cevaplayan tek şey budur. Fonksiyonları tek tek çevirirken de tam olarak bunu göremezsiniz. Eksik bir öğe, yokluk hatasıdır: hata fırlatılmaz, exception oluşmaz, test kırılmaz. Var olması gereken bir isim yoktur; mesele bu kadar. O isim sohbet kutusuna hiç girmemiştir ve iki yüz yeşil onay işaretine bakıp bunu fark etmeyebilirsiniz.

Neden stub veya uyumluluk proxy’si bırakmamalısınız?

Migrasyonun ortasında tamamlanmayan komutlar için yer tutucu bırakmak cazip gelir: raise NotImplementedError kullanan bir stub ya da eski binary’ye yönlendiren bir uyumluluk proxy’siyle “endpoint kataloğu eksiksiz görünsün” dersiniz. Yapmayın. İçi boş bir kabuk, açık bir eksikten üç nedenle daha maliyetlidir.

Önce stub, mutabakatı bozar. Komut adı yeni tarafın kümesine girer, diff 0 çıkar ve işin bittiğini sanırsınız. Açık bir eksik dürüstçe kırmızı görünür; stub ise “128 kaldı” bilgisini “her şey mevcut” diye yeşile boyayan bir yalandır.

Uyumluluk proxy’si ise arındırılmamış eski bağımlılığı kalıcılaştırır. Proxy çağrıyı eski Go binary’sine aktarır; bu durumda eski runtime asla silinemez. Migrasyonun amacı eski stack’i geride bırakmaktır, fakat yönlendiren proxy “geçici uyumluluk” adı altında eski stack’in yerleşip ömür boyu kalmasına izin verir.

Yarı tamamlanmış bir endpoint çağıranı da yanıltır. Bir Agent ya da insan kataloğu okur, çalıştığını varsayar, çağrıyı yapar ve runtime_unavailable ile karşılaşır. Daha kötüsü, sessizce boş sonuç döndüren sahte bir başarı alabilir.

Dürüst bir eksik aslında en ucuz seçenektir: diff bunu anında kırmızıya çeker ve herkes ne kadar iş kaldığını görür. Bu, uygulama tersine mühendisliğindeki kanıt eşiği ile aynı ilkedir: Bir şeyi “henüz kullanıma hazır değil” diye işaretlemek, yarım bir sürümünü yayınlamaktan her zaman daha ucuzdur.

Mutabakat betiğinin temel iskeleti

Mutabakatın özü tek satırda özetlenebilir: İki tarafın komut kümeleri de bildirimlerden türetilir; hiç kimse bunları elle yazmaz. “Migre edildi” listesini elle tutarsanız koddan kopacak üçüncü bir doğruluk kaynağı yaratmış olursunuz. İki hafta sonra da ilk bozulan şey o liste olur.

Yeni Python tarafındaki tek doğruluk kaynağı, her platformun cli.py dosyasındaki argparse bildirimleridir. Bir catalog modülü alt komutları dolaşır, {platform/command} kümesini dışarı aktarır; çıktı python -m reverse describe --format json ile üretilir. Bildirimin neden tek doğruluk kaynağı olabildiğini ve kataloğun nasıl tamamen otomatik türetildiğini interface-as-code yazısında ele almıştık. Eski Go tarafı zaten platform -> command eşlemesi, yani binary içine derlenmiş değişmez bir allowlist; aynı yapıda JSON dışa aktarmak burada son derece basit.

İki JSON dosyası elinizdeyse geriye yalnızca küme işlemleri kalır:

# Both sides' command sets derive from declarations, not transcription.
# Transcribe by hand and you've added a third source of truth that will drift.
import json
from collections import Counter

def ids(path):
    doc = json.load(open(path))
    return {f"{p['name']}/{c['name']}"
            for p in doc["platforms"] for c in p["commands"]}

old = ids("go-registry.dump.json")      # old registry: immutable platform->command allowlist
new = ids("python-catalog.dump.json")   # python -m reverse describe --format json

missing = old - new     # old side only: each one needs a keep-or-drop verdict
added   = new - old     # new side only: new capability, logged separately
kept    = old & new     # intersection: migrated, but still check for semantic drift

assert missing | kept == old            # every old-side item classified, none dropped

by_platform = Counter(pc.split("/")[0] for pc in missing)  # goes straight into the README table

Bu işlem birkaç milisaniye sürer; maliyeti yoktur, deterministiktir ve %100 doğrudur. missing bu 128 komuttur. Platforma göre toplandığında tablo şöyledir:

Platform

Migre edilmemiş komutlar

xiaohongshu

33

tiktok

30

hotspot

21

douyin

19

reddit

8

weibo

7

bilibili

5

zhihu

3

linkedin

1

netease_music

1

Toplam

128

Bu aşamada modele yer yok.

Modele satır satır karşılaştırma yaptırmanın maliyeti ve hata payı

Betiği atlayıp iki listeyi sohbet kutusuna yapıştırdığınızı ve “329 komuttan hangileri bu 201 içinde yok?” diye sorduğunuzu düşünün. Üç şey neredeyse kaçınılmaz biçimde gerçekleşir.

Öğeleri atlar: Liste uzadığında model eleman eleman küme farkı hesaplamaz; “yaklaşık doğru görünüyor” diye örnekleme yapar. Sonlardaki öğeler gözden kaybolur, elinize eksiksiz görünen ama bir düzine komut eksik bir yanıt geçer. Öğeler uydurur: Her iki tarafta da bulunan komutları eksik diye raporlayabilir veya gerçekten eksik olanları migre edilmiş sayabilir. Çünkü yaptığı şey farkı hesaplamak değil, bir mutabakat raporunun nasıl göründüğünü taklit etmektir. Tekrarlanabilir değildir: Aynı girdiyi iki kez verirsiniz, eksik listesi değişir. Her seferinde başka sonuç üreten bir “mutabakat”, mutabakat değildir.

Maliyet açısından da mantıklı değildir. Betik birkaç milisaniye çalışır; modelle karşılaştırma ise birkaç yüz bin token ve birden fazla öz-denetim turu gerektirir. Pahalı, yavaş ve güvenilmezdir. Küme işlemini küme işlemi yapan araca vermek, bu yazıdaki en tartışmasız öneri olmalı.

Modelin gerçek görevi: farkı açıklamak, migrasyonu karara bağlamak değil

Betik size migre edilmemiş 128 komut gerçeğini verir, ancak gerçek tek başına karar değildir. Her biri için “tut” ya da “çıkar” kararı gerekir; karar vermek içinse gerekçe gerekir. Modelin devreye girdiği alan burasıdır.

Her komut için “neden migre edilmedi?” sorusunu açıklayın. Ölü kod mu? Upstream endpoint kapatılmış mı? Ertelendi mi? Yoksa en zor ihtimal mi söz konusu: Komut silinmedi, başka bir komutta birleştirildi; ad kayboldu ama yetenek hâlâ var. “Birleştirildi, silinmedi” türündeki bu gizli eşleşmeyi yalnızca eksik listesinden göremezsiniz. Eşleştirmek için iki kayıt defterini bir arada okumak gerekir.

Kesişimdeki 201 komut da güvenli değildir. Migre edilmiş olması semantiğin korunduğu anlamına gelmez: Aynı isimle çalışan ama varsayılanı sessizce değiştirilmiş bir komut, tersine çevrilmiş sayfalama anlamı veya iki hata kodunun tek koda birleştirilmesi gibi durumlar olabilir. Bu, eksikten daha sinsi olan semantik sapmadır; diff yeşildir ve öğe hiç missing listesine girmez. Sapmayı denetlemek için modelin iki implementasyonu okuyup “davranış eşdeğer mi?” diye karar vermesi gerekir; nihai doğrulama ise diferansiyel testle yapılır (dört aşamalı iş akışının üçüncü aşamasındaki fixture karşılaştırması). Başarılı görünen bir çeviriye bakıp yine de “davranış burada değişmiş” diyebilmek, fingerprinting yazısındaki karşı kanıt bölümünün tam olarak anlattığı yetenektir. Zayıf bir model ise yalnızca “başarıyla migre edildi” ezberini tekrarlar.

İş bölümü böylece nettir: “Orada mı?” kararını betik verir; “Kalmalı mı, davranışı değişti mi?” soruları muhakeme ister. Bu örnekte diff’in kırmızı işaretlediği 4 komut, inceleme sonunda gerekli bulundu ve birinci sınıf yeni komutlar olarak geri eklendi. Betik belirler, model açıklar, insan karar verir; üç katmanın da yeri ayrıdır.

Hangi adımda hangi model kullanılmalı?

Aşağıdaki dört katmanın tamamı açıklama katmanında çalışır. Karar katmanında, yani diff işleminde, hiçbir model kullanılmaz. Bu yazıyı diğer “AI migrasyonu” içeriklerinden ayıran çizgi de budur.

Adım

Gerekli yetenek

Tercih

model id

İki kayıt defterini aynı anda besleyip “silinmedi, başka yerde birleşti” eşleşmelerini bulmak

Uzun bağlam; iki tarafın tüm bildirimlerini aynı anda okuyabilme

Kimi K3

kimi-k3

128 eksik öğe için ilk tur tut/çıkar değerlendirmesi ve yapılandırılmış taslak

Ucuz; yüksek eşzamanlılıkta yüzlerce çağrı yapabilme

Claude Sonnet 5

claude-sonnet-5

Semantik sapma değerlendirmesi: Migre edildi, peki davranış değişti mi? İki implementasyonu da okur

Güçlü muhakeme; “burada değişiklik var” diyebilme cesareti

Claude Opus 5

claude-opus-5

Migre edilmiş ancak fixture eşleşmiyor; parametre veya yanıt şekline göre nedenini açıklamak

Orta seviye muhakemeyle nedensellik atfetme

GPT-5.6 Sol

gpt-5.6-sol

En çok test etmeye değer olan üçüncü katmandır. Semantik sapma değerlendirmesi, doğrudan “zaten başarılı kabul edilmiş bir çeviriye itiraz edebilir misin?” sorusunu sınar. Model değiştirmenin sonucu en fazla etkilediği yer de burasıdır. Protokol şöyle:

  1. Kendi gerçek iki dilli migrasyonunuzda betiği çalıştırın ve missing kümesini çıkarın. Bu adımda sıfır model kullanın.

  2. Bunların 10 ila 15 tanesini kontrol grubu olarak gerçek durumuyla elle etiketleyin: çıkar, tut, başka yerde birleşti, ertelendi.

  3. Her öğe için aynı “tut/çıkar gerekçesini açıkla” prompt’unu claude-opus-5 ile ucuz bir katmana verin. İki şeye bakın: Tut/çıkar gerekçesi belirli bir kod gerçeğine mi dayanıyor, yoksa “muhtemelen kullanımdan kalktı” gibi muğlak bir yanıt mı veriyor? Ayrıca her biri kaç tane başka yerde birleşmiş eşleşmeyi yakalıyor?

  4. Yakaladığı gizli eşleşme sayısı, ilk turu ona emanet edip etmeyeceğinizin temel ölçütüdür.

Asıl sürtünme model seçimi değil, model değiştirme maliyeti

Üç sağlayıcıdan dört model; üç SDK, üç kimlik doğrulama düzeni, üç hata formatı. Katman değiştirmek için istemcinizi üç kez yeniden yazmak değmez. Bu yüzden çoğu ekip baştan sona tek model kullanır; muhakeme katmanına en çok ihtiyaç duyulan semantik sapma incelemesinde ise yalnızca muğlak cevaplar veren ucuz katmanla devam eder ve tüm yeşil görünen sapmaları içeri geçirir.

AIReiter bu katmanı sadeleştirir: Tek anahtar, OpenAI uyumlu tek arayüz, arka tarafta dört katmanın tamamı. İstek gövdesindeki model alanını değiştirmeniz yeterlidir.

# Semantic-drift review / per-item keep-or-drop: the reasoning tier
curl https://aireiter.com/api/v1/chat/completions \
  -H "Authorization: Bearer $AIREITER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-5",
    "messages": [{"role": "user", "content": "<both implementations + this command migration status, ask if behavior is equivalent>"}]
  }'

# First pass on 128 missing items in bulk: change the model field, leave the rest
#   "model": "claude-sonnet-5"
# Diff attribution when a fixture won't match:
#   "model": "gpt-5.6-sol"

Halihazırda OpenAI SDK kullanıyorsanız base_url değerini https://aireiter.com/api/v1 olarak ayarlayın; başka hiçbir şeyi değiştirmeniz gerekmez. Anthropic SDK tarafında ise aynı anahtarla POST /api/v1/messages çağrısını yapın.

Fiyat avantajı bu iş akışının tam merkezine denk gelir: İlk tur, yüzlerce öğeyi aynı anda işler ve her migrasyon turunda yeniden çalışır; yüksek eşzamanlılıktaki claude-sonnet-5 burada en ucuz seçenektir. Semantik sapma incelemesi ise claude-opus-5 ile tekrar tekrar ele alınan bir düzine zor vakadır ve öğe başına en pahalı aşamadır. İkisi de Claude katmanıdır; %30 indirim, en yoğun ve en pahalı bölümlere doğrudan yansır. Diff nedenini açıklama işi ise yarı fiyatına GPT olan gpt-5.6-sol tarafından yapılır.

  • API anahtarı alın

  • Kayıt olmadan deneyin: Önce birkaç eksik öğeyi elle çalıştırın ve “başka yerde birleşti” vakalarını yakalayıp yakalayamadığına bakın; ardından entegrasyona karar verin.

Sonuç

“Çevrildi” tek fonksiyonun yarattığı bir yanılsamadır. “Migre edildi” ise diff ile karara bağlanır. Küme işlemleri betiğe, açıklama modele, karar insana aittir. Bu sıra karıştırılamaz; özellikle de karar işini modele bırakarak.

Atlanması en kolay ama önemli bir adım daha var: Eksik listesi uzun vadede görünür kalacak şekilde README’ye girmeli. 128 sayısı 0 olana ya da her komut için yazılı bir “X nedeniyle migre edilmiyor” gerekçesi bulunana kadar orada kalmalı. Yalnızca bir PR tartışmasında yaşayan mutabakat, mutabakat değildir. Çünkü işi devralan kişi onu göremez ve aynı 128 öğenin üstüne yeniden basar. Bu yazının, interface-as-code yazısının ve birleşik response Model oluşturmama yazısının ortak noktası budur: Tek doğruluk kaynağının kendisi konuşsun; sonuçları insanların hafızasına dağıtmayın.