fix(havuz): B2 — başarı sırası barajını geçemeyen adaya o bölüm önerilmesin [KARAR]

Havuz yalnız taban sırasına bakıyordu; hayal dilimi "adayın üstünde
kapanan her şey" olduğu için barajın hemen dışındaki adaya tam da
yazamayacağı bölümler düşüyordu (52.000 sıralı adaya tıp, 310.000'e
mühendislik). Kaynak uydurma tablo değil: program_ozellik.min_basari_sirasi
(YÖK Atlas API, 2026 kılavuzu; katalogdaki "baraj … sıra" satırı ve
danışmanın tercihBaraji alanı da aynı kolonu okur). db.havuzAdaylari artık
min_basari_sirasi < adayın sırası olan programları SQL'de çıkarır; barajı
boş program süzülmez.

Kanıt (havuzdaki baraj dışı program, önce → sonra): a04 4 → 0, a06 11 → 0,
a08 11 → 0, p03 17 → 0; 40 profilin hepsinde 0. a07 (SÖZ 310.000, eğitim):
alandaki programların tamamı barajlı olduğu için alan artık gerçekten
gevşiyor (24 hayal → 5/13/6).

Bilinen sınır: kolon bazı barajlı bölümlerde boş (ör. 16 tıp, 11 hukuk
satırı) — veri işi, raporda.

/meraklisina şeması (aday havuzu düğümü), 4. bölüm anlatımı, aria-label
ve figcaption aynı kuralla güncellendi.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-10-05 01:17:01 +03:00
parent 22ac604233
commit 0a11b15304
4 changed files with 55 additions and 16 deletions

View File

