Files
kolaytercih/docs/ekip-raporlari/2026-09-22/04-uretim-engelleri.md
bilalgursen 2b350d0c5d content(rehber): gece vardiyasının 14 yeni yazısı + 2 düzeltme, ekip raporları ve kurallar
14 yeni rehber yazısı (hepsi editör denetiminden geçti, 46 yazıda 829 iç link
tarandı, 0 kırık hedef; 180+ DB rakamı yazıların kendi filtreleriyle yeniden
koşuldu):

  taban-siralamalari-alti-yilda-nasil-degisti · kac-net-ile-hangi-bolum ·
  siralama-bandlari-hangi-kapilar-acilir · ayni-bolum-farkli-universite-siralama-farki ·
  hangi-bolumlerin-kontenjani-azaldi · yeni-acilan-bolumler-nasil-degerlendirilir ·
  bilgisayar-mi-yazilim-muhendisligi-mi · kktc-universiteleri-okunur-mu ·
  yapay-zekaya-tercih-sordum-guvenilir-mi · ek-madde-1-puanim-yetiyor-mu ·
  universitede-ilk-hafta-ders-kaydi-muafiyet-kayit-dondurma · yks-2027-takvimi ·
  rehber-ogretmenler-icin-veri-kaynaklari · bolumumu-sevmedim-hangi-kapilar-var

İki canlı yazı düzeltildi:
- veliler-icin-tercih-rehberi: veli diliyle kapanış; altındaki "sıralamanı gir"
  kutusu artık veliye ölü uç değil
- bos-kontenjanlar-ne-anlatiyor: "birkaç yüz kişilik fark" aslında ~9 bin
  (ÖSYM 265.356 ↔ bizim 256.532); payda açıklaması tersti — ek kontenjan
  paydaya girseydi oran düşerdi. guncelleme alanı eklendi (sitemap lastmod).

Kurallar (AGENTS.md):
- Yayın sonrası arama motoru bildirimi: URL denetimi yalnız canlıda 200 dönen
  adrese; kota sayacı; mülk/hesap notu; sitemap grep kuralı
