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>
33 KiB
26 — Veri mühendisi: programs.il temizliği (A4/T34) + vakıf burs etiketi (A5)
Tarih: 22 Eylül 2026, gece vardiyası · Rol: veri-muhendisi · Mod: yalnız teşhis.
Yazılan tek dosya: bu rapor. data/ altına, veritabanına, scripts/ altına hiç yazılmadı; tüm bağlantılar sqlite3 -readonly data/yokatlas.db. Kopya alınmadı (disk), pnpm install/build koşulmadı.
Kanıt işaretleri: [D] bu gece koşulan sorgu · [K] koddan çıkarım (dosya:satır) · [doğrulanmalı] birincil kaynakla teyit şart.
1. Beş maddelik özet
- Kök neden tek cümle:
il,fakulteveisimalanları yalnız INSERT yolunda yazılıyor, UPDATE yolunda hiç tazelenmiyor.scripts/refresh.ts:665-690— mevcut satıra yalnızsira/puan/kontenjan/yerlesenyazılır. Bu yüzden 2021'de üçüncü parti bir CSV'den (scripts/ingest.ts:4→yokatlas-dataset-2025) gelen konum ve ad değerleri kalıcı: API doğrusunu söylese bile DB'ye giremiyor.ilkirliliği bir "YÖK Atlas hatası" değil, bizim tazeleme hattımızın kör noktası. - A5'in cevabı: kırılım YAPILABİLİR, veri elimizde. Burs/dil etiketi YÖK Atlas API'sinde ayrı bir kolon değil,
birimAdialanının içinde geliyor ("Tıp (İngilizce) (Burslu)") —scripts/refresh.ts:37-39bunu açıkça yazıyor. Kanıt: 2026'da yeni açılan vakıf lisans satırlarının %93,7'si (326/348) etiketli, eskiden beri var olan satırların yalnız %14,2'si (628/4.427) etiketli [D]. Fark,--isim-esitlebayrağının varsayılan KAPALI olmasından geliyor. Tek koşuyla geri alınabilir. → T11 "kırılım var" tarafına düşer. - A4'ün rakamları: 21.493 satırın 20.092'si tam ve temiz 81 Türkiye ili, 1.291'i KKTC/yurt dışı, 110'u boş [D]. Türkiye tarafında eksik il yok, uydurma il yok — yani
/il/[slug](T7) yalnız bir filtreye ihtiyaç duyuyor, şema değişikliğine değil. - Yanlış
unitur100 satır (Kıbrıs Amerikan 42 + Uluslararası Balkan 34 + Uluslararası Saraybosna 24) [D] — bunlar sihirbazın "Devlet" adımında devlet programı gibi görünüyor. Ters yönde daha büyük bir sızıntı var ve şimdiye dek raporlanmamış: sihirbazın "Vakıf (burslu olursa)" kovasıunitur <> 'DEVLET'ile kurulduğu için (src/lib/db.ts:77-83) içine 1.256 KKTC/yurt dışı satırı giriyor — vakıf havuzunun %13,4'ü. - Kapsam dışı ama yayını etkileyen bulgu:
kontenjan<yıl>kolonu yalnız genel kontenjanı tutuyor (kontenjan2025 = gk2025, 19.857/19.857 satır),yerlesen<yıl>ise tüm kota türlerinin toplamı (gkY+sgyY+dprmY+obkY,scripts/refresh.ts:212-217). Bu yüzden devlet lisans doluluğu %102,1 çıkıyor [D] — matematiksel olarak imkânsız. Bu gece yayımlananbilgisayar-mi-yazilim-muhendisligi-miyazısındaki "devlet YM %102,1" rakamı bu sapmadır. KKTC ve vakıf rakamları etkilenmiyor (KKTC'de aşan satır 0; devlet lisansta 5.618) — yanikktc-universiteleri-okunur-muyazısı güvende.
2. Veri kalitesi tablosu
| # | Kontrol | Sorgu (hepsi sqlite3 -readonly data/yokatlas.db) |
Sonuç | Önem |
|---|---|---|---|---|
| K1 | Farklı il değeri sayısı |
SELECT COUNT(DISTINCT il) FROM programs |
91 (81 TR ili + 6 KKTC + 4 yurt dışı) | bilgi |
| K2 | Boş il |
SELECT COUNT(*) FROM programs WHERE il IS NULL |
110 satır / 9 kurum; hepsi son_kilavuz_yili=2026 |
P1 |
| K3 | TR dışı il satırı |
WHERE il IN ('LEFKOŞA','GİRNE','GAZİMAĞUSA','LEFKE','GÜZELYURT','KIBRIS','SARAYBOSNA - BOSNA - HERSEK','BİŞKEK-KIRGIZİSTAN','TÜRKİSTAN-KAZAKİSTAN','BAKÜ-AZERBAYCAN') |
1.291 | P1 |
| K4 | TR ili tam mı | aynı listenin NOT IN'i + COUNT(DISTINCT il) |
81/81 — eksik il yok, fazla il yok | ✓ temiz |
| K5 | Yanlış unitur='DEVLET' |
WHERE unitur='DEVLET' AND (universite LIKE 'KIBRIS AMERİKAN%' OR LIKE '%BALKAN%' OR LIKE '%SARAYBOSNA%') |
100 satır | P1 |
| K6 | "Vakıf" kovasının saflığı | WHERE unitur IS NOT NULL AND unitur<>'DEVLET' GROUP BY unitur |
VAKIF 7.974 · KKTC 1.145 · VAKIF MYO 121 · YURTDISI KAMU 99 · YURTDISI VAKIF 12 | P1 |
| K7 | unitur boş |
WHERE unitur IS NULL |
0 ✓ (unitur-onar.ts işini yapmış) |
✓ |
| K8 | Aynı kurumun iki universite yazımı |
bazAd çakışma sorgusu (§3.4) |
95 kurum / 1.449 satır — bildirilen "10 KKTC üniversitesi" değil, katalogun tamamı | P2 |
| K9 | Aynı kurumda iki farklı unitur |
K8 sorgusunun unitur kırılımı |
4 kurum: Balkan, Saraybosna, Manas, Yesevi (DEVLET↔YURTDISI KAMU / KAMU↔VAKIF) | P1 |
| K10 | Ayırt edilemeyen program adı (2026 aktif) | GROUP BY universite,isim,tur,onlisans HAVING COUNT(*)>1 |
4.206 grup / 10.164 satır (Vakıf 6.079 · Devlet 3.209 · KKTC 985) | P1 |
| K11 | Vakıf lisansta burs etiketi | §4 sorgusu | 3.821/4.775 etiketsiz (KKTC 747/849) — bildirilen rakam doğrulandı | P1 |
| K12 | Etiketin satır yaşıyla ilişkisi | §4 sorgusu | 2026'da yeni: 326/348 etiketli; eskiden var olan: 628/4.427 | kanıt |
| K13 | yerlesen > kontenjan |
WHERE yerlesen2026 > kontenjan2026 |
11.964/21.493 satır; devlet lisansta 5.618, KKTC lisansta 0 | P1 |
| K14 | kontenjan = genel kontenjan mı |
kontenjan2025 <> gk2025 |
0 satır → evet, yalnız genel kontenjan | kanıt |
| K15 | netler yetim satırı |
LEFT JOIN programs ... WHERE p.id IS NULL |
8.215 satır (silinmiş/kimliği devredilmiş kodlara ait) | P2 |
| K16 | netler yıl kapsamı |
SELECT MAX(yil) FROM netler |
2025 — T36 doğrulandı, 2026 net verisi yok | P1 |
| K17 | Aykırı sıralama | WHERE sira2026<=0 |
0 ✓ | ✓ |
| K18 | fakulte boş (2026 aktif) |
WHERE fakulte IS NULL AND kontenjan2026 IS NOT NULL |
0 ✓ | ✓ |
3. Görev 1 — programs.il (A4 / T34)
3.1 Bildirilen bulguların tek tek doğrulanması
| Bildirilen | Durum | Kanıt |
|---|---|---|
91 farklı il değeri |
DOĞRU | K1 |
il boş 110 satır / 9 üniversite |
DOĞRU | K2; kurum listesi §3.2 |
Uluslararası Balkan Ü. 26 satır il='SARAYBOSNA - BOSNA - HERSEK', kurum Üsküp'te |
DOĞRU (26 satır) — ayrıca aynı kurumun 8 satırı il boş, 14 satırı ayrı adla YURTDISI KAMU |
§3.2 |
Kıbrıs Amerikan Ü. 42 satır unitur='DEVLET' |
DOĞRU (36 + 6, iki ad hattı) | K5 |
src/lib/db.ts:79 devlet filtresi bunları devlet sayıyor |
DOĞRU | uniturFiltreSql, src/lib/db.ts:77-83 [K] |
10 KKTC üniversitesi iki ayrı universite adıyla duruyor |
DOĞRU ama eksik tarif — aynı desen 95 kurumda var (1.449 satır). KKTC'ye özgü değil, API'nin 2026 ad biçiminden geliyor | K8 |
ODTÜ KKK programları ana kampüsle aynı universite ve il altında |
YARI ÇÜRÜTÜLDÜ. 8 KKK satırı il='KIBRIS' ve fakulte='ODTÜ Kuzey Kıbrıs Kampusu (KKTC-Güzelyurt)' taşıyor — yani ayrılabilir. Ortak olan yalnız universite. Ama ODTÜ Yazılım Mühendisliği'nin 2 satırı gerçekten il='ANKARA', fakulte='Mühendislik Fakültesi' ile duruyor → yazarın asıl iddiası doğru, sebebi farklı |
§3.3 |
3.2 Boş il: 110 satır, 9 kurum, hepsi 2026 kılavuzundan
SELECT universite, unitur, COUNT(*) FROM programs WHERE il IS NULL GROUP BY 1,2 ORDER BY 3 DESC;
| Kurum | unitur |
Satır | il nereden türetilebilir |
|---|---|---|---|
| TİRAN NEW YORK ÜNİVERSİTESİ (TİRAN-ARNAVUTLUK) | YURTDISI KAMU | 36 | ad parantezi |
| İÇİŞLERİ BAKANLIĞI VE MİLLİ SAVUNMA BAKANLIĞI ADINA SAĞLIK BİLİMLERİ ÜNİVERSİTESİNDE EĞİTİM ALACAKLAR | DEVLET | 15 | türetilemez (sahte kurum adı; bakanlık kontenjanı) |
| ULUSLARARASI BALKAN ÜNİVERSİTESİ (ÜSKÜP-MAKEDONYA) | YURTDISI KAMU | 14 | ad parantezi |
| ULUSLARARASI SARAYBOSNA ÜNİVERSİTESİ (SARAYBOSNA-BOSNA-HERSEK) | YURTDISI KAMU | 14 | ad parantezi |
| ULUSLARARASI SARAYBOSNA ÜNİVERSİTESİ | DEVLET | 9 | kardeş satırdan |
| ULUSLARARASI BALKAN ÜNİVERSİTESİ | DEVLET | 8 | kardeş satırdan (Üsküp, Saraybosna değil) |
| KIRGIZİSTAN-TÜRKİYE MANAS ÜNİVERSİTESİ (BİŞKEK-KIRGIZİSTAN) | YURTDISI VAKIF | 8 | ad parantezi |
| HOCA AHMET YESEVİ … (TÜRKİSTAN-KAZAKİSTAN) | YURTDISI VAKIF | 4 | ad parantezi |
| KIBRIS AMERİKAN ÜNİVERSİTESİ | DEVLET | 2 | kardeş satırdan (LEFKOŞA) |
95 satır ad/kardeş satırdan doldurulabilir; 15 satır (MSB/İçişleri) doldurulamaz — ÖSYM bunları tek bir yerleşkeye bağlamıyor. Tahminle doldurmuyoruz; eksik, eksik kalır ve veri-kalite'de beyaz listeye alınır.
3.3 Kök neden — hangi betik hangi alanı nereden yazıyor
| Alan | Yazan | Kaynak | UPDATE yolunda tazeleniyor mu |
|---|---|---|---|
il |
ingest.ts (2021 CSV) → sonra yalnız refresh.ts INSERT (r.ilAdi, satır 679) |
üçüncü parti CSV, sonra API | HAYIR |
unitur |
ingest.ts CSV → refresh.ts INSERT uniturSec() (518-524) → unitur-onar.ts yalnız NULL'lar |
CSV, sonra API (koşullu) | HAYIR |
fakulte |
ingest.ts CSV → refresh.ts INSERT fakulteSec() |
CSV, sonra API | HAYIR |
isim |
ingest.ts CSV → refresh.ts INSERT r.birimAdi; UPDATE yalnız --isim-esitle ile (643-648) |
CSV, sonra API | bayrak kapalıyken HAYIR |
sira/puan/kontenjan/yerlesen |
refresh.ts UPDATE (474-480) |
API | evet |
Üç mekanizma üst üste biniyor:
(a) UPDATE körlüğü. refresh.ts:665-680 — if (exists.get(id)) update.run(...) yalnız dört yıl kolonunu yazar. 2021 CSV'sinden gelen il/fakulte/isim beş yıldır hiç tazelenmedi. Kıbrıs Amerikan'ın 36 satırı il='LEFKOŞA', Balkan'ın 26 satırı il='SARAYBOSNA - BOSNA - HERSEK' — ikisi de 2021 verisi taşıyor (kontenjan2021 IS NOT NULL), yani CSV kökenli [D].
(b) uniturSec yanlışı kalıcılaştırıyor. refresh.ts:519-525:
const uniturSec = (universite: string, api: string | null): string | null => {
for (const k of [universite, bazAd(universite)]) {
const set = uniturlar.get(k);
if (set?.size === 1) return [...set][0]; // ← DB'deki değer API'yi EZİYOR
}
return api;
};
Niyet doğru (sözlük tutarlılığı, uniturOnar'ın çelişki koruması patlamasın diye), sonuç ters: API "KKTC" dese bile DB'de tek bir DEVLET varsa DEVLET yazılır. Kıbrıs Amerikan'ın 2026'da eklenen 6 yeni satırı bu yüzden de DEVLET oldu.
(c) İki ayrı ad hattı = iki ayrı kaynak. API 2026'da üniversite adını AD (İL) biçiminde veriyor (ORTA DOĞU TEKNİK ÜNİVERSİTESİ (ANKARA), DOĞU AKDENİZ ÜNİVERSİTESİ (KKTC-GAZİMAĞUSA)). CSV ise sade ad + ayrı il veriyordu. Böylece 95 kurumda iki paralel ad hattı oluştu:
-- K8
WITH b AS (SELECT universite, unitur, il,
TRIM(CASE WHEN universite LIKE '%)' THEN substr(universite,1,instr(universite,' (')-1)
ELSE universite END) baz, COUNT(*) n
FROM programs GROUP BY 1,2,3)
SELECT baz, universite, unitur, COALESCE(il,'(NULL)'), n FROM b
WHERE baz IN (SELECT baz FROM b GROUP BY baz HAVING COUNT(DISTINCT universite)>1);
-- 95 kurum / 1.449 satır
Yıl profili: AD (TR ili) eki 1.224 satır/80 kurum · AD (KKTC-şehir) 149/10 · AD (şehir-ülke) 76/5 [D].
ODTÜ örneği — sorunun tam resmi. universite='ORTA DOĞU TEKNİK ÜNİVERSİTESİ (ANKARA)' altında 11 satır var: 3'ü il='ANKARA' (KKTC uyruklu kontenjanı, doğru), 8'i il='KIBRIS' + fakulte='ODTÜ Kuzey Kıbrıs Kampusu (KKTC-Güzelyurt)' (doğru). Ama universite='ORTA DOĞU TEKNİK ÜNİVERSİTESİ' altındaki 72 eski CSV satırının içinde Yazılım Mühendisliği de var:
SELECT universite, il, fakulte, isim, kontenjan2026, sira2026
FROM programs WHERE isim LIKE 'Yazılım Müh%' AND universite LIKE 'ORTA DOĞU%';
-- ORTA DOĞU TEKNİK ÜNİVERSİTESİ | ANKARA | Mühendislik Fakültesi | Yazılım Mühendisliği | 45 | 299241
-- ORTA DOĞU TEKNİK ÜNİVERSİTESİ | ANKARA | Mühendislik Fakültesi | Yazılım Mühendisliği | 5 | 293024
ODTÜ Ankara'da Yazılım Mühendisliği yoktur; program Kuzey Kıbrıs Kampusu'ndadır (ncc.metu.edu.tr/tr/sng, yazar 13 teyit etmiş) [doğrulanmalı: 2026 ÖSYM kılavuzu]. 45/5 kontenjan ikilisi de KKK'nin klasik Burslu / %50 İndirimli desenidir — ama iki satırın adı birebir aynı, çünkü A5'teki etiket kaybı tam burada vuruyor. Yani üç hata aynı satırda: yanlış il, yanlış fakulte, kayıp burs etiketi. Aynı desen ODTÜ'de 16 ad grubunda daha var (Bilgisayar Müh. ×3 → 105/65/65, Elektrik-Elektronik ×3, İşletme ×6 …) [D].
3.4 Etki haritası — hangi yüzey ne yanlış gösteriyor
| Yüzey | Dosya | Ne oluyor | Etkilenen |
|---|---|---|---|
| Sihirbaz "Devlet" adımı | src/lib/db.ts:78 unitur = 'DEVLET' |
KKTC ve Balkan/Saraybosna programları devlet üniversitesi gibi havuza giriyor | 100 satır |
| Sihirbaz "Vakıf (burslu olursa)" adımı | src/lib/db.ts:79-80 unitur <> 'DEVLET' |
KKTC (1.145) + yurt dışı (111) satırı vakıf havuzuna giriyor; etiket kaybı yüzünden öğrenci hangisinin burslu olduğunu da göremiyor | 1.256 satır / havuzun %13,4'ü |
| Sihirbaz il adımı (facet) | src/lib/db.ts:325-327 — kodda not düşülmüş: "81 il + KKTC/yurtdışı" |
DAÜ'nün 276 satırı GAZİMAĞUSA ve KIBRIS çiplerine bölünmüş; aynı bölünme 9 KKTC kurumunda var | 1.080 satır |
/universiteler hub'ı |
src/lib/katalog.ts:270-337 |
MAX(unitur) + alfabetik ilk ad hattı kazanıyor → Uluslararası Balkan Ü. "Devlet / Saraybosna" görünüyor (doğrusu: yurt dışı kamu / Üsküp) |
3 kurum kartı |
/universite/<slug> |
src/lib/katalog.ts:402 stats.devletMi |
Kıbrıs Amerikan Ü. sayfasında "devlet üniversitesi" rozeti | 1 sayfa |
| il faceti / il listesi | aynı | il boş 110 satır hiçbir il filtresine düşmüyor — sessizce kayboluyor |
110 satır |
/il/[slug] planı (T7, #18 yazısı) |
henüz yok | Bugünkü SELECT DISTINCT il 91 değer döner → /il/baku-azerbaycan, /il/kibris gibi sayfalar üretilir |
önkoşul |
| Bu gecenin yazıları | content/rehber/bilgisayar-mi-yazilim-muhendisligi-mi.md |
ODTÜ head-to-head tablodan çıkarılmış ve neden çıkarıldığı yazıda yazılmış → doğru davranış, düzeltme gerekmiyor. Ama aynı yazının devlet doluluk rakamları §5'teki kota asimetrisinden sapmalı | 1 yazı, 2 rakam |
content/rehber/kktc-universiteleri-okunur-mu.md |
KKTC evreni unitur='KKTC' OR universite LIKE 'KIBRIS AMERİKAN%' ile elle kurulmuş → yazı doğru; düzeltme sonrası sorgu sadeleşir, rakam değişmez |
— |
3.5 Önerilen şema — yeni kolon yok
Soru "il yanında ulke/bolge mi, yoksa ayrı kampus alanı mı" şeklinde soruldu. Cevabım: ikisi de değil. Her iki bilgi de zaten DB'de:
- Ülke/statü ayrımı
unitur'de yaşıyor:DEVLET · VAKIF · VAKIF MYO · KKTC · YURTDISI KAMU · YURTDISI VAKIF. Birulkekolonu bu sözlüğün kopyasını çıkarır ve iki alanın çelişme ihtimalini yaratır. - Kampüs bilgisi
fakulte'de yaşıyor:ODTÜ Kuzey Kıbrıs Kampusu (KKTC-Güzelyurt),ASBÜ-Kuzey Kıbrıs Yerleşkesi (KKTC-Lefkoşa),İTÜ-KKTC EĞİTİM ARAŞTIRMA YERLEŞKESİ (GAZİMAĞUSA)[D].
A) ulke/bolge kolonu |
B) il normalize + kampus kolonu |
C) Kolon yok: il'i normalize et, unitur'ü düzelt |
|
|---|---|---|---|
| Göç | yokatlas-goc.ts + ingest.ts + refresh.ts INSERT + veri-kalite.ts |
aynısı | yok |
| Dolduran kaynak | API'de böyle bir alan yok — ad parantezinden türetmek zorundayız | aynı sorun | ad parantezi (aynı iş, kolonsuz) |
| Yıllık refresh maliyeti | her yıl yeni kolonun da senkronu | aynı + kampus eşlemesi |
il senkronu (zaten yapılmalı) |
| Okuyan taraf değişikliği | katalog.ts, db.ts, facet, tipler |
aynısı + tipler | tek satır filtre: AND unitur IN ('DEVLET','VAKIF','VAKIF MYO') |
T7 (/il/[slug]) çözülür mü |
evet | evet | evet |
| Çift kaynak riski | unitur ile çelişebilir |
fakulte ile çelişebilir |
yok |
Öneri C. İki UPDATE + bir satır kod. Kurucunun "over-engineering yapma" talimatına uyan en küçük çözüm.
C'nin tek gerçek açığı, şema değil hat açığı: il/fakulte/isim UPDATE yolunda tazelenmediği sürece aynı kir her yıl birikir. Bunun kolonla ilgisi yok — çözümü refresh.ts'e --kimlik-onar/--isim-esitle ile aynı güvenlik desenini taşıyan bir --yer-esitle bayrağı: API ile il/fakulte farkı olan satırları önce listeler, gözle onaylanınca yazar. Ayrı bir CTO şartnamesine değer; bu gece yazılmaz.
3.6 Düzeltme betiği taslağı — KOŞULMADI, yalnız yazıldı
Ön koşullar: dev sunucu kapalı (WAL tek yazar), önce yedek, sonra pnpm veri-kalite --yil 2026.
# 0) Yedek — geri alma yolu budur. WAL'i önce kapat.
sqlite3 data/yokatlas.db "PRAGMA wal_checkpoint(TRUNCATE);"
cp data/yokatlas.db data/yokatlas.db.yedek-2026-09-22
BEGIN;
-- ── 1) unitur: yanlış DEVLET etiketleri (K5 = 100 satır) ────────────────
-- Kıbrıs Amerikan Ü. YÖK'ün KKTC listesinde (yok.gov.tr/tr/university?type=6)
UPDATE programs SET unitur='KKTC'
WHERE unitur='DEVLET' AND universite LIKE 'KIBRIS AMERİKAN%'; -- 42
-- Balkan + Saraybosna: aynı kurumun diğer ad hattı zaten YURTDISI KAMU
UPDATE programs SET unitur='YURTDISI KAMU'
WHERE unitur='DEVLET'
AND (universite LIKE 'ULUSLARARASI BALKAN%'
OR universite LIKE 'ULUSLARARASI SARAYBOSNA%'); -- 58
-- ── 2) il: KKTC'de 'KIBRIS' toplayıcısını şehre indir (179 satır) ───────
-- Şehir zaten ad ya da fakülte parantezinde yazılı; tahmin YOK.
UPDATE programs SET il = CASE
WHEN universite LIKE '%(KKTC-LEFKOŞA)%' THEN 'LEFKOŞA'
WHEN universite LIKE '%(KKTC-GİRNE)%' THEN 'GİRNE'
WHEN universite LIKE '%(KKTC-GAZİMAĞUSA)%' THEN 'GAZİMAĞUSA'
WHEN universite LIKE '%(KKTC-LEFKE)%' THEN 'LEFKE'
WHEN fakulte LIKE '%(KKTC-Lefkoşa)%' THEN 'LEFKOŞA'
WHEN fakulte LIKE '%(KKTC-Güzelyurt)%' THEN 'GÜZELYURT'
WHEN fakulte LIKE '%(GAZİMAĞUSA)%' THEN 'GAZİMAĞUSA'
END
WHERE il='KIBRIS'
AND (universite LIKE '%(KKTC-%' OR fakulte LIKE '%(KKTC-%' OR fakulte LIKE '%(GAZİMAĞUSA)%');
-- beklenen: 179; sonrasında SELECT COUNT(*) FROM programs WHERE il='KIBRIS' = 0
-- ── 3) il: yurt dışı değerini mevcut sözleşmeye uydur (26 satır) ────────
-- Mevcut sözleşme: 'ŞEHİR-ÜLKE' (BİŞKEK-KIRGIZİSTAN, TÜRKİSTAN-KAZAKİSTAN)
UPDATE programs SET il='ÜSKÜP-KUZEY MAKEDONYA'
WHERE universite='ULUSLARARASI BALKAN ÜNİVERSİTESİ' AND il='SARAYBOSNA - BOSNA - HERSEK'; -- 26
UPDATE programs SET il='SARAYBOSNA-BOSNA HERSEK'
WHERE il='SARAYBOSNA - BOSNA - HERSEK'; -- 15
-- ── 4) il: boş 110 satırın 95'i (kalan 15 bilerek NULL) ─────────────────
UPDATE programs SET il = CASE
WHEN universite LIKE '%(TİRAN-ARNAVUTLUK)%' THEN 'TİRAN-ARNAVUTLUK'
WHEN universite LIKE '%(ÜSKÜP-MAKEDONYA)%' THEN 'ÜSKÜP-KUZEY MAKEDONYA'
WHEN universite LIKE '%(SARAYBOSNA-BOSNA-HERSEK)%' THEN 'SARAYBOSNA-BOSNA HERSEK'
WHEN universite LIKE '%(BİŞKEK-KIRGIZİSTAN)%' THEN 'BİŞKEK-KIRGIZİSTAN'
WHEN universite LIKE '%(TÜRKİSTAN-KAZAKİSTAN)%' THEN 'TÜRKİSTAN-KAZAKİSTAN'
WHEN universite='ULUSLARARASI BALKAN ÜNİVERSİTESİ' THEN 'ÜSKÜP-KUZEY MAKEDONYA'
WHEN universite='ULUSLARARASI SARAYBOSNA ÜNİVERSİTESİ' THEN 'SARAYBOSNA-BOSNA HERSEK'
WHEN universite='KIBRIS AMERİKAN ÜNİVERSİTESİ' THEN 'LEFKOŞA'
END
WHERE il IS NULL
AND universite <> 'İÇİŞLERİ BAKANLIĞI VE MİLLİ SAVUNMA BAKANLIĞI ADINA SAĞLIK BİLİMLERİ ÜNİVERSİTESİNDE EĞİTİM ALACAKLAR';
-- beklenen: 95; kalan 15 MSB/İçişleri satırı NULL kalır (kaynak da boş veriyor)
COMMIT;
Doğrulama sorguları (düzeltmeden sonra koşulur):
SELECT COUNT(DISTINCT il) FROM programs; -- beklenen 88 (81 TR + 5 KKTC şehri + ... )
SELECT COUNT(*) FROM programs WHERE il IS NULL; -- beklenen 15
SELECT COUNT(*) FROM programs WHERE il='KIBRIS'; -- beklenen 0
SELECT COUNT(*) FROM programs WHERE unitur='DEVLET'
AND (universite LIKE 'KIBRIS AMERİKAN%' OR universite LIKE '%BALKAN%'
OR universite LIKE '%SARAYBOSNA%'); -- beklenen 0
SELECT COUNT(DISTINCT il) FROM programs
WHERE unitur IN ('DEVLET','VAKIF','VAKIF MYO'); -- beklenen 81 ← T7'nin kabul kriteri
SELECT SUM(kontenjan2026), SUM(yerlesen2026) FROM programs; -- düzeltmeden ÖNCEKİYLE AYNI olmalı
Geri alma: data/yokatlas.db.yedek-2026-09-22 dosyasını geri kopyala. Betik yalnız 4 kolonsuz alana dokunuyor, sıralama/kontenjan verisine hiç dokunmuyor — son doğrulama sorgusu bunu kanıtlar.
Birlikte gitmesi gereken kod değişikliği (tek satır): /il/[slug] ve il faceti AND unitur IN ('DEVLET','VAKIF','VAKIF MYO') ile süzülmeli; yoksa /il/uskup-kuzey-makedonya üretilir. Sihirbazın "Vakıf" kovası da unitur IN ('VAKIF','VAKIF MYO') olmalı (src/lib/db.ts:79) — bu ayrı bir ürün kararı: KKTC programları havuzdan çıkarsa vakıf havuzu 9.351 → 8.095 satıra iner. [BİLAL] değil, urun-yoneticisi/ceo kararı.
İdempotens uyarısı: betik koşulduktan sonra unitur-onar.ts'in çelişki koruması (aynı üniversitede birden fazla unitur) hâlâ geçer — Balkan/Saraybosna'nın iki ad hattı farklı universite dizgileri olduğu için ayrı gruplar sayılıyor [K].
4. Görev 2 — vakıf burs etiketi (A5)
Tek cümlelik cevap
Etiket YÖK Atlas API'sinde ayrı bir alan değil, program adının (birimAdi) içinde geliyor; veri elimizde ve kırılım yapılabilir — bugün eksik olmasının sebebi refresh.ts'in --isim-esitle bayrağının varsayılan kapalı olması, kaynağın etiketi vermemesi değil.
Kanıt zinciri
(1) Kodun kendi belgesi — scripts/refresh.ts:37-39:
--isim-esitle: kimliği AYNI olup yalnız adı farklı satırlarda (API burs/dil eki veriyor: "Tıp (İngilizce) (Burslu)") isim API'den yazılır. Varsayılan KAPALI: isim, sihirbaz kategorilerini ve bölüm sayfası başlığını besler.
Yani etiketin kaynağı biliniyor ve yazılmaması bilinçli bir seçim. Gerekçe de meşru: isim sihirbaz kategorilerini besliyor, "Tıp (Burslu)" ile "Tıp" farklı kategoriye düşebilir.
(2) API isteği burs boyutunu tanıyor — refresh.ts:181 filtre nesnesinde bursOraniId: null var; yani uç nokta burs oranına göre süzmeyi destekliyor. Ama yanıt kaydından tutulan alanlar listesinde (TUTULAN_ALANLAR, satır 124-148) burs alanı yok — ham .jsonl.gz dosyası kaydın tamamını yazıyor (refresh.ts:378), ince kayıt değil, ama data/ham/ bu makinede mevcut değil (.gitignore:48), bu yüzden API yanıtında ayrı bir bursOrani alanı olup olmadığı yerel olarak doğrulanamadı [doğrulanmalı — tek --ham koşusuyla ya da 1 isteklik size:1 sorgusuyla 2 dakikada kapanır].
(3) Asıl kanıt — satır yaşına göre etiketlilik. Yeni satırlar INSERT'te r.birimAdi'yi doğrudan yazıyor (refresh.ts:677), eski satırların adı hiç güncellenmiyor:
SELECT CASE WHEN sira2025 IS NOT NULL OR kontenjan2025 IS NOT NULL
THEN '2025te de vardi' ELSE '2026da yeni' END durum,
COUNT(*) n,
SUM(isim LIKE '%(Burslu)%' OR isim LIKE '%İndirimli)%' OR isim LIKE '%(Ücretli)%') etiketli
FROM programs
WHERE kontenjan2026 IS NOT NULL AND onlisans=0 AND unitur LIKE 'VAKIF%'
GROUP BY 1;
| Satır | n | Etiketli | Oran |
|---|---|---|---|
| 2026'da yeni açılan (isim API'den yazıldı) | 348 | 326 | %93,7 |
| 2025'te de var olan (isim 2021 CSV'sinden) | 4.427 | 628 | %14,2 |
Aynı veri, aynı kurumlar, aynı yıl — tek fark satırın INSERT mi UPDATE mi yolundan geçtiği. API etiketi veriyor; biz yazmıyoruz.
(4) veri_meta kaydı da aynı şeyi gösteriyor. kimlik_onar:* kayıtlarının yeni.isim alanları API'den geldiği gibi duruyor: "Ebelik (Burslu)", "Ebelik (%50 İndirimli)", "Siber Güvenlik (Burslu) (İngilizce)", "Endüstri Mühendisliği (Ücretli)", "Anestezi (%25 İndirimli)" [D]. Etiket sözlüğü tam: Burslu · %75/%50/%25 İndirimli · Ücretli.
Bugünkü kırılım (bildirilen rakamlar doğrulandı)
SELECT CASE WHEN unitur LIKE 'VAKIF%' THEN 'Vakıf' WHEN unitur='KKTC' THEN 'KKTC'
WHEN unitur='DEVLET' THEN 'Devlet' ELSE unitur END grup,
SUM(onlisans=0) lisans,
SUM(onlisans=0 AND isim LIKE '%(Burslu)%') burslu,
SUM(onlisans=0 AND isim LIKE '%İndirimli)%') indirimli,
SUM(onlisans=0 AND isim LIKE '%(Ücretli)%') ucretli,
SUM(onlisans=0 AND isim NOT LIKE '%(Burslu)%' AND isim NOT LIKE '%İndirimli)%'
AND isim NOT LIKE '%(Ücretli)%') etiketsiz
FROM programs WHERE kontenjan2026 IS NOT NULL GROUP BY 1;
| Grup | 2026 lisans | Burslu | İndirimli | Ücretli | Etiketsiz |
|---|---|---|---|---|---|
| Devlet | 6.505 | 9 | 39 | 13 | 6.444 (beklenen — devlette burs etiketi olmaz) |
| Vakıf | 4.775 | 339 | 416 | 199 | 3.821 (%80,0) |
| KKTC | 849 | 39 | 51 | 12 | 747 (%88,0) |
| Yurt dışı kamu | 98 | 14 | 31 | 19 | 34 |
Yazarların bildirdiği 3.821/4.775 ve (873 payda ile) 768/873 rakamları doğrulandı; payda farkı (849 vs 873) yalnız KKTC evreninin unitur='KKTC' mi yoksa + Kıbrıs Amerikan mı tanımlandığına bağlı — A4 düzeltmesinden sonra iki tanım birleşiyor.
data/kaynak/ altındaki dosyalarda burs bilgisi var mı
Yok. Oradaki iki dosya kurum düzeyinde YÖK istatistiği:
yok-istatistik-ogrenci-sayilari-2025-2026.xls— sütunları:Okuyan Önlisans · Okuyan Lisans · Okuyan Yükseklisans · Okuyan Doktora · Genel Toplam, satırları üniversite × il × (DEVLET/VAKIF/KKTC).yok-istatistik-ogretim-elemani-sayilari-2025-2026.xls— öğretim elemanı sayıları.
İkisi de program düzeyinde değil, burs/ücret alanı içermiyor (JasperReports dökümü; file + strings ile başlık satırları okundu, dosyalar değiştirilmedi). Bu dosyalar A5 için kullanılamaz; başka bir işe (kurum büyüklüğü/öğrenci-öğretim üyesi oranı içerikleri) yarayabilir.
Yazarlara verilecek net cevap
Kırılım bugün yapılamaz, ama kalıcı olarak imkânsız değil. Veri kaynakta var; DB'ye tek bir refresh koşusuyla girer. Bu koşu yapılana kadar hiçbir yazıda burslu/%50/ücretli dağılımı verilmesin — bugünkü sayımlar (%80'i etiketsiz) gerçek dağılım değil, tazelenmemiş adların sayımıdır ve yayımlanırsa yanlış olur.
Bu koşunun bedeli ve riski (Bilal/CTO için)
# ÖNCE kopyada: ham dosya yoksa API'den tek geçiş (~22 sn/21.493 kayıt, 0,5 sn/sayfa)
cp data/yokatlas.db /tmp/deneme.db
pnpm refresh --yil 2026 --db /tmp/deneme.db --isim-esitle
pnpm veri-kalite --yil 2026 --db /tmp/deneme.db --onceki data/yokatlas.db
- Etkilenecek satır: kabaca 10.164 (K10'daki ayırt edilemeyen ad grupları); kesin sayıyı koşunun
"yalnız adı (burs/dil eki) farklı N satır"satırı verir (refresh.ts:609). - Risk — küçümsenmemeli:
isimsihirbaz kategorilerini (src/lib/kategoriler.ts) ve/bolum/<slug>başlıklarını besliyor. "Bilgisayar Mühendisliği" → "Bilgisayar Mühendisliği (Burslu)" olursa kategori eşlemesi ve bölüm slug'ı kayabilir; kaydedilmiş raporlardaki program adları da tutmayabilir. Bu yüzden doğru sıra: (1) kopyada koş, (2) kategori eşleme farkını say, (3) gerekirse okuyan tarafa "etiketi kırp" normalizasyonu ekle, (4) ancak sonra gerçek DB. Bu gece yapılmaz. - Daha ucuz alternatif:
isim'e hiç dokunmadan ayrı birburskolonu türetmek (Burslu/%75/%50/%25/Ücretli/—). Ama bu §3.5'te reddettiğim "yeni kolon" yoluna girer ve kategori riskini de çözmez, sadece erteler. Önerim:--isim-esitle+ okuyan tarafta etiket kırpma.
5. Kapsam dışı ama yayını ilgilendiren bulgu: doluluk oranları yukarı sapmalı
Görevde yok, ama bu gece yayımlanan rakamları etkilediği için rapora giriyor.
SELECT COUNT(*) FROM programs WHERE kontenjan2025 IS NOT NULL AND gk2025 IS NOT NULL
AND kontenjan2025 <> gk2025; -- 0 → kontenjan = YALNIZ genel kontenjan
SELECT COUNT(*) FROM programs WHERE yerlesen2025 IS NOT NULL AND gkY2025 IS NOT NULL
AND yerlesen2025 <> gkY2025; -- 7.989 → yerlesen = gkY+sgyY+dprmY+obkY
scripts/refresh.ts:212-217 yerlesen() dört kota türünü toplarken, kontenjan kolonuna yalnız r.kontenjan (genel kontenjan) yazılıyor. Pay ile payda aynı evreni saymıyor:
| Grup (2026 lisans) | Kontenjan | Yerleşen | Doluluk | yerlesen>kontenjan satır |
|---|---|---|---|---|
| Devlet | 280.131 | 286.150 | %102,1 | 5.618 |
| Vakıf | 99.638 | 78.475 | %78,8 | — |
| KKTC | 13.162 | 7.923 | %60,2 | 0 |
- KKTC ve vakıf rakamları güvende — KKTC'de okul birincisi/şehit-gazi/depremzade kontenjanı olmadığı için sapma sıfır;
kktc-universiteleri-okunur-muyazısının ÖSYM ile birebir uyuşması bunu bağımsız olarak doğruluyor (13.162/7.923 ÖSYM Tablo 1 ile aynı). - Devlet doluluk rakamları sapmalı.
bilgisayar-mi-yazilim-muhendisligi-miyazısındaki "devlet YM %102,1" tam olarak bu sapmadır; %100'ü aşan her doluluk rakamı bu hatanın imzasıdır. - En küçük düzeltme yazı tarafında: doluluk hesabında paydayı da tüm kota türlerini kapsayacak şekilde kurmak mümkün değil (toplam kontenjan kolonu DB'de yok) → bu sezon devlet için doluluk rakamı yayımlanmasın, ya da "genel kontenjana göre" kaydıyla ve %100 üstü değerler açıklanarak verilsin. Kalıcı düzeltme
kontenjanToplam<yıl>kolonu gerektirir → yeni yılın refresh'ine bağlanmalı, bu gece değil. - Backlog önerisi:
veri-kalite.ts'e ZORUNLU kontrol olarakyerlesen>kontenjanoranı eklensin; bugün böyle bir kontrol yok (scripts/veri-kalite.ts:145-150yalnızunitur boş/il boşbilgi satırı basıyor, çıkış kodunu etkilemiyor).
6. Backlog önerileri (urun-yoneticisine)
| Öneri | Gerekçe | Boy |
|---|---|---|
BACKLOG #9'u genişlet: "3 yurt dışı/KKTC üniversitesi DEVLET etiketli" → gerçek kapsam 100 satır + 179 il='KIBRIS' + 110 boş il + 26 yanlış şehir; çözüm §3.6 betiği |
bugünkü madde kapsamı gerçeğin üçte biri | S |
T34 kabul kriteri: SELECT COUNT(DISTINCT il) FROM programs WHERE unitur IN ('DEVLET','VAKIF','VAKIF MYO') = 81 ve COUNT(*) WHERE il IS NULL = 15 |
T7/#18'in önkoşulu, komutla doğrulanabilir | — |
Yeni: refresh.ts --yer-esitle (il/fakulte senkronu, önce listeler sonra yazar) |
yoksa aynı kir 2027'de yeniden birikir | M |
Yeni: veri-kalite.ts'e 3 ZORUNLU kontrol — (a) aynı baz kurum adında iki unitur, (b) TR dışı il × TR unitur çelişkisi, (c) yerlesen>kontenjan |
üçü de bu gece elle bulundu; otomatik olmalı | S |
A5 sonrası: --isim-esitle koşusu + kategori eşleme farkının sayımı |
T11'in önkoşulu | M |
7. Engeller
data/ham/2026-2026-09-21.jsonl.gzbu makinede yok (.gitignore:48, dizin hiç yok). API yanıtında ayrı birbursOrani/ogrenimTurualanı olup olmadığını yerel olarak doğrulayamadım — A5'in cevabı bundan bağımsız (etiketbirimAdiiçinde geliyor, §4/3 kanıtı), ama "ayrıca ayrı kolon da var mı" sorusu açık kaldı.- Disk. Kural gereği DB kopyası alınmadı, betik denemesi yapılmadı; §3.6 ve §4'teki komutlar hiç koşulmadı, yalnız yazıldı.
- ÖSYM 2026 kılavuzu açılamadı (yazar 14 de aynı engele takılmış: PDF metin katmanı çıkarılamıyor, makinede
poppleryok). "ODTÜ Yazılım Mühendisliği Ankara'da değil, Kuzey Kıbrıs'ta" iddiası bu yüzden kılavuz maddesine değil, (a) ODTÜ KKK'nin kendi sayfasına ve (b) 45/5 Burslu-%50 kontenjan desenine dayanıyor → [doğrulanmalı] işaretli kaldı.
Bilal'den istenen (3 madde)
- §3.6 düzeltme betiğine onay — 100
unitur+ 320ilsatırını düzeltir, sıralama/kontenjan verisine dokunmaz, geri alma tekcp. Onaylarsan betiğiveri/il-temizligidalında yazıp kopyada doğrularım; T7 (/il/[slug]) ve #18 yazısı bu onaya bağlı. (karar: 3 dk) - Ürün kararı: sihirbazın "Vakıf (burslu olursa)" adımı KKTC ve yurt dışı programlarını kapsasın mı? Bugün kapsıyor (1.256 satır, havuzun %13,4'ü) ve öğrenciye söylenmiyor. Kapsamasın dersen vakıf havuzu 9.351 → 8.095'e iner. (karar: 2 dk)
- Devlet doluluk rakamı bu sezon yayımlanmasın onayı —
bilgisayar-mi-yazilim-muhendisligi-miyazısındaki "%102,1" ve "%99,8" kota asimetrisinden sapmalı (§5); yazı yayına girmedenrehber-editoruo iki rakamı çıkarsın ya da "genel kontenjana göre" kaydıyla versin. (karar: 2 dk, uygulama: 10 dk)