@@ -17,7 +17,7 @@ flowchart TD
A --> B("2. adım · İl seçimi<br/>programı olan tüm iller, seçtiğin alanlardaki program sayısına göre yeniden sayılır") A --> B("2. adım · İl seçimi<br/>programı olan tüm iller, seçtiğin alanlardaki program sayısına göre yeniden sayılır")
B --> C("3. adım · Devlet / Vakıf<br/>sayılar hem alanı hem ili hesaba katar") B --> C("3. adım · Devlet / Vakıf<br/>sayılar hem alanı hem ili hesaba katar")
C --> P("Danışmana söylediklerin<br/>öğretim dili, uzaktan/örgün, burs, yıllık ücret sınırı, evden uzaklık — sohbette söyleyip kaydettiklerin varsa havuzu bunlar da süzer") C --> P("Danışmana söylediklerin<br/>öğretim dili, uzaktan/örgün, burs, yıllık ücret sınırı, evden uzaklık — sohbette söyleyip kaydettiklerin varsa havuzu bunlar da süzer")
P --> H("Aday havuzu<br/>elde kalan gerçek programlar — yalnızca en son tercih kılavuzunda yer alanlar<br/>kapanan ya da kodu değişip eski kaydı kalan programlar önerilmez<br/>yalnızca KKTC uyruklulara ya da meslek lisesi mezunlarına ayrılmış kontenjanlar da havuza girmez") P --> H("Aday havuzu<br/>elde kalan gerçek programlar — yalnızca en son tercih kılavuzunda yer alanlar<br/>kapanan ya da kodu değişip eski kaydı kalan programlar önerilmez<br/>yalnızca KKTC uyruklulara ya da meslek lisesi mezunlarına ayrılmış kontenjanlar da havuza girmez<br/>sıralaman bir bölümün başarı sırası barajının gerisindeyse (tıp, hukuk, mühendislik, öğretmenlik gibi) o bölüm de girmez")
H --> S{"Havuzda 24'ten az program mı kaldı?"} H --> S{"Havuzda 24'ten az program mı kaldı?"}
S -- "evet" --> G("Filtreler adım adım gevşetilir<br/>önce danışmana söylediklerin, sonra il, sonra alan — listede açıkça belirtilir<br/>seçimine uyan programlar havuzda kalır, boşluk sıralamana en yakın diğer programlarla dolar") S -- "evet" --> G("Filtreler adım adım gevşetilir<br/>önce danışmana söylediklerin, sonra il, sonra alan — listede açıkça belirtilir<br/>seçimine uyan programlar havuzda kalır, boşluk sıralamana en yakın diğer programlarla dolar")
G --> H G --> H
@@ -45,13 +45,13 @@ export function HuniSemasi() {
return ( return (
<ElCizimiSema <ElCizimiSema
tanim={SEMA} tanim={SEMA}
ariaLabel="Sihirbaz akış şeması: sıralamanla açılan programlar alan, il ve devlet/vakıf adımlarıyla, danışmana söyleyip kaydettiğin tercihler (öğretim dili, uzaktan/örgün, burs, yıllık ücret sınırı, evden uzaklık) varsa onlarla da aday havuzuna daraltılır; havuza yalnızca en son tercih kılavuzunda yer alan programlar girer, kapanan ya da kodu değişip eski kaydı kalan programlar önerilmez, yalnızca KKTC uyruklulara ya da meslek lisesi mezunlarına ayrılmış kontenjanlar da havuza girmez; alanlar bölümün adına ve bağlı olduğu fakülteye göre belirlenir, il adımında programı olan tüm iller listelenir; havuz 24'ün altına düşerse filtreler önce danışmana söylediklerin, sonra il, sonra alan sırasıyla gevşetilir, gevşeyen seçimine uyan programlar havuzda kalır ve boşluk sıralamana en yakın diğer programlarla dolar, yine de dar kalırsa liste eldeki programlarla kurulur ve dağılım havuza uyarlanır; yapay zekâ havuzdan üstte hayal, ortada dengeli, sonda güvenli olacak şekilde en fazla 24 tercih seçip her satıra gerekçe yazar; risk notu ve trend özeti gerçek sıralama geçmişinden hesaplanır." ariaLabel="Sihirbaz akış şeması: sıralamanla açılan programlar alan, il ve devlet/vakıf adımlarıyla, danışmana söyleyip kaydettiğin tercihler (öğretim dili, uzaktan/örgün, burs, yıllık ücret sınırı, evden uzaklık) varsa onlarla da aday havuzuna daraltılır; havuza yalnızca en son tercih kılavuzunda yer alan programlar girer, kapanan ya da kodu değişip eski kaydı kalan programlar önerilmez, yalnızca KKTC uyruklulara ya da meslek lisesi mezunlarına ayrılmış kontenjanlar da havuza girmez, sıralaman bir bölümün başarı sırası barajının gerisindeyse (tıp, hukuk, mühendislik, öğretmenlik gibi) o bölüm de girmez; alanlar bölümün adına ve bağlı olduğu fakülteye göre belirlenir, il adımında programı olan tüm iller listelenir; havuz 24'ün altına düşerse filtreler önce danışmana söylediklerin, sonra il, sonra alan sırasıyla gevşetilir, gevşeyen seçimine uyan programlar havuzda kalır ve boşluk sıralamana en yakın diğer programlarla dolar, yine de dar kalırsa liste eldeki programlarla kurulur ve dağılım havuza uyarlanır; yapay zekâ havuzdan üstte hayal, ortada dengeli, sonda güvenli olacak şekilde en fazla 24 tercih seçip her satıra gerekçe yazar; risk notu ve trend özeti gerçek sıralama geçmişinden hesaplanır."
figcaption={ figcaption={
<> <>
Havuza yalnızca en son tercih kılavuzunda yer alan programlar girer; Havuza yalnızca en son tercih kılavuzunda yer alan programlar girer;
kapanan ya da kodu değişip eski kaydı kalan programlar, yalnızca KKTC kapanan ya da kodu değişip eski kaydı kalan programlar, yalnızca KKTC
uyruklulara ya da meslek lisesi mezunlarına ayrılmış kontenjanlar uyruklulara ya da meslek lisesi mezunlarına ayrılmış kontenjanlar ve
önerilmez. Her başarı sırası barajını geçemediğin bölümler önerilmez. Her
adım havuzu biraz daha daraltır; danışmana söyleyip kaydettiğin adım havuzu biraz daha daraltır; danışmana söyleyip kaydettiğin
tercihler de (dil, ücret, uzaklık gibi) havuzu süzer. Yapay zekâ tercihler de (dil, ücret, uzaklık gibi) havuzu süzer. Yapay zekâ
listeyi bu havuzun{" "} listeyi bu havuzun{" "}

View File

@@ -127,7 +127,10 @@ export function MeraklisinaIcerik() {
kalmış bir program sana önerilmez. Adında &ldquo;KKTC kalmış bir program sana önerilmez. Adında &ldquo;KKTC
Uyruklu&rdquo; ya da &ldquo;M.T.O.K.&rdquo; (meslek lisesi Uyruklu&rdquo; ya da &ldquo;M.T.O.K.&rdquo; (meslek lisesi
mezunlarına ayrılmış) yazan kontenjanlar da havuza girmez; onlar mezunlarına ayrılmış) yazan kontenjanlar da havuza girmez; onlar
herkesin yazabileceği tercihler değildir. Aşağıdaki şema akışın herkesin yazabileceği tercihler değildir. Tıp, hukuk, mühendislik
ya da öğretmenlik gibi başarı sırası barajı olan bölümlerde
sıralaman barajın gerisindeyse o bölümü tercih edemezsin; bu
yüzden o da havuza girmez. Aşağıdaki şema akışın
tamamını gösterir — havuz 24&apos;ün altına düşerse filtrelerin hangi tamamını gösterir — havuz 24&apos;ün altına düşerse filtrelerin hangi
sırayla gevşetildiği (önce danışmana söylediklerin, sonra il, sırayla gevşetildiği (önce danışmana söylediklerin, sonra il,
sonra alan), yine de yetmezse listenin eldeki programlarla, sana sonra alan), yine de yetmezse listenin eldeki programlarla, sana

View File

@@ -89,6 +89,16 @@ export type OzellikSuzgeci = {
let ozellikTablosuVar: boolean | null = null; let ozellikTablosuVar: boolean | null = null;
function ozellikTablosuVarMi(): boolean {
if (ozellikTablosuVar == null) {
ozellikTablosuVar =
getDb()
.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='program_ozellik'")
.get() !== undefined;
}
return ozellikTablosuVar;
}
function ozellikFiltreSql(o?: OzellikSuzgeci): { sql: string; args: (string | number)[] } { function ozellikFiltreSql(o?: OzellikSuzgeci): { sql: string; args: (string | number)[] } {
if (!o) return { sql: "", args: [] }; if (!o) return { sql: "", args: [] };
const kosul: string[] = []; const kosul: string[] = [];
@@ -104,19 +114,27 @@ function ozellikFiltreSql(o?: OzellikSuzgeci): { sql: string; args: (string | nu
args.push(o.ucretUst); args.push(o.ucretUst);
} }
if (kosul.length === 0) return { sql: "", args: [] }; if (kosul.length === 0) return { sql: "", args: [] };
if (ozellikTablosuVar == null) { if (!ozellikTablosuVarMi()) return { sql: "", args: [] };
ozellikTablosuVar =
getDb()
.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='program_ozellik'")
.get() !== undefined;
}
if (!ozellikTablosuVar) return { sql: "", args: [] };
return { return {
sql: `AND id IN (SELECT id FROM program_ozellik WHERE ${kosul.join(" AND ")})`, sql: `AND id IN (SELECT id FROM program_ozellik WHERE ${kosul.join(" AND ")})`,
args, args,
}; };
} }
/**
* Başarı sırası barajı: `program_ozellik.min_basari_sirasi` programı tercih
* edebilmek için gereken en düşük sıradır (YÖK Atlas'tan, kılavuz yılına ait;
* ör. tıp 50.000). Adayın sırası bundan kötüyse o programı yazamaz. Barajı
* boş olan program (barajsız ya da veride eksik) süzülmez.
*/
function barajFiltreSql(sira: number): { sql: string; args: number[] } {
if (!ozellikTablosuVarMi()) return { sql: "", args: [] };
return {
sql: "AND id NOT IN (SELECT id FROM program_ozellik WHERE min_basari_sirasi < ?)",
args: [sira],
};
}
function uniturFiltreSql(grup?: UniturGrubu): { sql: string; args: string[] } { function uniturFiltreSql(grup?: UniturGrubu): { sql: string; args: string[] } {
if (grup === "devlet") return { sql: "AND unitur = ?", args: ["DEVLET"] }; if (grup === "devlet") return { sql: "AND unitur = ?", args: ["DEVLET"] };
if (grup === "vakif") if (grup === "vakif")
@@ -155,6 +173,8 @@ export function dilimAra(
iller?: string[]; iller?: string[];
uniturGrubu?: UniturGrubu; uniturGrubu?: UniturGrubu;
ozellik?: OzellikSuzgeci; ozellik?: OzellikSuzgeci;
/** Adayın sırasıyla yazamayacağı (baraj dışı) programları çıkar */
barajDisiHaric?: boolean;
limit?: number; limit?: number;
offset?: number; offset?: number;
} = {} } = {}
@@ -176,16 +196,27 @@ export function dilimAra(
: ""; : "";
const unitur = uniturFiltreSql(opts.uniturGrubu); const unitur = uniturFiltreSql(opts.uniturGrubu);
const ozellik = ozellikFiltreSql(opts.ozellik); const ozellik = ozellikFiltreSql(opts.ozellik);
const baraj = opts.barajDisiHaric
? barajFiltreSql(sira)
: { sql: "", args: [] };
const { alt, ust } = dilimAraligi(sira, dilim); const { alt, ust } = dilimAraligi(sira, dilim);
if (ust != null && ust < alt) return { programlar: [], toplam: 0 }; if (ust != null && ust < alt) return { programlar: [], toplam: 0 };
const siraKosulu = const siraKosulu =
ust != null ? `${EFEKTIF_SIRA} BETWEEN ? AND ?` : `${EFEKTIF_SIRA} >= ?`; ust != null ? `${EFEKTIF_SIRA} BETWEEN ? AND ?` : `${EFEKTIF_SIRA} >= ?`;
const siraArgs = ust != null ? [alt, ust] : [alt]; const siraArgs = ust != null ? [alt, ust] : [alt];
const args = [tur, onlisans, ...illerListe, ...unitur.args, ...ozellik.args, ...siraArgs]; const args = [
tur,
onlisans,
...illerListe,
...unitur.args,
...ozellik.args,
...baraj.args,
...siraArgs,
];
const base = `FROM programs const base = `FROM programs
WHERE tur = ? AND onlisans = ? ${ilFiltre} ${unitur.sql} ${ozellik.sql} WHERE tur = ? AND onlisans = ? ${ilFiltre} ${unitur.sql} ${ozellik.sql} ${baraj.sql}
AND ${EFEKTIF_SIRA} IS NOT NULL AND ${EFEKTIF_SIRA} IS NOT NULL
AND ${siraKosulu}`; AND ${siraKosulu}`;
// hayal: sınıra en yakın (en büyük taban) önce; diğerleri en yakından uzağa // hayal: sınıra en yakın (en büyük taban) önce; diğerleri en yakından uzağa
@@ -246,6 +277,7 @@ export function searchByRank(
* alandan karışık geldiği için seçilen alan olduğundan az görünüyordu. Bu * alandan karışık geldiği için seçilen alan olduğundan az görünüyordu. Bu
* yüzden havuz dilimin tamamını alır, alan/il süzgecini kendisi uygular ve * yüzden havuz dilimin tamamını alır, alan/il süzgecini kendisi uygular ve
* en son kırpar (bkz. lib/rapor-havuzu.ts). En büyük puan türü ~9 bin satır. * en son kırpar (bkz. lib/rapor-havuzu.ts). En büyük puan türü ~9 bin satır.
* Adayın başarı sırası barajını geçemediği programlar buraya hiç girmez.
*/ */
export function havuzAdaylari( export function havuzAdaylari(
sira: number, sira: number,
@@ -253,7 +285,7 @@ export function havuzAdaylari(
opts: { uniturGrubu?: UniturGrubu; ozellik?: OzellikSuzgeci } = {} opts: { uniturGrubu?: UniturGrubu; ozellik?: OzellikSuzgeci } = {}
): Record<DilimKey, Program[]> { ): Record<DilimKey, Program[]> {
// LIMIT -1: SQLite'ta "sınırsız" // LIMIT -1: SQLite'ta "sınırsız"
const ortak = { ...opts, limit: -1 }; const ortak = { ...opts, barajDisiHaric: true, limit: -1 };
return { return {
hayal: dilimAra(sira, turKey, "hayal", ortak).programlar, hayal: dilimAra(sira, turKey, "hayal", ortak).programlar,
dengeli: dilimAra(sira, turKey, "dengeli", ortak).programlar, dengeli: dilimAra(sira, turKey, "dengeli", ortak).programlar,

View File

@@ -214,6 +214,9 @@ function dilimEkle(r: {
* "24'ten az" kararı o alanda/ilde gerçekten kaç program olduğuna bakar. * "24'ten az" kararı o alanda/ilde gerçekten kaç program olduğuna bakar.
* Bir filtre gevşediğinde ona uyan programlar havuzdan düşmez: önce onlar * Bir filtre gevşediğinde ona uyan programlar havuzdan düşmez: önce onlar
* alınır, boşluk sıraya en yakın diğer programlarla dolar. * alınır, boşluk sıraya en yakın diğer programlarla dolar.
*
* Adayın yazamayacağı programlar hiçbir basamakta havuza girmez: başarı
* sırası barajının gerisinde kaldığı bölümler ve özel kontenjan satırları.
*/ */
export function havuzOlustur( export function havuzOlustur(
params: RaporParams, params: RaporParams,
@@ -242,7 +245,8 @@ export function havuzOlustur(
// Bırakmazsa profil gevşetilir ve aşağıdaki sihirbaz akışı aynen sürer; // Bırakmazsa profil gevşetilir ve aşağıdaki sihirbaz akışı aynen sürer;
// liste yine kurulur, gevşetme yapay zekâya ve adaya söylenir. // liste yine kurulur, gevşetme yapay zekâya ve adaya söylenir.
const suzgec = profilSuzgeci(profil, iller.length > 0); const suzgec = profilSuzgeci(profil, iller.length > 0);
// Dilimin tamamı; özel kontenjan satırları (KKTC uyruklu, M.T.O.K.) hariç // Dilimin tamamı; adayın barajını geçemediği programlar (SQL) ve özel
// kontenjan satırları (KKTC uyruklu, M.T.O.K.) hariç
const adaylar = (ozellik?: OzellikSuzgeci) => const adaylar = (ozellik?: OzellikSuzgeci) =>
dilimEkle( dilimEkle(
havuzAdaylari(params.sira, params.tur, { uniturGrubu, ozellik }), havuzAdaylari(params.sira, params.tur, { uniturGrubu, ozellik }),