- Yıkıcı git komutları yasak: reset/checkout --/restore/clean/stash
- Tarayıcı açma: tasarımcı ve UX gerekli gördüğünde açabilir (yetenek için
  .claude/agents/tasarimci.md'ye tarayıcı araçları eklendi)

docs/gece-vardiyasi/2026-09-22/ — 34 rapor: CEO kararları ve kapanış turu,
marka/ödeme analizi, sıfır ödeme teşhisi, SEO konu planı, veri kalitesi,
editör denetimi, CTO şartnamesi, yazılımcı ve güvenlik raporları, SABAH-OZETI.

docs/ekip/YAYIN-KUYRUGU.md — Search Console bildirim kuyruğu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 23:25:34 +03:00

277 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 04 — Üretim engelleri: liste ve üretim anı dönüşüme ne kadar zarar veriyor?
Hazırlayan: Yapay zekâ mühendisi · 22 Eyl 2026 gündüz · Kod değiştirilmedi, commit atılmadı.
Kanıt türleri: **[ölçüldü]** = bu oturumda koşturularak (LLM çağrısı YOK, maliyet 0 TL), **[koddan çıkarım]** = yalnızca kod okunarak. Gerçek modelle hiçbir koşu yapılmadı.
> **Satır numaraları `main @ bda4d07` referanslıdır.** Çalışma ağacında Bilal'e ait commit'lenmemiş değişiklikler var (`Dockerfile`, `globals.css`, `layout.tsx`, `liste-uretici.tsx`, yeni `src/app/api/saglik/`) — dokunulmadı. `liste-uretici.tsx`'teki satır numaraları o değişikliklerle kayar.
>
> **O devam eden iş bu raporun 5. maddesiyle doğrudan ilgili:** yeni `sunucuAyaktaMi()` + `kod:"SUNUCUYA_ULASILAMIYOR"` yaması, üretim bittikten hemen sonra konteyner ölünce (ters vekil 502) WebKit'in sayfayı `listem.txt` olarak indirdiği 22 Eyl vakasını kapatıyor. **Bu dalda liste DB'ye yazılmış, kredi harcanmış ve kullanıcı listeyi hiç görmemiş oluyor** — yani "3 liste oluşturuldu" sayısının bir kısmı ekrana hiç ulaşmamış olabilir. Aşağıdaki §5 tablosu bu dalı (g)'nin bir varyantı olarak okumalı.
---
## 5 maddelik karar özeti
1. **Bekleme süresi tek başına 3 listeyi açıklamıyor.** Tipik üretim ~10–20 sn (kod yorumu, `src/lib/ai/cagri.ts:66-67`), havuz SQL'i 2–72 ms [ölçüldü]. Ama **bekleme ekranı 28 saniyede donuyor**: 4 aşama mesajı 7 sn arayla akıyor (`uretim-mesaji.ts:16`), sonra "neredeyse hazır" yazısında kalıyor; "uzun sürdü" uyarısı ise **90 sn**'de geliyor (`liste-uretici.tsx:45`) — yani 28–90 sn arası kullanıcı ilerleme sinyali olmadan bekliyor. En kötü hâl 126 sn (2 deneme × 60 sn + 6 sn geçiş supabı).
2. **Asıl kapı kredi değil, maskedir.** Yeni kullanıcı 5 kredi alıyor (`credits.ts:11`), liste 3 kredi (`credits.ts:14`) — ama paketsiz kullanıcının listesinde **24 satırın 21'inin yapay zekâ metni kilitli** (`rapor-maske.ts:13`, `listem-icerik.tsx:144`). Deneme, kredinin %60'ını harcayıp %87,5'i kilitli bir çıktı üretiyor. Danışman da kilitli 21 satırı görmüyor (`api/soru/route.ts` "kilitli" dalı), yani kalan 2 kredi de yarım değerde. **"Denemeden önce ödeme" hissinin kaynağı burası.**
3. **Bir metin fiilen yanlış vaat veriyor.** `/sonuc`'taki tadımlık CTA'sı: *"24 satırın tamamı için giriş yap — 5 deneme kredin hazır"* (`tadimlik-satiri.tsx`). Giriş yapan kullanıcı 24 satırın tamamını almıyor; 3 açık + 21 kilitli alıyor. Aynı CTA giriş dönüşünde kullanıcıyı `/listem?uret=1`'e değil **düz `/sonuc`'a** bırakıyor (`callback=${sonucHref()}` → `"/sonuc"`), yani üretim başlamıyor, bir tık daha gerekiyor. Yanındaki hazır panel doğru yere (`LISTEM_URET_HREF`) gidiyor — iki CTA aynı sayfada farklı davranıyor.
4. **"Üretmeden gösterme" için elimizde hazır ve bedava bir yol var.** 24'lük iskeletin **gerekçe dışındaki her şeyi zaten deterministik**: program seçimi, dilim, risk notu ve trend cümlesi LLM'siz kuruluyor — **24 satır 2–72 ms'de, 0 LLM çağrısıyla** [ölçüldü]. Üstüne 522 satırlık tadımlık havuzu (`app.db/tadimlik_havuzu`, kova×tür×kategori×tip) duruyor [ölçüldü: 522 satır]. Bugün bu varlığın tamamı **yalnızca `/sonuc`'ta, yalnızca tek satır** olarak kullanılıyor — 30 günde 23 kişinin gördüğü sayfada. Trafiğin %75'i olan katalog sayfaları yapay zekâ çıktısını hiç görmüyor.
5. **3 listenin yanında kaç başarısız deneme olduğu Rybbit'ten ölçülemiyor** — `liste_uretim_hata` olayı 21 Eyl 04:49'da eklendi (`cf19903`) ve prod'a 21 Eyl öğleden sonra çıktı; 23 Ağu–21 Eyl penceresinin tamamında hata dalı ölçüsüzdü. **Ama prod DB'den bugün, kod değişmeden çıkarılabiliyor:** `credit_ledger`'da `report_generate` satırı = deneme, aynı `ref_id`'li `refund` satırı = başarısızlık. Sorgu §5'te.
---
## 1. Üretim anının maliyeti
### Kullanıcı ne yaşıyor (akış, dosya:satır)
| # | Adım | Nerede | Süre |
|---|---|---|---|
| 1 | "Listemi oluştur" → seçimler storage'a yazılır, `/listem?uret=1`'e gidilir | `sihirbaz-cagri-karti.tsx:179-188` | anlık |
| 2 | Girişsizse araya `/giris` girer (Google OAuth tur) | `sihirbaz-cagri-karti.tsx:185` | ~5–15 sn (ölçülmedi) |
| 3 | `ListeUretici` mount → localStorage/çerez profili okunur → server action | `liste-uretici.tsx:162-176` | anlık |
| 4 | **3 kredi düşülür** (LLM'den ÖNCE) | `rapor-actions.ts:119-124` | anlık |
| 5 | Aday havuzu SQL + filtre/gevşetme | `rapor-havuzu.ts:93` | **2–72 ms** [ölçüldü] |
| 6 | LLM çağrısı (`reasoning_effort:"none"`, `max_tokens:4000`) | `rapor.ts:304-315`, `cagri.ts:90-115` | tipik ~10–20 sn [kod yorumu, `cagri.ts:66`], üst sınır 60 sn |
| 7 | Şema/adet tutmazsa **2. deneme** (yeni 60 sn bütçesi) | `rapor.ts:303-332` | +0–60 sn |
| 8 | Rapor DB'ye yazılır, `router.replace("/listem")` | `rapor-actions.ts:181-195`, `liste-uretici.tsx:114` | anlık |
| 9 | Geçiş olmazsa emniyet supabı tam sayfa yükler | `liste-uretici.tsx:41,136-150` | +6 sn |
**Toplam:** tipik **15–30 sn**, gerçekçi kötü hâl **60–70 sn**, teorik en kötü **~126 sn**.
### Ekranda ne görüyor
- İki kolonlu iskelet (8 satır skeleton + danışman paneli) + shimmer'lı aşama metni (`liste-uretici.tsx:239-341`).
- Metinler: 4 aşama, 7000 ms arayla, **sonuncuda duruyor** (`uretim-mesaji.ts:11-17,19`). → **28 sn sonra ilerleme sinyali yok.**
- Altta: *"Bu işlem yarım dakika kadar sürebilir, sayfayı kapatma."* (`liste-uretici.tsx:271`).
- "Beklenenden uzun sürdü" mesajı **90 sn**'de (`liste-uretici.tsx:45`). 60 sn'de ilk deneme abort olup ikinci deneme sessizce başlıyorsa kullanıcı 60–90 sn arası hiçbir şey öğrenmiyor.
**Bir ilk kullanıcıyı kaçırır mı?** Ortalama (15–30 sn) için hayır; bu ekran iyi tasarlanmış. Kaçırdığı yer **kuyruk**: girişsiz kullanıcı için tıklama → OAuth → yeniden yükleme → 15–30 sn bekleme zinciri, ödül 3 açık satırsa orantısız. Mobilde `/sonuc`'tan çıkışa medyan 33 sn (03 raporu §2) — bu sabırla, girişten sonra 30 sn daha bekleme talep ediliyor.
### "Sayfayı kapatma" gerçek bir tehdit
`cagri.ts:63-67` kendi notunda söylüyor: *"fonksiyon dışarıdan öldürülürse harcanan kredi iade edilemiyor."* Kredi LLM'den önce düşüyor (`rapor-actions.ts:119`), iade yalnızca `catch` bloğu koşarsa oluyor (`rapor-actions.ts:169-178`). Kullanıcı sekmeyi 20. saniyede kapatırsa **5 deneme kredisinin 3'ünü hiçbir şey görmeden kaybetme riski var** ve bu dal hiçbir yerde sayılmıyor. [koddan çıkarım]
### Maliyet (token; TL yazılmadı — fiyat OpenRouter panelinden okunmalı)
Model: `deepseek/deepseek-v4-flash` varsayılan (`client.ts:6`); env ile değişebilir.
| Profil | Havuz | Hedef (h/d/g) | Gevşetildi | Havuz JSON | ~token |
|---|---|---|---|---|---|
| 5.000 / say / müh + İstanbul | 40 | **8/6/10** | **il** | 9.606 char | ~2.9k |
| 30.000 / say / müh | 51 | 5/13/6 | — | 12.350 | ~3,7k |
| 75.000 / ea / hukuk (devlet) | 60 | 5/13/6 | kategori | 14.185 | ~4,3k |
| 175.000 / söz / seçimsiz | 60 | 5/13/6 | — | 14.324 | ~4,3k |
| 375.000 / tyt / sağlık | 60 | 5/13/6 | kategori | 14.477 | ~4,4k |
| 750.000 / tyt / seçimsiz | 60 | 5/13/6 | — | 14.749 | ~4,5k |
[ölçüldü] — `havuzOlustur` + `havuzuKompaktJson`, LLM'e gidilmedi. Token ≈ char/3.3 (Türkçe+JSON için kaba katsayı, doğrulanmadı).
- **Girdi/çağrı:** havuz (~2,9–4,5k) + sistem prompt'u (~600) + kullanıcı sarmalayıcı (~200) ≈ **3,7–5,3k token**.
- **Çıktı/çağrı:** 24 × (id + ~15 kelimelik gerekçe) + genel + uyarılar ≈ **~1,1–1,5k token** (tavan `max_tokens: 4000`).
- **Başarılı üretim = 1 çağrı.** En kötü hâl **6 çağrı**: dış döngü 2 deneme (`rapor.ts:303`) × iç geçici-hata tekrarı 3 (`cagri.ts:43`).
- Revizyon aynı maliyet + önceki liste özeti (24 satır ≈ +1k token).
---
## 2. Kredi kapısı
| Soru | Cevap | Kanıt |
|---|---|---|
| Liste kaç kredi? | **3** | `credits.ts:14` |
| Yeni kullanıcıda kaç kredi? | **5**, kayıt anında otomatik | `credits.ts:11`, `auth.ts:148-157` |
| Ücretsiz deneme var mı? | Evet ama **maskeli**: 24 satırın ilk 3'ü açık | `rapor-maske.ts:13`, `listem-icerik.tsx:144` |
| Revizyon deneme kredisiyle yapılabilir mi? | **Hayır** — paket şartı var | `rapor-actions.ts:215` |
| Sohbet? | 1 kredi/mesaj → kalan 2 kredi = 2 soru | `credits.ts:88-120` |
| Kredi bitince ne görüyor? | "Kredin bu liste için yetmiyor" + paket CTA (299 TL) ya da top-up (129 TL) | `liste-uretici.tsx:180-206` |
| `kredi_bitti` ölçülüyor mu? | Evet, istemcide; ayrıca `krediBittiIsaretle` 48 saatlik e-posta zamanlayıcısını kuruyor | `liste-uretici.tsx:121`, `credits.ts:206-225` |
### "Denemeden önce ödeme" hissi nerede
1. **Maske.** Deneme kullanıcısının aldığı yapay zekâ metni toplamda ~5 cümle: 3 gerekçe (her biri ≤15 kelime) + kırpılmış genel değerlendirme (ilk 2 cümle, `rapor-maske.ts:26-30`) + 1 uyarı. Kalan 21 satırda "Bu tercih için kişisel gerekçe paketle açılır." yazıyor. Yani **deneme, ürünü göstermiyor; paywall'u gösteriyor**.
2. **Sayfa başlığı.** Paketsiz kullanıcının liste sayfasının H1'i: *"Veriyi ücretsiz incele. Kararı Yapay Zeka ile netleştir."* (`listem-govde.tsx:186-188`) — kullanıcı az önce 3 kredisini yaktı, karşılandığı cümle bir satış cümlesi.
3. **Danışman kısıtı.** Kilitli satırları danışman da görmüyor ve sorulursa 299 TL'yi söylüyor (`api/soru/route.ts` kilitli dalı). Kalan 2 kredi yarım değerde.
4. **Yanlış vaat.** `/sonuc` tadımlık CTA'sı "24 satırın tamamı için giriş yap" diyor; teslim edilen 3/24. Bu hem dönüşüm hem güven sorunu.
---
## 3. Değeri üretmeden gösterme — **en önemli madde**
### Bugün elimizde ne var
| Varlık | Durum | Nerede gösteriliyor |
|---|---|---|
| **Tadımlık havuzu** — 522 satır, kova×tür×kategori×tip; genel 178 / devlet 170 / vakıf 174 [ölçüldü] | Dolu, **elle yazılmış** (LLM değil; KARARLAR 21 Eyl) | Yalnız `/sonuc`, **tek satır**, yalnız girişsize (`tadimlik-bolumu.tsx:12-13`) |
| **Deterministik 24'lük iskelet** — seçim + dilim + risk notu + trend cümlesi | Kod hazır, LLM gerekmiyor | **Hiçbir yerde** ürün öncesi gösterilmiyor |
| Ham dilim tablosu (hayal/dengeli/garanti) | Çalışıyor | `/sonuc`, `/universite/*`, `/bolum/*` |
| Ana sayfada örnek liste | **Yok** | — |
| `/meraklisina` demo | Var ama sayı/şema anlatımı, liste değil | `meraklisina-demo.tsx` |
**Sorun:** tadımlık, huninin en dar kapısının **arkasında**. 30 günde `/sonuc`'u 23 kişi gördü; katalogdan gelen 464 oturum yapay zekâ çıktısını hiç görmedi. `tadimlik_goruntulendi` 30 günde 0 (03 raporu §2) — gösterildiğine dair kanıt da yok.
### Öneri: "Senin 24'lük iskeletin" — 0 LLM çağrısı, 0 ek veri
Ölçüm [ölçüldü]: `havuzOlustur` + `dilimHedefiHesapla` + `riskNotuMetni` + `trendOzetiMetni` ile **24 satırın tamamı 2,1–72 ms'de, hiç LLM çağrısı yapmadan** kuruluyor. Örnek çıktı (750k/tyt):
```
1. [hayal] İnşaat Teknolojisi
risk : Son taban sıralaması senin sıranın üstünde kapandı; hayal tercihi olarak düşün.
trend: 2021-2026 arasında taban 1,1M düzeyinden 746B düzeyine indi; taban sıkılaştı.
```
Bunlar **kullanıcının kendi sıralamasına göre hesaplanmış gerçek cümleler** — jenerik örnek değil. Eksik olan tek şey `gerekce` (LLM'in tek cümlesi).
**Teknik yol:**
- **Veri kaynağı:** mevcut `yokatlas.db` + `rapor-havuzu.ts`. Yeni tablo, yeni betik, yeni env yok.
- **Üretim zamanı:** istek anında, sunucuda (RSC). SQL 2–72 ms.
- **Maliyet:** **0** — LLM'e hiç gidilmiyor, anonim istek zaten LLM'e gitmiyor (`tadimlik-havuzu.ts:1-4` kuralı korunur).
- **Ekran:** `/sonuc`'ta bugünkü tek tadımlık satırının yerine 24 satırlık gerçek iskelet; 1–3. satırların gerekçesi **tadımlık havuzundan** (kova×tür×kategori×tip anahtarıyla zaten eşleşiyor), 4–24 arası gerekçe alanı bulanık + "Giriş yap, yapay zekâ 24 gerekçeyi senin için yazsın". Yani bugünkü kilit deneyiminin **ücretsiz, dürüst ve kredi harcamayan** prova hâli.
- **Katalog sayfalarına taşınabilir hâli:** `/universite/*` ve `/bolum/*`'da sıra girildikten sonra aynı iskeletin ilk 5 satırı — 464 oturumluk trafiğe yapay zekâ çıktısının ne olduğunu ilk kez gösterir.
**Neden bu, LLM'li bir "örnek liste"den iyi:** kişiselleştirilmiş (kendi sırası, kendi illeri), bayatlamaz (canlı veriden), 0 TL, ve KARARLAR 21 Eyl'deki "tadımlık için LLM koşusu varsayılan yol değildir" kararıyla çelişmez.
**Alternatif (daha pahalı, önerilmez):** 6 kova × 5 tür = 30 hazır örnek listeyi batch üretmek ≈ 30 çağrı, ~135k girdi + ~45k çıktı token, tek seferlik. Prod veriye yazdığı için `[BİLAL]`. Elle yazım yolu (522 satırda yapıldığı gibi) bundan da ucuz.
---
## 4. Kalite ve güven
### Havuz-dışına çıkamama — **sağlam**
`normalizeEt` (`rapor.ts:120-137`) modelin döndürdüğü her id'yi `havuzMap`'te doğruluyor; havuzda olmayan ve tekrar eden id'ler **sessizce atılıyor**, dilim ise havuzdaki gerçek değerden **yeniden atanıyor**. Kurtarma dalı (`rapor.ts:349-385`) eksik dilimleri yine havuzdan deterministik dolduruyor. Modelin uydurduğu bir program kullanıcıya **ulaşamaz**. Bu korumaya dokunulmamalı.
### 24'lük iskelet — garanti edilen şey "24" değil
`dilimHedefiHesapla` ideal 5/13/6'dan sapabiliyor ve sapma sessiz:
- **5.000 / say / Mühendislik + İstanbul → 8 hayal / 6 dengeli / 10 garanti** [ölçüldü]. Bu listeye "dengeli ağırlıklı" demek mümkün değil.
- Aynı profilde **il filtresi tamamen düşürüldü** (`gevsetildi: ["il"]`): kullanıcı İstanbul seçti, havuz Türkiye geneline açıldı. `havuzOlustur` bunu `gevsetildi` olarak döndürüyor ama `raporUret` bunu yalnızca prompt'a not düşüyor (`rapor.ts:255-264`) — **`RaporKapsam`'a konmuyor** (`rapor.ts:105-111`), yani kullanıcı hiç öğrenmiyor. `uyarlandi` bayrağı yalnızca sayıların kaydığını söylüyor, **hangi seçiminin feda edildiğini söylemiyor.**
### "Bu bana özel" hissini taşıyan tek alan: `gerekce`
- `gerekce`: tek cümle, ≤15 kelime, sistem prompt'unda "METİN DİYETİ" olarak sıkıştırılmış (`rapor.ts:79-81`).
- `riskNotu` ve `trendOzeti` **deterministik** — aynı sıra bandındaki herkeste birebir aynı cümle. Kişisel okunmuyor.
- Kullanıcının sihirbazda girdiği **iller ve öncelikler çıktıda hiçbir yerde geri yansımıyor**; prompt'a giriyor ama satır düzeyinde görünür karşılığı yok.
- Paketsizde bu yüzeyin %87,5'i maskeli.
### Vaat dili denetimi — **prompt var, çıktı denetimi yok**
Prompt "garanti / kesin / yüzde yüz" diyor (`rapor.ts:80-86`), sohbet prompt'u da yasaklıyor (`api/soru/route.ts`). Ama **çıktı tarafında hiçbir denetim yok**: `gerekceServisEdilebilir` / `YASAK_GEREKCE_DILI` yalnızca tadımlıkta kullanılıyor (`tadimlik-havuzu.ts:62,91,126`). Rapor metinleri DB'ye yazılıyor (`rapor-actions.ts:181-195`) ve her `/listem` açılışında yeniden servis ediliyor — bir kez sızan "yüksek ihtimalle" cümlesi kalıcı. PROTOKOL/ilke 3'e aykırı ("prompt tek başına yetmez").
### İki iyileştirme önerisi (prompt/şema seviyesi)
**İ1 — Şemaya doğrulanabilir kişiselleştirme alanı ekle.** `AiTercihSchema`'ya `esles: z.enum([...kullanıcının gerçek kategorileri, illeri, öncelikleri, "genel"])` ekle. Enum kullanıcının kendi girdisinden üretildiği için model **uyduramaz**, kod çapraz doğrulayabilir ve UI satırın yanında bir çip basabilir ("İstanbul" / "Burs önceliğin" / "Mühendislik"). Maliyet: satır başına ~10 token (+~240 token/liste). Kazanç: kişiselleştirme **görünür** ve **denetlenebilir** hâle gelir. `[KARAR]` — ama iskelet değişikliği olduğu için `/meraklisina` şeması aynı commit'te güncellenmeli (AGENTS.md).
**İ2 — Çıktı denetimi + gevşetme dürüstlüğü.** (a) `gerekceServisEdilebilir`'i `lib/risk.ts` ya da ortak bir modüle taşıyıp rapor `gerekce` / `genelDegerlendirme` / `uyarilar` alanlarına da uygula; takılan satırın gerekçesi deterministik şablona düşsün ve sayaç tutulsun (§5'teki tek olay). (b) `gevsetildi`'yi `RaporKapsam`'a ekleyip UI'da tek cümle: "İstanbul'da 24 program çıkmadı; listeye yakın illerden de eklendi." Bu hem dürüstlük hem "beni gerçekten dinlemiş" sinyali. `[KARAR]`.
---
## 5. Sessiz hatalar
### Dallar ve ölçüm durumu
| # | Dal | Kod | Kredi | Ölçülüyor mu |
|---|---|---|---|---|
| a | Şema iki denemede de tutmadı | `rapor.ts:334-348` | iade | `liste_uretim_hata{kod:"HATA"}` — **yalnız 21 Eyl'den beri** |
| b | 429/5xx, 3 tekrar tükendi | `cagri.ts:41-59` | iade | aynı |
| c | 60 sn zaman aşımı | `cagri.ts:68,90` | iade | aynı |
| d | `AI_KEY_MISSING` | `client.ts:34` | iade | aynı (kullanıcıya altyapı sızmıyor — doğru) |
| e | Havuz < 3 program | `rapor.ts:236-240` | iade | aynı |
| f | **Kurtarma dalı: liste kuruldu ama satırlar şablon** | `rapor.ts:349-385` | harcandı | **HAYIR** — yalnız `console.warn`. `liste_olusturuldu` atılıyor, başarı sayılıyor |
| g | **Kullanıcı sekmeyi üretim sırasında kapattı** | `cagri.ts:63-67` notu | **iade edilemeyebilir** | **HAYIR** — hiç olay yok |
| h | İstemci tarafı istisna | `liste-uretici.tsx:95` | belirsiz | `kod:"ISTISNA"` |
| i | Kredi yetersiz | `liste-uretici.tsx:121` | harcanmadı | `kredi_bitti` |
| j | Oturum düşmüş (AUTH) | `liste-uretici.tsx:123-124` | harcanmadı | **HAYIR** — sessizce `/giris`'e atıyor |
### 3 listenin yanında kaç başarısız deneme var?
**Rybbit'ten ölçülemiyor.** `liste_uretim_hata` olayı `cf19903` (21 Eyl 2026 04:49) ile eklendi ve 03 raporu §0'a göre prod'a 21 Eyl ~15:20'de çıktı. 23 Ağu–21 Eyl penceresinin tamamı ölçüsüz.
**Ama prod DB'den bugün, kod değişmeden çıkarılabilir** — `credit_ledger`'da her deneme bir `report_generate` satırı, her başarısızlık aynı `ref_id`'li bir `refund` satırı bırakıyor (`rapor-actions.ts:119-124`, `171-176`). Salt okuma, Bilal koşar:
```sql
-- 30 günde liste üretim denemesi / başarısız (iade edilmiş) oranı
SELECT date(g.created_at,'unixepoch','localtime') AS gun,
COUNT(*) AS deneme,
SUM(CASE WHEN r.id IS NULL THEN 0 ELSE 1 END) AS basarisiz_iade
FROM credit_ledger g
LEFT JOIN credit_ledger r ON r.reason='refund' AND r.ref_id = g.ref_id
WHERE g.reason='report_generate'
AND g.created_at >= strftime('%s','now','-30 days')
GROUP BY 1 ORDER BY 1;
```
```sql
-- Kurtarma dalına düşmüş (şablon gerekçeli) liste sayısı
SELECT COUNT(*) FROM reports
WHERE result LIKE '%Sıralamana ve seçimlerine uygun olduğu için listene eklendi.%';
```
`deneme − basarisiz_iade` sayısı Rybbit'teki `liste_olusturuldu` = 3 ile de çapraz doğrulanır; aradaki fark sekme kapatan kullanıcıları (dal g) gösterir.
### Eklenecek tek olay
**`liste_uretim_kalite`** — üretim başarıyla bittiğinde sunucudan değil, mevcut `liste_olusturuldu` olayına **iki özellik ekleyerek** (yeni olay adı gerektirmez, `OlayAdi` birliği büyümez):
```
liste_olusturuldu { tur, sira_kovasi,
kurtarma: 0|1, // rapor.ts:349 dalına düşüldü mü
ai_satir: <sayı> } // AI'nın verdiği, havuzda doğrulanan satır sayısı
```
Bu tek ek, (f) dalını görünür kılar: "liste kuruldu" ile "yapay zekâ gerçekten 24 gerekçe yazdı" arasındaki farkı ölçer. `ListeSonuc`'a iki alan eklemek yeterli; prompt/model değişmez.
---
## Eval seti — bugün yok, kurulması öneriliyor
Repoda eval yok. Bu turda yalnız **iki maliyetsiz ölçüm** koşuldu (havuz boyutu; deterministik iskelet süresi). Gerçek modelle hiçbir koşu yapılmadı.
Önerilen: `scripts/eval-liste.ts` (`tsx`), girdi 12 temsilî profil (6 kova × say/ea/söz/tyt karışık, il-filtreli ve filtresiz, seçimsiz dahil). Ölçülecekler:
| Metrik | Hedef | Bugün nasıl ölçülür |
|---|---|---|
| Şema geçerliliği (1. denemede) | %100 | `yapilandirilmisUret` null dönüşü |
| Havuz-dışı program sayısı | **0** | `normalizeEt` öncesi/sonrası fark |
| Kurtarma dalına düşme oranı | 0 | `rapor.ts:353` warn'ı sayaca çevrilir |
| Yasak ifade sayısı (gerekce/genel/uyarılar) | **0** | `gerekceServisEdilebilir` |
| Dilim dağılımı ideale uzaklık | raporlanır | `dilimHedefiHesapla` vs `IDEAL_HEDEF` |
| p50/p95 gecikme | p95 < 30 sn | çağrı süresi |
| Girdi/çıktı token | raporlanır | API yanıtı `usage` |
`anahtarVar()` yoksa mock yolu koşar ve rapora "gerçek modelle koşulmadı" yazılır. Gerçek modelle bir tam koşu = **12 çağrı** (retry'la en kötü 24) — 50 çağrı sınırının altında, ayrı onay gerekmez; prod DB'ye yazmaz.
---
## Maliyet ve gecikme etkisi (önerilerin)
| Öneri | LLM çağrısı | Gecikme | Not |
|---|---|---|---|
| §3 "Senin iskeletin" önizlemesi | **0** | +2–72 ms SSR | Yeni tablo/betik yok |
| İ1 `esles` alanı | değişmez (1) | ihmal | +~240 token/liste (~%5 çıktı) |
| İ2 çıktı denetimi + `gevsetildi` | **0** | <1 ms (regex) | Saf fonksiyon |
| §5 iki olay özelliği | 0 | 0 | Yalnız ölçüm |
| Aşama mesajı + 90 sn eşiği | 0 | 0 | Metin/sabit |
Hiçbir öneri model, sağlayıcı ya da env değiştirmiyor; kredi başına maliyet aynı kalıyor.
---
## Önerilen değişiklikler
| # | Değişiklik | Dosya | Yetki |
|---|---|---|---|
| 1 | **Tadımlık CTA'sının vaadini ve hedefini düzelt:** metin "24 satırın tamamı" demesin (maske 3/24); `callback` `sonucHref()` yerine `LISTEM_URET_HREF` olsun | `tadimlik-satiri.tsx` | `[KARAR]` — metin marka/vaat içerdiği için son hâli Bilal onaylamalı |
| 2 | **§3 "Senin 24'lük iskeletin" önizlemesi** — 0 LLM, kendi sırasıyla, gerekçe bulanık | yeni bileşen + `sonuc/page.tsx` | `[KARAR]` (uygulama `cto`/`yazilimci` şartnamesiyle); `/meraklisina` şeması aynı commit'te |
| 3 | **İ2 çıktı denetimi:** yasak dil filtresi rapor metinlerine de | `rapor.ts`, `tadimlik-havuzu.ts`→ortak modül | `[KARAR]` |
| 4 | **`gevsetildi`'yi `RaporKapsam`'a ekle** ve UI'da tek cümle söyle | `rapor.ts:105`, `listem-govde.tsx` | `[KARAR]` |
| 5 | **Aşama mesajları 28 sn'de donmasın; "uzun sürdü" eşiği 90→55 sn** (ilk abort'tan önce) | `uretim-mesaji.ts`, `liste-uretici.tsx:45` | `[KARAR]` |
| 6 | **İ1 `esles` alanı** — şema + `/meraklisina` senkronu | `rapor.ts`, `huni-semasi.tsx` | `[KARAR]`, önce eval |
| 7 | **Deneme maskesini gevşet** (ör. ilk 3 yerine ilk 8 satır açık, ya da deneme listesinin tamamı açık + revizyon/PDF ücretli) | `rapor-maske.ts:13` | **`[BİLAL]`** — doğrudan gelir modeli kararı |
| 8 | Prod DB'de §5 sorgularını koş | — | **`[BİLAL]`** |
---
## Bilal'den istenen
1. **§5'teki iki SQL'i prod'da koş** (salt okuma) ve sonucu paylaş — "3 liste"nin yanında kaç deneme ve kaç şablon-gerekçeli liste olduğunu ancak bu söyler. (~5 dk)
2. **Karar ver: deneme kullanıcısı 24 satırın kaçını görecek?** Bugün 3; bu, denemenin ürünü değil paywall'u göstermesine yol açıyor ve `/sonuc`'taki CTA metnini fiilen yanlış kılıyor. (~10 dk, gelir modeli kararı)
3. **§3 önizlemesini (0 maliyet, 0 LLM) sıraya al mı?** Katalogdaki 464 oturuma yapay zekâ çıktısının ne olduğunu ilk kez gösterecek tek ucuz hamle bu. (~5 dk onay)