fix(revizyon): "ilk N" ölçütü seçimde kodla garanti ediliyor; mock yolu da kuralı uyguluyor
Model 24 geçerli satırı öncelikli satırsız doldurunca secimiOnar tamamlayacak
boşluk bulamıyor, ilkTercihleriOneAl öne alacak satır bulamıyordu ("ilk 5
İstanbul" istendi, liste değişmedi — 7 Eki 2026). Yeni saf fonksiyon
ilkTercihleriGarantile: ölçüte uyan ama seçilmemiş havuz programları, aynı
dilimdeki uymayan satırların (önce kodla gelen, sonra en düşük uyumlu; model
gerekçeli satırlar en son) yerine takasla girer, dilim adetleri değişmez.
rapor.ts: nihai seçimden sonra uygulanır, tani.ilkNEklenen alanı eklendi,
onarim.tamamlanan takas kadar artar, modelSecimi nihai seçimden yeniden
sayılır. Dev mock dilim içinde öncelikliyi önce alır ve ilkTercihleriOneAl
uygular.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,7 @@ import { ILK_YIL } from "../veri-yillari";
|
||||
import {
|
||||
cikarSuzgeci,
|
||||
efektifParams,
|
||||
ilkTercihleriGarantile,
|
||||
ilkTercihleriOneAl,
|
||||
kuralOzeti,
|
||||
oncelikSuzgeci,
|
||||
@@ -325,6 +326,8 @@ export type RaporTani = {
|
||||
uyariAtilan: string[];
|
||||
/** Koddan eklenen uyarı sayısı. */
|
||||
uyariSablon: number;
|
||||
/** Revizyonun "ilk N" ölçütü için kodla takas edilen satır sayısı (kural yoksa 0). */
|
||||
ilkNEklenen: number;
|
||||
};
|
||||
|
||||
// --- Deterministik satır metinleri: risk ve trend gerçek YÖK Atlas sıra
|
||||
@@ -369,15 +372,22 @@ function mockRapor(
|
||||
havuz: AdayProgram[],
|
||||
params: RaporParams,
|
||||
revizyonNotu?: string,
|
||||
oncelikli?: ((p: AdayProgram) => boolean) | null,
|
||||
): RaporSonuc {
|
||||
// Prod ile aynı hedef hesabı: mock, uyarlanmış dağılımı da birebir taklit eder
|
||||
const hedef = dilimHedefiHesapla(havuz, revizyonIskeleti(params));
|
||||
const toplamHedef = hedef.hayal + hedef.dengeli + hedef.garanti;
|
||||
const efektif = (p: AdayProgram) => p.efektifSira ?? 0;
|
||||
// Revizyonun "ilk N" ölçütüne uyanlar dilim içinde önce gelir (prod'daki
|
||||
// garanti takasının mock karşılığı); eşitte taban sırası iyiden kötüye
|
||||
const dilimden = (dilim: AdayProgram["dilim"], adet: number) =>
|
||||
havuz
|
||||
.filter((p) => p.dilim === dilim)
|
||||
.sort((a, b) => efektif(a) - efektif(b))
|
||||
.sort(
|
||||
(a, b) =>
|
||||
Number(oncelikli?.(b) ?? false) - Number(oncelikli?.(a) ?? false) ||
|
||||
efektif(a) - efektif(b),
|
||||
)
|
||||
.slice(0, adet);
|
||||
|
||||
const secilen = [
|
||||
@@ -386,7 +396,7 @@ function mockRapor(
|
||||
...dilimden("garanti", hedef.garanti),
|
||||
];
|
||||
|
||||
const tercihler = secilen.map((p, i) => ({
|
||||
const tercihlerHam = secilen.map((p, i) => ({
|
||||
programId: p.id,
|
||||
sira: i + 1,
|
||||
dilim: p.dilim,
|
||||
@@ -401,6 +411,9 @@ function mockRapor(
|
||||
for (const p of secilen) {
|
||||
programlar[p.id] = programBilgisi(p);
|
||||
}
|
||||
// Prod sırasıyla aynı: "ilk N" ölçütüne uyanlar başa (revizyon-kurali.ts)
|
||||
const secilenMap = new Map(secilen.map((p) => [p.id, p]));
|
||||
const { tercihler } = ilkTercihleriOneAl(tercihlerHam, params.revizyon, (id) => secilenMap.get(id));
|
||||
|
||||
return {
|
||||
tercihler,
|
||||
@@ -551,7 +564,7 @@ export async function raporUretAyrintili(
|
||||
// Dev'de API key yoksa gerçek Yapay Zeka yerine mock rapor (üretim gecikmesi taklidi)
|
||||
if (mockAktif()) {
|
||||
await new Promise((r) => setTimeout(r, 1500));
|
||||
return { rapor: mockRapor(havuz, params, revizyonNotu), tani: null };
|
||||
return { rapor: mockRapor(havuz, params, revizyonNotu, oncelikli), tani: null };
|
||||
}
|
||||
|
||||
const kullaniciMesaji = [
|
||||
@@ -709,7 +722,31 @@ export async function raporUretAyrintili(
|
||||
uyarilar: [],
|
||||
};
|
||||
}
|
||||
const nihai = enIyi;
|
||||
// "İlk N" garantisi (revizyon-kurali.ts): model öncelikli satırları
|
||||
// atlamışsa ölçüte uyan havuz programları, aynı dilimdeki uymayan satırların
|
||||
// yerine takasla girer; dilim adetleri değişmez. Prompt'taki "EN AZ N tane
|
||||
// seç" ricadır, sonuç buraya bağlıdır. Takasla giren satırın gerekçesi
|
||||
// şablondan basılır (kaynak "tamamlandi").
|
||||
const garanti = ilkTercihleriGarantile(
|
||||
enIyi.secim,
|
||||
havuz,
|
||||
kural,
|
||||
uyum,
|
||||
(p): SeciliSatir => ({ programId: p.id, gerekce: null, kaynak: "tamamlandi" }),
|
||||
);
|
||||
const nihai: Deneme = {
|
||||
...enIyi,
|
||||
secim: garanti.secim,
|
||||
onarim: {
|
||||
...enIyi.onarim,
|
||||
tamamlanan: enIyi.onarim.tamamlanan + garanti.eklenen,
|
||||
// Takas model satırı çıkarmış olabilir: sayı nihai seçimden yeniden okunur
|
||||
modelSecimi: DILIMLER.reduce(
|
||||
(n, d) => n + garanti.secim[d].filter((s) => s.kaynak !== "tamamlandi").length,
|
||||
0,
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
// --- Metin denetimi (deterministik; ek model çağrısı yok). İhlalli metin
|
||||
// kullanıcıya gitmez, koddan üretilen şablona düşer.
|
||||
@@ -882,6 +919,7 @@ export async function raporUretAyrintili(
|
||||
genelSablon,
|
||||
uyariAtilan,
|
||||
uyariSablon,
|
||||
ilkNEklenen: garanti.eklenen,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user