fix(veri): yanlış DEVLET etiketi kalıcı onarım + baz ad çelişki denetimi

3 kurum (Kıbrıs Amerikan, Uluslararası Balkan, Uluslararası Saraybosna)
kaynak CSV'den `unitur='DEVLET'` geliyordu. `db.ts:79-82` filtreleri
yüzünden "devlet üniversitesi istiyorum" diyen öğrencinin aday havuzuna
27 KKTC/yurt dışı programı sızıyor, "vakıf" diyende aynı 27'si eksik
kalıyordu. Kullanıcının fark edemeyeceği bir doğruluk hatasıydı.

unitur-onar.ts — Aşama D (KURUM_DUZELT):
  A/B/C yalnız `unitur IS NULL` satırlara dokunuyordu; bu satırlar NULL
  değil, DOLU ve YANLIŞ. D koşulsuz çalışır ve Aşama A'dan ÖNCE koşar ki
  yanlış değer başka satırlara kopyalanmasın. İdempotent (2. koşu: 0/0).
  Her düzeltmenin kanıtı kurumun YÖK Atlas'taki kendi parantezli ikinci
  yazımı: "(ÜSKÜP-MAKEDONYA)" → YURTDISI KAMU, "(KKTC-LEFKOŞA)" → KKTC.
  refresh.ts:519 `uniturSec` DB'deki değeri kopyaladığı için düzeltme
  buraya yazılınca her tazelemede kalıcı olur.

veri-kalite.ts — iki yeni ZORUNLU kontrol (dosyanın sonuna):
  13. "baz ad başına tek unitur" — kök neden buydu: unitur-onar.ts'in
      eski çelişki koruması GROUP BY universite (TAM ad) ile çalıştığı
      için aynı kurumun iki yazımı arasındaki DEVLET↔YURTDISI KAMU
      çelişkisini hiç görmüyordu.
  14. "DEVLET etiketi Türkiye ili ile destekli" — 13'ün kör noktası:
      Kıbrıs Amerikan'ın İKİ yazımı da yanlış etiketli olduğu için
      ortada çelişki yok. 13 tek başına 100 satırın yalnız 58'ini
      koruyordu. Şartnamenin ötesinde, gerekçesi raporun §4'ünde.

Doğrulama: düzeltme öncesi DB'de iki kontrol de KALDI (çıkış kodu 1);
sonrasında 0 ZORUNLU kaldı, 3 uyarı (üçü de önceden vardı). Tek satır
bilerek bozulduğunda ikisi de yakaladı. tsc + eslint temiz.

Veri (126 satır) ayrı commit'te. Rapor: docs/gece-vardiyasi/2026-09-22/
09-p2-unitur.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-09-23 00:24:42 +03:00
parent 9bd448bd16
commit b66c720b32
3 changed files with 254 additions and 3 deletions

View File

