Merge branch 'worktree-agent-a5bcd7331b2f3c5b2' into v2

This commit is contained in:
bilalgursen
2026-10-07 23:25:11 +03:00
16 changed files with 206 additions and 9 deletions

View File

@@ -0,0 +1,79 @@
/**
* Program varyant etiketinin MEKANİK testi — parasız, anahtarsız, salt okur.
*
* pnpm tsx scripts/eval/varyant-denetim.ts
*
* react-server koşulu gerekmez: db.ts ve program-varyant.ts saf/sqlite.
* Doğrulananlar: (1) varyantEtiketi birim kuralları, (2) Başkent Tıp'ın 6
* satırının etiketleri birbirinden farklı ve hiçbiri null, (3) dilimAra'nın
* döndürdüğü her satırda `varyant` tanımlı (SELECT_COLS tüm yolu kapsıyor),
* (4) devlet/Türkçe/örgün programda null. data/yokatlas.db'ye yazılmaz.
* Beklenti tutmazsa çıkış kodu 1.
*/
import { dilimAra, programGetir } from "../../src/lib/db";
import { varyantEtiketi, type VaryantGirdisi } from "../../src/lib/program-varyant";
let hata = 0;
function bekle(ad: string, kosul: boolean, detay = ""): void {
console.log(`${kosul ? "✔" : "✘"} ${ad}${detay ? ` — ${detay}` : ""}`);
if (!kosul) hata++;
}
// 1. Birim: etiket kuralları
const birim: [VaryantGirdisi, string | null][] = [
[{ bursOrani: "Burslu", ogrenimDili: "İngilizce", ogrenimTuru: "Örgün Öğretim" }, "Burslu · İngilizce"],
[{ bursOrani: null, ogrenimDili: "Türkçe", ogrenimTuru: "Örgün Öğretim" }, null],
[{ bursOrani: "Ücretli", ogrenimDili: "Türkçe", ogrenimTuru: "İkinci Öğretim" }, "Ücretli · İkinci Öğretim"],
[{ bursOrani: "%50 İndirimli", ogrenimDili: null, ogrenimTuru: null }, "%50 İndirimli"],
// DB'de burs_orani boş string de geliyor (devlet); null gibi davranır
[{ bursOrani: "", ogrenimDili: "Türkçe", ogrenimTuru: "Uzaktan Öğretim" }, "Uzaktan Öğretim"],
];
for (const [girdi, beklenen] of birim) {
const sonuc = varyantEtiketi(girdi);
bekle(
`birim ${JSON.stringify(girdi)}`,
sonuc === beklenen,
`beklenen ${JSON.stringify(beklenen)}, gelen ${JSON.stringify(sonuc)}`,
);
}
// 2. Başkent Tıp ×6: isim hepsinde "Tıp", varyant hepsinde farklı
const BASKENT_TIP = ["200610657", "200610666", "200611488", "200690357", "200690358", "200690359"];
const baskent = BASKENT_TIP.map((id) => ({ id, p: programGetir(id) }));
for (const { id, p } of baskent) {
bekle(
`programGetir(${id}) varyant dolu`,
p != null && p.varyant != null,
p ? `${p.universite} / ${p.isim} → ${p.varyant}` : "bulunamadı",
);
}
const etiketler = baskent.map(({ p }) => p?.varyant ?? null);
bekle(
"Başkent Tıp 6 varyant birbirinden farklı",
new Set(etiketler).size === BASKENT_TIP.length,
etiketler.join(" | "),
);
// 3. dilimAra yolu: her satırda varyant tanımlı (string ya da null)
const { programlar } = dilimAra(100000, "say", "dengeli", { limit: 50 });
const tanimsiz = programlar.filter(
(p) => !("varyant" in p) || (p.varyant !== null && typeof p.varyant !== "string"),
);
bekle(
`dilimAra 50 satırda varyant tanımlı (${programlar.length} satır)`,
programlar.length > 0 && tanimsiz.length === 0,
tanimsiz.map((p) => p.id).join(","),
);
const etiketli = programlar.filter((p) => p.varyant).length;
console.log(` (bilgi) dilimAra örneğinde etiketli satır: ${etiketli}/${programlar.length}`);
// 4. Devlet / Türkçe / örgün → null (Marmara Hukuk)
const marmara = programGetir("107210332");
bekle(
"107210332 Marmara Hukuk varyant null",
marmara != null && marmara.varyant === null,
marmara ? `${marmara.universite} / ${marmara.isim} → ${JSON.stringify(marmara.varyant)}` : "bulunamadı",
);
console.log(hata === 0 ? "\nVaryant denetimi: TEMİZ" : `\nVaryant denetimi: ${hata} hata`);
process.exit(hata === 0 ? 0 : 1);