Merge branch 'gece/0922-unitur-kacagi' into is/0923-birlesik
# Conflicts: # scripts/veri-kalite.ts
This commit is contained in:
BIN
data/yokatlas.db
BIN
data/yokatlas.db
Binary file not shown.
147
docs/gece-vardiyasi/2026-09-22/09-p2-unitur.md
Normal file
147
docs/gece-vardiyasi/2026-09-22/09-p2-unitur.md
Normal 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.**
|
||||||
@@ -3,8 +3,10 @@
|
|||||||
*
|
*
|
||||||
* YÖK Atlas API'si bazı kayıtlarda universiteTuru döndürmüyor; DB'de ~2.081
|
* 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
|
* 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) —
|
||||||
|
* `programs` VE `programs_arsiv` üzerinde
|
||||||
* A) Aynı üniversitenin dolu satırından kopyala (Nişantaşı, Beykent…)
|
* A) Aynı üniversitenin dolu satırından kopyala (Nişantaşı, Beykent…)
|
||||||
* B) Kalanlarda il KKTC yerleşimiyse unitur='KKTC'
|
* B) Kalanlarda il KKTC yerleşimiyse unitur='KKTC'
|
||||||
* C) Küçük manuel eşleme (Cerrahpaşa, MSB/İçişleri, Alanya, Manas…)
|
* C) Küçük manuel eşleme (Cerrahpaşa, MSB/İçişleri, Alanya, Manas…)
|
||||||
@@ -13,20 +15,24 @@
|
|||||||
* duplikat adlar normalize edilir; refresh.ts insert yolunda da aynı
|
* duplikat adlar normalize edilir; refresh.ts insert yolunda da aynı
|
||||||
* normalizasyon uygulanır ki duplikat bir daha oluşmasın.
|
* normalizasyon uygulanır ki duplikat bir daha oluşmasın.
|
||||||
*
|
*
|
||||||
* İdempotenttir; yalnızca NULL satırlara dokunur.
|
* İdempotenttir. A/B/C yalnızca `programs` tablosunun NULL satırlarına dokunur;
|
||||||
|
* D (KURUM_DUZELT) NULL koşulundan bağımsızdır — düzelttiği alanlar dolu ama
|
||||||
|
* yanlış — ve `programs_arsiv`'i de tarar (varsa).
|
||||||
*
|
*
|
||||||
* Kullanım: npx tsx scripts/unitur-onar.ts (dev sunucu KAPALIYKEN —
|
* 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ı)
|
* uygulama DB'yi readonly açar ama WAL checkpoint için tek yazar olmalı)
|
||||||
*/
|
*/
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import Database from "better-sqlite3";
|
import Database from "better-sqlite3";
|
||||||
|
import { tabloVar } from "./yokatlas-goc";
|
||||||
|
|
||||||
/** Tire etrafı boşluk + çift boşluk temizliği (üniversite adı için). */
|
/** Tire etrafı boşluk + çift boşluk temizliği (üniversite adı için). */
|
||||||
export function uniAdiNormalize(ad: string): string {
|
export function uniAdiNormalize(ad: string): string {
|
||||||
return ad.replace(/\s*-\s*/g, "-").replace(/\s{2,}/g, " ").trim();
|
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",
|
"GİRNE",
|
||||||
"LEFKOŞA",
|
"LEFKOŞA",
|
||||||
"GAZİMAĞUSA",
|
"GAZİMAĞUSA",
|
||||||
@@ -51,6 +57,49 @@ const MANUEL_IL: Record<string, string> = {
|
|||||||
"İSTANBUL ÜNİVERSİTESİ-CERRAHPAŞA": "İSTANBUL",
|
"İ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.
|
||||||
|
*
|
||||||
|
* Aynı yanlış etiket `programs_arsiv`'e de yazılmıştı (kapanan programlar oraya
|
||||||
|
* `programs`'tan olduğu gibi taşınıyor). Bugün `src/` tarafında arşivi okuyan
|
||||||
|
* SQL yok, ama tablo ileride okunursa sızıntı geri gelirdi; bu yüzden Aşama D
|
||||||
|
* iki tabloyu da tarar. Dokunulan kolon yalnız `unitur` ve `il`.
|
||||||
|
*/
|
||||||
|
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 {
|
export function uniturOnar(db: Database.Database): void {
|
||||||
// 0) Üniversite adı normalizasyonu (Cerrahpaşa duplikatını birleştirir)
|
// 0) Üniversite adı normalizasyonu (Cerrahpaşa duplikatını birleştirir)
|
||||||
const adlar = db
|
const adlar = db
|
||||||
@@ -69,6 +118,35 @@ export function uniturOnar(db: Database.Database): void {
|
|||||||
}
|
}
|
||||||
if (duzeltilen > 0) console.log(`Ad normalizasyonu: ${duzeltilen} kurum`);
|
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.
|
||||||
|
// `programs` ve (varsa) `programs_arsiv` aynı haritadan geçer — iki tablo
|
||||||
|
// ayrışırsa arşiv ileride okunduğunda aynı sızıntı geri gelir.
|
||||||
|
const dTablolar = tabloVar(db, "programs_arsiv")
|
||||||
|
? ["programs", "programs_arsiv"]
|
||||||
|
: ["programs"];
|
||||||
|
for (const tablo of dTablolar) {
|
||||||
|
const dUnitur = db.prepare(
|
||||||
|
`UPDATE ${tablo} SET unitur = ? WHERE universite = ? AND unitur IS NOT ?`
|
||||||
|
);
|
||||||
|
const dIl = db.prepare(
|
||||||
|
`UPDATE ${tablo} 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ı) ${tablo}: unitur ${dUniturToplam} satır, il ${dIlToplam} satır`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// A) Aynı üniversitenin dolu satırından kopyala. Birden fazla FARKLI dolu
|
// 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.
|
// değer varsa sessizce seçim yapma — kaynak veride tutarsızlık demektir.
|
||||||
const celiskiler = db
|
const celiskiler = db
|
||||||
@@ -148,11 +226,18 @@ if (process.argv[1]?.endsWith("unitur-onar.ts")) {
|
|||||||
db.pragma("journal_mode = WAL");
|
db.pragma("journal_mode = WAL");
|
||||||
db.transaction(() => uniturOnar(db))();
|
db.transaction(() => uniturOnar(db))();
|
||||||
db.pragma("wal_checkpoint(TRUNCATE)");
|
db.pragma("wal_checkpoint(TRUNCATE)");
|
||||||
const dagilim = db
|
for (const tablo of tabloVar(db, "programs_arsiv")
|
||||||
.prepare(
|
? ["programs", "programs_arsiv"]
|
||||||
"SELECT COALESCE(unitur,'(NULL)') AS t, COUNT(*) AS n FROM programs GROUP BY unitur ORDER BY n DESC"
|
: ["programs"]) {
|
||||||
)
|
const dagilim = db
|
||||||
.all() as { t: string; n: number }[];
|
.prepare(
|
||||||
console.log("Dağılım:", dagilim.map((d) => `${d.t}=${d.n}`).join(" "));
|
`SELECT COALESCE(unitur,'(NULL)') AS t, COUNT(*) AS n FROM ${tablo} GROUP BY unitur ORDER BY n DESC`
|
||||||
|
)
|
||||||
|
.all() as { t: string; n: number }[];
|
||||||
|
console.log(
|
||||||
|
`Dağılım (${tablo}):`,
|
||||||
|
dagilim.map((d) => `${d.t}=${d.n}`).join(" ")
|
||||||
|
);
|
||||||
|
}
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { EFEKTIF_SIRA_SQL, ILK_YIL } from "../src/lib/veri-yillari";
|
|||||||
import { EFEKTIF_INDEKS, efektifSorguPlani } from "./db-index";
|
import { EFEKTIF_INDEKS, efektifSorguPlani } from "./db-index";
|
||||||
import { kimlikFarklari, onarimKayitlari, yilKolonlari, type DbKimlik } from "./kimlik";
|
import { kimlikFarklari, onarimKayitlari, yilKolonlari, type DbKimlik } from "./kimlik";
|
||||||
import { hamOku, sonHamDosya, TUR_MAP } from "./refresh";
|
import { hamOku, sonHamDosya, TUR_MAP } from "./refresh";
|
||||||
|
import { KKTC_ILLERI } from "./unitur-onar";
|
||||||
import {
|
import {
|
||||||
argOku,
|
argOku,
|
||||||
bayrakVar,
|
bayrakVar,
|
||||||
@@ -295,6 +296,53 @@ async function main() {
|
|||||||
console.log(` şimdi, tüm satırlar (yeni dahil) : ${toplamlar(simdi)}`);
|
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)";
|
||||||
|
// 13 ve 14 arşivi de tarar: kapanan programlar `programs_arsiv`'e olduğu gibi
|
||||||
|
// taşındığı için yanlış etiket orada da duruyordu (BACKLOG #21). Bugün `src/`
|
||||||
|
// tarafında arşivi okuyan SQL yok, ama iki tablo ayrışırsa denetim bunu
|
||||||
|
// görmez ve tablo ileride okunduğunda sızıntı geri gelir.
|
||||||
|
const KURUMLAR = tabloVar(db, "programs_arsiv")
|
||||||
|
? `(SELECT universite, unitur, il FROM programs
|
||||||
|
UNION ALL SELECT universite, unitur, il FROM programs_arsiv)`
|
||||||
|
: "programs";
|
||||||
|
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 ${KURUMLAR} 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 ${KURUMLAR}
|
||||||
|
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}`
|
||||||
|
);
|
||||||
urapKontrolleri(db, zorunlu, bilgi);
|
urapKontrolleri(db, zorunlu, bilgi);
|
||||||
|
|
||||||
db.close();
|
db.close();
|
||||||
|
|||||||
Reference in New Issue
Block a user