@@ -0,0 +1,147 @@
# 09 · P2 — Sihirbaz havuzundaki sessiz sızıntı kapatıldı
Dal: `gece/0922-unitur-kacagi` · Şartname: `06-ceo-kararlari.md` §3 P2 · Teşhis: `05-urap.md` §6
Commit düzeni: (1) kod + bu rapor, (2) `data/yokatlas.db` binary'si.
## Özet (5 madde)
1. **Sızıntı kapandı.** "Devlet üniversitesi istiyorum" diyen öğrencinin aday havuzuna giren 27 KKTC/yurt dışı programı artık devlet filtresinde **0**, vakıf filtresinde **27**. Ölçüldü, çıkarım değil.
2. **126 satır düzeldi**, tam şartnamedeki sayı: 100 `unitur` + 26 `il`. Değişen kolon **yalnız bu ikisi**; `programs` tablosunun 45 kolonu tek tek karşılaştırıldı.
3. **2021–2026 puan/sıra/kontenjan/yerleşen kolonlarında değişen satır: 0.** 34 yıl kolonu, 21.493 satır, öncesi/sonrası birebir. `programs_arsiv`, `netler`, `veri_meta` de dokunulmadı.
4. **Kök neden kapandı, tekrarı denetleniyor.** `unitur-onar.ts`'e NULL koşulundan bağımsız **Aşama D** (`KURUM_DUZELT`) eklendi; `veri-kalite.ts`'e iki yeni ZORUNLU kontrol geldi. Kontroller düzeltme öncesi DB'de **KALDI**, sonrasında **GEÇTİ** verdi; ayrıca tek satır bilerek bozulduğunda ikisi de yakaladı.
5. **Bir kapsam genişletmesi var, bilerek:** şartnamedeki "baz ad başına tek `unitur`" kontrolü Kıbrıs Amerikan'ı (100 satırın 42'si) **yakalayamıyor** — o kurumun iki yazımı da yanlış etiketli olduğu için ortada çelişki yok. Bu yüzden ikinci bir 6 satırlık kontrol eklendi (§4). Onaysız bırakılırsa "kök neden kapandı" cümlesi yalan olurdu.
## 1. Ne değişti
| Dosya | Değişiklik |
|---|---|
| `scripts/unitur-onar.ts` | `KURUM_DUZELT` haritası + **Aşama D** (Aşama A'dan önce koşar). `KKTC_ILLERI` dışa aktarıldı (tek kaynak). Başlık yorumu "yalnızca NULL satırlara dokunur" → A/B/C NULL, D koşulsuz. |
| `scripts/veri-kalite.ts` | Kontrol 13 (baz ad başına tek `unitur`) + kontrol 14 (DEVLET etiketi Türkiye ili ile destekli). Dosyanın **en sonuna** eklendi; mevcut satırlar yeniden düzenlenmedi (P3 ile çakışmayı küçültmek için). |
| `data/yokatlas.db` | 126 satır (ayrı commit). |
`KURUM_DUZELT` içeriği ve her satırın kanıtı — kurumun YÖK Atlas'taki **kendi parantezli ikinci yazımı**:
| Ad (DB'de) | `unitur` önce → sonra | `il` |
|---|---|---|
| KIBRIS AMERİKAN ÜNİVERSİTESİ | DEVLET → **KKTC** (36) | değişmedi |
| KIBRIS AMERİKAN ÜNİVERSİTESİ (KKTC-LEFKOŞA) | DEVLET → **KKTC** (6) | değişmedi |
| ULUSLARARASI BALKAN ÜNİVERSİTESİ | DEVLET → **YURTDISI KAMU** (34) | SARAYBOSNA - BOSNA - HERSEK → **ÜSKÜP-MAKEDONYA** (26) |
| ULUSLARARASI SARAYBOSNA ÜNİVERSİTESİ | DEVLET → **YURTDISI KAMU** (24) | değişmedi (kurum gerçekten Saraybosna'da) |
`ÜSKÜP-MAKEDONYA` yazımı uydurma değil: kurumun kendi adındaki parantezli ek, DB'deki diğer yurt dışı illerin biçimiyle (`BİŞKEK-KIRGIZİSTAN`, `TÜRKİSTAN-KAZAKİSTAN`, `BAKÜ-AZERBAYCAN`) aynı.
`unitur` dağılımı: `DEVLET 12142→12042`, `KKTC 1145→1187`, `YURTDISI KAMU 99→157`. Toplam sabit.
## 2. Fark raporu (öncesi/sonrası)
Yöntem: düzeltme öncesi DB `sqlite3 .backup` ile scratchpad'e alındı, sonra `ATTACH` ile kolon kolon karşılaştırıldı.
```
programs: önce 21493 → sonra 21493 (satır kaybı/ekleme yok)
programs_arsiv: önce 3735 → sonra 3735 (unitur/il değişen satır: 0)
netler: önce 62975 → sonra 62975
veri_meta: önce 37 → sonra 37
programs, 45 kolon tarandı — DEĞİŞEN: unitur=100, il=26
yıl kolonları (34 kolon: sıra/puan/kontenjan/yerleşen + 2025 ek kontenjanları,
2021-2026) değişen satır: 0
```
`pnpm veri-kalite --onceki` kendi bağımsız kontrolüyle aynı sonucu verdi:
```
GEÇTİ önceki DB: satır kaybı — 0
GEÇTİ önceki DB: geçmiş yıllar korunmuş — 20 kolonda dolu değeri değişen/silinen satır: 0
2025 sağlaması (count | Σsira | Σpuan | Σkontenjan | Σyerlesen)
önceki DB : 21493 | 11099796362 | 5433214.11872 | 756453 | 740586
şimdi, önceki DB'deki aynı id'ler : 21493 | 11099796362 | 5433214.11872 | 756453 | 740586
```
## 3. Kabul kriterleri — tek tek
**(1) `pnpm veri-kalite` temiz ve yeni kontrol çelişkiyi gerçekten yakalıyor.** ✅
```
pnpm veri-kalite --yil 2026 --db data/yokatlas.db --onceki <öncesi>
…
GEÇTİ baz ad başına tek unitur — aynı kurumun iki yazımı devlet/vakıf filtresini bölmüyor
bilgi baz ad unitur farkı (devlet/vakıf ayrımını bölmeyen) — HOCA AHMET YESEVİ …/YURTDISI KAMU,YURTDISI VAKIF/17 ; KIRGIZİSTAN-TÜRKİYE MANAS …/29
GEÇTİ DEVLET etiketi Türkiye ili ile destekli — DEVLET etiketli her kurumun en az bir programı Türkiye ilinde
Sonuç: 0 ZORUNLU kontrol kaldı, 3 uyarı. (çıkış kodu 0)
```
3 uyarı **düzeltme öncesiyle birebir aynı**, hiçbiri bu işten doğmadı: `il boş` 110 satır (kapsam dışı), `kimlik ATLANDI` (`data/ham` repoda yok), `yetim netler` 2066.
Yakalama iki yoldan kanıtlandı:
- *Düzeltme öncesi DB'de* (gerçek kusur): `KALDI baz ad başına tek unitur — … ULUSLARARASI BALKAN ÜNİVERSİTESİ/DEVLET,YURTDISI KAMU/48 ; ULUSLARARASI SARAYBOSNA ÜNİVERSİTESİ/DEVLET,YURTDISI KAMU/38` ve `KALDI DEVLET etiketi Türkiye ili ile destekli — KIBRIS AMERİKAN ÜNİVERSİTESİ/LEFKOŞA/36 ; … (KKTC-LEFKOŞA)/KIBRIS/6 ; ULUSLARARASI BALKAN …/34 ; ULUSLARARASI SARAYBOSNA …/24` → `Sonuç: 2 ZORUNLU kontrol kaldı`, çıkış kodu 1.
- *Bilerek bozma* (düzeltilmiş DB'nin atılabilir kopyasında **tek** satır `DEVLET`'e döndürüldü): ikisi de yakaladı → `Sonuç: 2 ZORUNLU kontrol kaldı`. Kopya silindi; gerçek DB'ye dokunulmadı.
**(2) `db.ts` devlet filtresi 27 programı artık döndürmüyor, vakıf filtresi döndürüyor.** ✅ Ölçüldü.
`src/lib/db.ts:79-82` filtreleri + `EFEKTIF_SIRA = COALESCE(sira2026, sira2025)` (havuza ancak efektif sırası olan satır girer):
```sql
-- devlet: AND unitur = 'DEVLET'
-- vakıf : AND unitur IS NOT NULL AND unitur <> 'DEVLET'
SELECT COUNT(*) FROM programs
WHERE universite IN ('KIBRIS AMERİKAN ÜNİVERSİTESİ',
'KIBRIS AMERİKAN ÜNİVERSİTESİ (KKTC-LEFKOŞA)',
'ULUSLARARASI BALKAN ÜNİVERSİTESİ',
'ULUSLARARASI SARAYBOSNA ÜNİVERSİTESİ')
AND <filtre> AND COALESCE(sira2026, sira2025) IS NOT NULL;
```
| | önce | sonra |
|---|---|---|
| devlet havuzu | **27** | **0** |
| vakıf havuzu | **0** | **27** |
**(3) `/universiteler` hub'ında üç kurum "Devlet" listesinden çıkıyor.** ✅ (kısmen koddan çıkarım — tarayıcı açılmadı)
`getAllUniversiteler` (`src/lib/katalog.ts:268-271`) `MAX(unitur) GROUP BY universite` okur; `universite-listesi.tsx:44-47` `u.unitur === "DEVLET"` olanı devlet listesine, `VAKIF`/`VAKIF MYO` olanı vakfa, kalanı `digerUniler`'e koyar. Aynı SQL DB'de koşturuldu:
```
önce : KIBRIS AMERİKAN …|DEVLET … (KKTC-LEFKOŞA)|DEVLET ULUSLARARASI BALKAN …|DEVLET ULUSLARARASI SARAYBOSNA …|DEVLET
sonra: KIBRIS AMERİKAN …|KKTC … (KKTC-LEFKOŞA)|KKTC ULUSLARARASI BALKAN …|YURTDISI KAMU ULUSLARARASI SARAYBOSNA …|YURTDISI KAMU
Devlet listesindeki kurum sayısı: 170 → 166
```
166 = 170 − **4 yazım** (3 kurum; Kıbrıs Amerikan'ın iki yazımı bugün iki ayrı slug — `kategoriBul` baz ad birleştirmesi kapsam dışı, BACKLOG #10).
Dördü de `KKTC`/`YURTDISI KAMU` olduğu için vakıf listesine **girmiyor**, "Diğer" grubuna düşüyor — hub'da sayı dengesi bozulmuyor.
**(4) 2021–2026 puan/sıra kolonlarında hiçbir değişiklik yok.** ✅ §2.
Ayrıca: `npx next typegen && npx tsc --noEmit` temiz, `npx eslint scripts/unitur-onar.ts scripts/veri-kalite.ts` temiz. Betik **idempotent**: ikinci koşu `unitur 0 satır, il 0 satır`.
## 4. Kapsam genişletmesi ve gerekçesi (şeffaflık)
Şartname `veri-kalite.ts`'e tek kontrol istiyordu: "baz ad başına tek `unitur`" (~8 satır). Uygulandı — ama düzeltme öncesi DB'de koşturunca **Kıbrıs Amerikan'ı hiç görmüyor**: o kurumun her iki yazımı da `DEVLET` etiketli, yani baz ad içinde çelişki yok. Bu kontrol tek başına 100 satırın yalnız 58'ini koruyor; 42'si (öğrenciye sızan 27 programın 12'si) denetimsiz kalıyordu.
Bu yüzden **kontrol 14** eklendi (6 satır): *DEVLET etiketli bir kurumun en az bir programı Türkiye ilinde olmalı.* Türkiye illerinde tire geçmiyor, yurt dışı iller tireli, KKTC illeri `KKTC_ILLERI`'nde; hiç ili olmayan kurumlar (MSB/İçişleri) hariç tutuldu. Düzeltme öncesi DB'de yanlış 4 yazımın **dördünü birden**, sıfır yanlış pozitifle yakalıyor.
Kapsam **dışında bırakılanlara dokunulmadı**: `il` boş 19 satır, burs/dil ekli adlar (B4), `kategoriBul` düzeltmesi.
## 5. Yeni bulgular (bu geceye alınmadı — backlog önerisi)
| # | Bulgu | Sorgu / kanıt | Önem |
|---|---|---|---|
| A | **`programs_arsiv`'de aynı yanlış etiket sürüyor**: 31 satır ULUSLARARASI BALKAN + 30 satır ULUSLARARASI SARAYBOSNA `unitur='DEVLET'`, 24 satırda il Saraybosna. CEO §6'nın veri mühendisine sorduğu soru buydu. | `SELECT universite, unitur, il, COUNT(*) FROM programs_arsiv WHERE universite LIKE '%BALKAN%' OR universite LIKE '%SARAYBOSNA%' GROUP BY 1,2,3` | **Düşük — kullanıcıya yansımıyor.** `src/` tarafında `programs_arsiv`'i okuyan hiçbir SQL yok (tablo yalnızca `src/lib/kapanan-sluglar.ts`'te bir yorumda geçer); `db.ts` havuzu yalnız `programs`'tan besleniyor. Yine de bir sonraki denetimde yeniden "bulgu" olarak çıkacak; `KURUM_DUZELT`'i arşive de uygulamak tek satırlık iş. |
| B | **`data/yokatlas.db-shm` ve `-wal` git'te izleniyor** (32 KB + 0 bayt). Bunlar SQLite'ın geçici dosyaları: DB her açılıp kapandığında oluşup siliniyor, dolayısıyla `git status` kendiliğinden kirleniyor. | `git ls-files data/` | **Düşük.** Uygulamanın `better-sqlite3` ile `readonly` açılışı eski `-shm` yanındayken de sorunsuz çalışıyor (ölçtüm); ama `sqlite3 -readonly` CLI'ı bu durumda "unable to open database file (14)" veriyor — denetim sorgusu koşarken yanıltır. Öneri: `git rm --cached` + `.gitignore`. **Bu commit'e dahil etmedim**: `.gitignore`'da Bilal'in commit'lenmemiş değişikliği var. |
| C | Baz ad çelişkisi kalan 2 kurum: Manas ve Hoca Ahmet Yesevi (`YURTDISI KAMU` ↔ `YURTDISI VAKIF`). | kontrol 13'ün `bilgi` satırı | **Yok.** İkisi de `<> 'DEVLET'` olduğu için devlet/vakıf filtresini bölmüyor; kurum gerçekten ortak. Bilerek ZORUNLU yapılmadı, `bilgi` olarak görünür duruyor. |
## 6. Kullanıcıya yansıyan etki (düzelen)
| Yüzey | Önce | Sonra |
|---|---|---|
| Sihirbaz → "Devlet üniversitesi" | Havuzda 27 KKTC/Bosna/Makedonya programı | 0 |
| Sihirbaz → "Vakıf" | Aynı 27 program eksik | 27'si havuzda |
| `/universiteler` hub'ı | 3 kurum (4 yazım) "Devlet üniversiteleri" listesinde | "Diğer" grubunda |
| `/universite/uluslararasi-balkan-universitesi` | "Tür: Devlet", şehir Saraybosna (Bosna) | Tür: Yurt dışı kamu, şehir Üsküp-Makedonya |
| Tadımlık satırı (`tadimlik-satiri.tsx:37`) | Aynı semantik, aynı sızıntı | Düzeldi (aynı `unitur` alanını okur) |
## Bilal'den istenen
1. **Dalı incele ve merge kararını ver** (`gece/0922-unitur-kacagi`, 2 commit: kod+rapor, veri). Fark raporu §2'de ve veri commit'inin mesajında; geri dönüş için `veri-2025-son` etiketi duruyor. **~10 dk.**
2. **Elindeki ham CSV'de tek `grep`** — `data/ham/` repoda yok: bu üç kurum kaynak dosyada gerçekten `DEVLET` mi yazıyor? Doğrularsa teşhis kapanır, `ingest.ts`'e aynı harita eklenir. **~5 dk.**
3. **Karar:** §5-A (arşiv tablosundaki aynı yanlış etiket) ve §5-B (`-shm`/`-wal` git'ten çıkarılsın mı) backlog'a mı, yoksa bu dala ek commit mi? İkisi de kullanıcıya yansımıyor. **~2 dk.**

View File

@@ -3,8 +3,9 @@
*
* YÖK Atlas API'si bazı kayıtlarda universiteTuru döndürmüyor; DB'de ~2.081
* satır unitur=NULL kalıyor ve bunlar hem devlet/vakıf filtrelerinden hem
* sihirbaz sayaçlarından sessizce düşüyor. Onarım üç aşamalı:
* sihirbaz sayaçlarından sessizce düşüyor. Onarım dört aşamalı:
*
* D) Kaynak veride DOLU ama YANLIŞ olan kurum alanları (KURUM_DUZELT)
* A) Aynı üniversitenin dolu satırından kopyala (Nişantaşı, Beykent…)
* B) Kalanlarda il KKTC yerleşimiyse unitur='KKTC'
* C) Küçük manuel eşleme (Cerrahpaşa, MSB/İçişleri, Alanya, Manas…)
@@ -13,7 +14,8 @@
* duplikat adlar normalize edilir; refresh.ts insert yolunda da aynı
* normalizasyon uygulanır ki duplikat bir daha oluşmasın.
*
* İdempotenttir; yalnızca NULL satırlara dokunur.
* İdempotenttir. A/B/C yalnızca NULL satırlara dokunur; D (KURUM_DUZELT)
* NULL koşulundan bağımsızdır — düzelttiği alanlar dolu ama yanlış.
*
* Kullanım: npx tsx scripts/unitur-onar.ts (dev sunucu KAPALIYKEN —
* uygulama DB'yi readonly açar ama WAL checkpoint için tek yazar olmalı)
@@ -26,7 +28,8 @@ export function uniAdiNormalize(ad: string): string {
return ad.replace(/\s*-\s*/g, "-").replace(/\s{2,}/g, " ").trim();
}
const KKTC_ILLERI = [
/** KKTC il değerleri — tek kaynak; veri-kalite.ts de bunu okur. */
export const KKTC_ILLERI = [
"GİRNE",
"LEFKOŞA",
"GAZİMAĞUSA",
@@ -51,6 +54,44 @@ const MANUEL_IL: Record<string, string> = {
"İSTANBUL ÜNİVERSİTESİ-CERRAHPAŞA": "İSTANBUL",
};
/**
* Aşama D — kaynak veride DOLU ama YANLIŞ olan kurum alanları.
*
* MANUEL_UNITUR'dan farkı: burada değer NULL değil, yanlış. Bu yüzden bu
* harita NULL koşulu OLMADAN çalışır. Her satırın kanıtı kurumun YÖK Atlas'ta
* geçen parantezli ikinci yazımıdır (aynı kurum, doğru etiketli):
*
* "ULUSLARARASI BALKAN ÜNİVERSİTESİ (ÜSKÜP-MAKEDONYA)" → YURTDISI KAMU
* "ULUSLARARASI SARAYBOSNA ÜNİVERSİTESİ (SARAYBOSNA-…)" → YURTDISI KAMU
* "KIBRIS AMERİKAN ÜNİVERSİTESİ (KKTC-LEFKOŞA)" → ili KKTC
*
* Yanlış etiket ilk CSV ingest'inden (scripts/ingest.ts) geliyor; refresh.ts
* `uniturSec` DB'deki değeri sadakatle kopyaladığı için her tazelemede
* yeniden üretiliyordu. Düzeltme buraya yazılınca kalıcı olur.
*
* Etki: `src/lib/db.ts` devlet filtresi (`unitur = 'DEVLET'`) bu kurumların
* programlarını sihirbaz havuzuna alıyordu; vakıf filtresi (`unitur <>
* 'DEVLET'`) ise dışarıda bırakıyordu.
*
* `il` düzeltmesi yalnız YANLIŞ yazılmış değeri hedefler (yanlis → dogru);
* boş il'ler kapsam dışı — eksik, eksik olarak görünmeli.
*/
const KURUM_DUZELT: Record<
string,
{ unitur?: string; il?: { yanlis: string; dogru: string } }
> = {
"KIBRIS AMERİKAN ÜNİVERSİTESİ": { unitur: "KKTC" },
"KIBRIS AMERİKAN ÜNİVERSİTESİ (KKTC-LEFKOŞA)": { unitur: "KKTC" },
"ULUSLARARASI BALKAN ÜNİVERSİTESİ": {
unitur: "YURTDISI KAMU",
// Kurum Üsküp'te; 26 satırda ili Saraybosna yazıyor. Doğru değerin yazımı
// DB'deki diğer yurt dışı illerin biçimini izler (BİŞKEK-KIRGIZİSTAN…)
// ve kurumun kendi parantezli adından alınmıştır.
il: { yanlis: "SARAYBOSNA - BOSNA - HERSEK", dogru: "ÜSKÜP-MAKEDONYA" },
},
"ULUSLARARASI SARAYBOSNA ÜNİVERSİTESİ": { unitur: "YURTDISI KAMU" },
};
export function uniturOnar(db: Database.Database): void {
// 0) Üniversite adı normalizasyonu (Cerrahpaşa duplikatını birleştirir)
const adlar = db
@@ -69,6 +110,28 @@ export function uniturOnar(db: Database.Database): void {
}
if (duzeltilen > 0) console.log(`Ad normalizasyonu: ${duzeltilen} kurum`);
// D) Dolu ama yanlış kurum alanları. A'dan ÖNCE koşar: yanlış değer başka
// satırlara kopyalanmadan düzelsin. NULL koşulu yok; değer zaten dolu.
const dUnitur = db.prepare(
"UPDATE programs SET unitur = ? WHERE universite = ? AND unitur IS NOT ?"
);
const dIl = db.prepare(
"UPDATE programs SET il = ? WHERE universite = ? AND il = ?"
);
let dUniturToplam = 0;
let dIlToplam = 0;
for (const [ad, duzelt] of Object.entries(KURUM_DUZELT)) {
if (duzelt.unitur) {
dUniturToplam += dUnitur.run(duzelt.unitur, ad, duzelt.unitur).changes;
}
if (duzelt.il) {
dIlToplam += dIl.run(duzelt.il.dogru, ad, duzelt.il.yanlis).changes;
}
}
console.log(
`Aşama D (yanlış kurum alanı): unitur ${dUniturToplam} satır, il ${dIlToplam} satır`
);
// A) Aynı üniversitenin dolu satırından kopyala. Birden fazla FARKLI dolu
// değer varsa sessizce seçim yapma — kaynak veride tutarsızlık demektir.
const celiskiler = db

View File

@@ -21,6 +21,7 @@ import { EFEKTIF_SIRA_SQL, ILK_YIL } from "../src/lib/veri-yillari";
import { EFEKTIF_INDEKS, efektifSorguPlani } from "./db-index";
import { kimlikFarklari, onarimKayitlari, yilKolonlari, type DbKimlik } from "./kimlik";
import { hamOku, sonHamDosya, TUR_MAP } from "./refresh";
import { KKTC_ILLERI } from "./unitur-onar";
import {
argOku,
bayrakVar,
@@ -291,6 +292,46 @@ async function main() {
console.log(` şimdi, tüm satırlar (yeni dahil) : ${toplamlar(simdi)}`);
}
// 13. Aynı kurumun iki yazımı arasında unitur çelişkisi — BAZ AD üzerinden.
// unitur-onar.ts'in eski çelişki koruması GROUP BY universite (TAM ad) ile
// çalıştığı için "X ÜNİVERSİTESİ" ve "X ÜNİVERSİTESİ (ÜSKÜP-MAKEDONYA)" iki
// ayrı kurum sayılıyor, aralarındaki DEVLET↔YURTDISI KAMU çelişkisi hiç
// görünmüyordu. Baz ad = sondaki parantezli ek atılmış hâl.
const BAZ_AD =
"TRIM(CASE WHEN instr(universite, '(') > 0 THEN substr(universite, 1, instr(universite, '(') - 1) ELSE universite END)";
const bazAdCeliskileri = `(SELECT ${BAZ_AD} AS bazAd, GROUP_CONCAT(DISTINCT unitur) AS turler, COUNT(*) AS adet,
MAX(unitur = 'DEVLET') <> MIN(unitur = 'DEVLET') AS devletBolunmus
FROM programs WHERE unitur IS NOT NULL GROUP BY 1 HAVING COUNT(DISTINCT unitur) > 1)`;
const bolunmus = ornek(`SELECT bazAd, turler, adet FROM ${bazAdCeliskileri} WHERE devletBolunmus`);
zorunlu(
"baz ad başına tek unitur",
bolunmus === "",
bolunmus === ""
? "aynı kurumun iki yazımı devlet/vakıf filtresini bölmüyor"
: `devlet filtresine giren, vakıf filtresinden düşen kurum: ${bolunmus} → scripts/unitur-onar.ts KURUM_DUZELT`
);
const esdegerFark = ornek(`SELECT bazAd, turler, adet FROM ${bazAdCeliskileri} WHERE NOT devletBolunmus`);
bilgi("baz ad unitur farkı (devlet/vakıf ayrımını bölmeyen)", false, esdegerFark || "yok");
// 14. DEVLET etiketli ama hiçbir programı Türkiye ilinde olmayan kurum.
// 13'ün kör noktası: kurumun İKİ yazımı da yanlış etiketliyse çelişki yoktur.
// Türkiye illerinde tire geçmez; yurt dışı iller tireli (BİŞKEK-KIRGIZİSTAN…),
// KKTC illeri KKTC_ILLERI'nde. İli hiç olmayan kurumlar (MSB/İçişleri) hariç.
const yurtDisiDevlet = ornek(
`SELECT universite, GROUP_CONCAT(DISTINCT il), COUNT(*) FROM programs
WHERE unitur = 'DEVLET' GROUP BY universite
HAVING SUM(il IS NOT NULL) > 0
AND SUM(il NOT LIKE '%-%' AND il NOT IN (${KKTC_ILLERI.map(() => "?").join(",")})) = 0`,
...KKTC_ILLERI
);
zorunlu(
"DEVLET etiketi Türkiye ili ile destekli",
yurtDisiDevlet === "",
yurtDisiDevlet === ""
? "DEVLET etiketli her kurumun en az bir programı Türkiye ilinde"
: `tüm programları KKTC/yurt dışında olduğu hâlde DEVLET: ${yurtDisiDevlet}`
);
db.close();
console.log(`\nSonuç: ${basarisiz} ZORUNLU kontrol kaldı, ${uyari} uyarı.`);
if (basarisiz > 0) process.exit(1);