/** * Rehber bağlantısı doğrulamasının MEKANİK testi — parasız, anahtarsız, DB'siz. * * pnpm tsx --conditions=react-server scripts/eval/baglanti-denetim.ts * * lib/ai/baglanti-denetimi.ts gerçek content/rehber listesiyle sınanır: * kayıtlı slug dokunulmaz, yakın slug yeniden yazılır (başlık kayıttan), * uydurma slug düz metne iner; akış tamponunun parça parça çıktısı tek * seferlik sonuçla birebir aynı olmalı. Beklenti tutmazsa çıkış kodu 1. */ import { BaglantiTamponu, rehberBaglantilariniDuzelt, type RehberKaydi } from "@/lib/ai/baglanti-denetimi"; import { getRehberAramaKayitlari } from "@/lib/rehber"; type Senaryo = { ad: string; metin: string; /** Beklenen tam çıktı (string) ya da çıktıyı denetleyen fonksiyon. */ bekle: string | ((cikti: string) => boolean); duzeltme: number; }; function senaryolar(rehberler: readonly RehberKaydi[]): Senaryo[] { const kayit = (slug: string) => { const r = rehberler.find((x) => x.slug === slug); if (!r) throw new Error(`content/rehber içinde yok: ${slug}`); return r; }; const yatay = kayit("yatay-gecis-cap-yandal"); const obp = kayit("obp-nedir-nasil-hesaplanir"); const gercek = kayit("devlet-mi-vakif-mi"); return [ { ad: "gercek-slug-aynen", metin: `Şu yazıya bak: [${gercek.baslik}](/rehber/${gercek.slug}) — orada ayrıntı var.`, bekle: `Şu yazıya bak: [${gercek.baslik}](/rehber/${gercek.slug}) — orada ayrıntı var.`, duzeltme: 0, }, { ad: "yakin-eslesme-markdown", metin: "Detay için [Yatay geçiş](/rehber/yatay-gecis-rehberi) yazısına bak.", bekle: `Detay için [${yatay.baslik}](/rehber/${yatay.slug}) yazısına bak.`, duzeltme: 1, }, { ad: "uydurma-duz-metin", metin: "Bunu [Tamamen uydurma yazı](/rehber/tamamen-uydurma-seyler) anlatıyor.", bekle: "Bunu Tamamen uydurma yazı anlatıyor.", duzeltme: 1, }, { ad: "ters-tirnak-ve-ciplak", metin: "Bkz. `/rehber/obp-nedir` ve ayrıca /rehber/yatay-gecis-rehberi. Uydurma: /rehber/tamamen-uydurma-seyler bitti.", bekle: `Bkz. [${obp.baslik}](/rehber/${obp.slug}) ve ayrıca [${yatay.baslik}](/rehber/${yatay.slug}). Uydurma: bitti.`, duzeltme: 3, }, { ad: "koseli-parantez-kayipsiz", metin: "[2024] verisi ve [not] şöyle; `kod` de olduğu gibi kalır.", bekle: "[2024] verisi ve [not] şöyle; `kod` de olduğu gibi kalır.", duzeltme: 0, }, { ad: "baska-yol-dokunulmaz", metin: "[Ankara Üniversitesi](/universite/ankara-universitesi) ve [Tıp](/bolum/tip) kalır.", bekle: "[Ankara Üniversitesi](/universite/ankara-universitesi) ve [Tıp](/bolum/tip) kalır.", duzeltme: 0, }, { ad: "site-koku-ile-markdown", metin: "Oku: [OBP](https://kolaytercih.com/rehber/obp-nedir).", bekle: `Oku: [${obp.baslik}](/rehber/${obp.slug}).`, duzeltme: 1, }, ]; } /** Metni verilen parça sayısına rastgele olmayan, sabit noktalardan böler. */ function parcala(metin: string, adet: number): string[] { const boy = Math.max(1, Math.ceil(metin.length / adet)); const parcalar: string[] = []; for (let i = 0; i < metin.length; i += boy) parcalar.push(metin.slice(i, i + boy)); return parcalar; } function main() { const rehberler = getRehberAramaKayitlari(); if (rehberler.length < 10) throw new Error(`rehber listesi şüpheli derecede kısa: ${rehberler.length}`); let hata = 0; const kontrol = (ad: string, tuttu: boolean, detay: string) => { if (!tuttu) hata++; console.log(`${tuttu ? "geçti" : "KALDI"} [${ad}]${tuttu ? "" : `\n ${detay}`}`); }; for (const s of senaryolar(rehberler)) { const tek = rehberBaglantilariniDuzelt(s.metin, rehberler); const beklendi = typeof s.bekle === "string" ? tek.metin === s.bekle : s.bekle(tek.metin); kontrol(s.ad, beklendi && tek.duzeltmeler.length === s.duzeltme, `çıktı: ${tek.metin}\n düzeltme: ${JSON.stringify(tek.duzeltmeler)}`); // Tampon: metin 1, 3, 4, 7 ve karakter karakter parçalanınca da aynı sonuç for (const adet of [1, 3, 4, 7, s.metin.length]) { const tampon = new BaglantiTamponu(rehberler); let akis = ""; for (const p of parcala(s.metin, adet)) akis += tampon.besle(p); akis += tampon.bitir(); kontrol( `${s.ad} · tampon ${adet} parça`, akis === tek.metin && tampon.duzeltmeler.length === tek.duzeltmeler.length, `tampon: ${akis}\n tek seferlik: ${tek.metin}`, ); } } // Tampon bir bağlantı adayını kapanmadan bırakmamalı (yanlış hap ekrana gitmesin) { const tampon = new BaglantiTamponu(rehberler); const ilk = tampon.besle("Bak: [Yatay geçiş](/rehber/yatay-gecis"); const son = tampon.besle("-rehberi) iyi.") + tampon.bitir(); kontrol("tampon-adayi-tutuyor", ilk === "Bak: " && !ilk.includes("/rehber/") && son.includes("/rehber/yatay-gecis-cap-yandal"), `ilk: ${ilk}\n son: ${son}`); } { const tampon = new BaglantiTamponu(rehberler); const ilk = tampon.besle("Ayrıntı /reh"); const son = tampon.besle("ber/obp-nedir yazısında.") + tampon.bitir(); kontrol("tampon-yarim-onek", ilk === "Ayrıntı " && son.includes("/rehber/obp-nedir-nasil-hesaplanir"), `ilk: ${ilk}\n son: ${son}`); } const toplam = senaryolar(rehberler).length * 6 + 2; console.log(`\n${toplam - hata}/${toplam} senaryo geçti (mekanik test; gerçek model davranışını ölçmez)`); process.exit(hata ? 1 : 0); } main();