From c1d81cd1ec26b22215684774e38989d38d23c675 Mon Sep 17 00:00:00 2001 From: bilalgursen Date: Mon, 5 Oct 2026 01:13:57 +0300 Subject: [PATCH] =?UTF-8?q?fix(havuz):=20B1=20=E2=80=94=20tek=20dilime=20y?= =?UTF-8?q?=C4=B1=C4=9F=C4=B1lan=20havuz=2024'=C3=BCn=20alt=C4=B1na=20k?= =?UTF-8?q?=C4=B1rp=C4=B1lmas=C4=B1n=20[KARAR]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 24 eşiği kırpmadan önce sayılıyor, sonra her dilim 20'ye iniyordu; havuzu tek dilimde toplanan adayın listesi 20–22 satırda kalıyordu (SAY 800 devlet sağlık: 617 güvenli program varken 22 satır). Kırpma artık dilim başına 20'yi korur ama toplam 24'ün altına düşecekse eksiği, adayı kalan dilimlerden tamamlar. Dağıtım kuralı dilimHedefiHesapla ile aynı (dengeli → güvenli → hayal) ve tek yardımcıda toplandı; 5/13/6 iskeleti ve hedef hesabı değişmedi. Kanıt (liste satırı, önce → sonra): a02 22 → 24 (1/1/22), a01 21 → 24, a11/a12/a17/b05 20 → 24. Diğer 33 profilde havuz birebir aynı. Co-Authored-By: Claude Fable 5.1 --- src/lib/rapor-havuzu.ts | 68 ++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/src/lib/rapor-havuzu.ts b/src/lib/rapor-havuzu.ts index fc33807..aab3f16 100644 --- a/src/lib/rapor-havuzu.ts +++ b/src/lib/rapor-havuzu.ts @@ -76,6 +76,35 @@ export type DilimHedef = Record; // Listenin ideal iskeleti: 5 hayal / 13 dengeli / 6 garanti = 24 tercih. export const IDEAL_HEDEF: DilimHedef = { hayal: 5, dengeli: 13, garanti: 6 }; +const DILIM_ONCELIGI: Dilim[] = ["dengeli", "garanti", "hayal"]; + +function dilimSay(havuz: AdayProgram[]): DilimHedef { + const mevcut: DilimHedef = { hayal: 0, dengeli: 0, garanti: 0 }; + for (const p of havuz) mevcut[p.dilim]++; + return mevcut; +} + +/** + * `pay` toplamı `toplam`ın altındaysa eksiği, adayı kalan dilimlere birer + * birer dağıtır (öncelik: dengeli → garanti → hayal — omurga önce, sigorta + * sonra, en riskli dilim en son). `pay`'i yerinde günceller. + */ +function eksigiDagit(pay: DilimHedef, mevcut: DilimHedef, toplam: number) { + let eksik = toplam - pay.hayal - pay.dengeli - pay.garanti; + while (eksik > 0) { + let dagitildi = false; + for (const d of DILIM_ONCELIGI) { + if (eksik <= 0) break; + if (mevcut[d] > pay[d]) { + pay[d]++; + eksik--; + dagitildi = true; + } + } + if (!dagitildi) break; + } +} + /** * Havuzun gerçek dilim dağılımına uyarlanmış liste hedefi. İdeal 5/13/6'dan * başlar; bir dilimde yeterli aday yoksa eksik, kapasitesi kalan dilimlere @@ -84,30 +113,13 @@ export const IDEAL_HEDEF: DilimHedef = { hayal: 5, dengeli: 13, garanti: 6 }; * Deterministiktir: aynı havuz her zaman aynı hedefi üretir. */ export function dilimHedefiHesapla(havuz: AdayProgram[]): DilimHedef { - const mevcut: DilimHedef = { hayal: 0, dengeli: 0, garanti: 0 }; - for (const p of havuz) mevcut[p.dilim]++; - - const toplamHedef = Math.min(HEDEF, havuz.length); + const mevcut = dilimSay(havuz); const hedef: DilimHedef = { hayal: Math.min(IDEAL_HEDEF.hayal, mevcut.hayal), dengeli: Math.min(IDEAL_HEDEF.dengeli, mevcut.dengeli), garanti: Math.min(IDEAL_HEDEF.garanti, mevcut.garanti), }; - - const oncelik: Dilim[] = ["dengeli", "garanti", "hayal"]; - let eksik = toplamHedef - hedef.hayal - hedef.dengeli - hedef.garanti; - while (eksik > 0) { - let dagitildi = false; - for (const d of oncelik) { - if (eksik <= 0) break; - if (mevcut[d] > hedef[d]) { - hedef[d]++; - eksik--; - dagitildi = true; - } - } - if (!dagitildi) break; - } + eksigiDagit(hedef, mevcut, Math.min(HEDEF, havuz.length)); return hedef; } // Prompt'a giden nihai havuz: dilim başına aday sayısı. Arama dilimin tamamını @@ -116,10 +128,22 @@ export function dilimHedefiHesapla(havuz: AdayProgram[]): DilimHedef { // modellerde prefill + isabet maliyeti yüksek (ölçüm: 6 Ağu 2026). const PROMPT_LIMIT_DILIM = 20; -/** Dilim sırasını koruyarak her dilimden en fazla n aday bırakır. */ +/** + * Dilim sırasını koruyarak her dilimden en fazla n aday bırakır. Havuz tek + * dilime yığılmışsa (ör. çok iyi derece: neredeyse hepsi güvenli) n'e kırpmak + * listeyi 24'ün altına düşürürdü; o durumda eksik, adayı kalan dilimlerden + * tamamlanır — yeterli program varken liste 24'ten kısa kalmaz. + */ function dilimBasinaKirp(havuz: AdayProgram[], n: number): AdayProgram[] { - const sayac: Record = { hayal: 0, dengeli: 0, garanti: 0 }; - return havuz.filter((p) => ++sayac[p.dilim] <= n); + const mevcut = dilimSay(havuz); + const pay: DilimHedef = { + hayal: Math.min(n, mevcut.hayal), + dengeli: Math.min(n, mevcut.dengeli), + garanti: Math.min(n, mevcut.garanti), + }; + eksigiDagit(pay, mevcut, Math.min(HEDEF, havuz.length)); + const sayac: DilimHedef = { hayal: 0, dengeli: 0, garanti: 0 }; + return havuz.filter((p) => ++sayac[p.dilim] <= pay[p.dilim]); } function dilimEkle(r: {