feat: update app.db and BACKLOG.md with new decisions and adjustments
All checks were successful
Deploy / deploy (push) Successful in 7m45s
All checks were successful
Deploy / deploy (push) Successful in 7m45s
- Updated the app.db file to reflect recent changes in the application state. - Modified BACKLOG.md to include new entries regarding the removal of certain wizard steps, adjustments to priority chips, and the introduction of special quota conditions for candidates. - Added details on the decision to link priority chips to data sources and clarified the implications for user experience and data handling.
This commit is contained in:
@@ -10,12 +10,19 @@ import {
|
||||
} from "@/types/yokatlas";
|
||||
import type { RaporParams } from "@/features/rapor/types/rapor";
|
||||
import { kategoriEslesir } from "./kategoriler";
|
||||
import { uyumBaglami, uyumBaglamiVar, uyumPuanla, type UyumBaglami } from "./uyum-puani";
|
||||
import { SON_YIL, YILLAR } from "./veri-yillari";
|
||||
|
||||
export type Dilim = "hayal" | "dengeli" | "garanti";
|
||||
|
||||
export interface AdayProgram extends Program {
|
||||
dilim: Dilim;
|
||||
/** Uyum puanı 0-1 (lib/uyum-puani.ts); ölçüt yoksa yazılmaz. */
|
||||
uyum?: number;
|
||||
/** Koddan üretilen "öne çıkan" veri cümleleri (≤3); gerekçede meşru sayı kaynağı. */
|
||||
oneCikan?: string[];
|
||||
/** Gevşetme katmanı (0 = adayın seçimine tam uyan); sıralamada birincil anahtar. */
|
||||
katman?: number;
|
||||
}
|
||||
|
||||
export type Gevsetilen = "profil" | "kategori" | "il";
|
||||
@@ -75,6 +82,15 @@ export type DilimHedef = Record<Dilim, number>;
|
||||
|
||||
// Listenin ideal iskeleti: 5 hayal / 13 dengeli / 6 garanti = 24 tercih.
|
||||
export const IDEAL_HEDEF: DilimHedef = { hayal: 5, dengeli: 13, garanti: 6 };
|
||||
// "Kolay yerleşme" önceliği seçiliyse güvenli dilim payı artar (6 Eki 2026):
|
||||
// 4 hayal / 12 dengeli / 8 güvenli. /meraklisina şeması bu iki iskeleti anlatır.
|
||||
export const IDEAL_HEDEF_KOLAY_YERLESME: DilimHedef = { hayal: 4, dengeli: 12, garanti: 8 };
|
||||
export const KOLAY_YERLESME_ONCELIGI = "Kolay yerleşme";
|
||||
|
||||
/** Adayın önceliklerine göre liste iskeleti (tek kaynak; rapor, mock ve eval aynı yoldan). */
|
||||
export function idealHedef(oncelikler?: readonly string[]): DilimHedef {
|
||||
return oncelikler?.includes(KOLAY_YERLESME_ONCELIGI) ? IDEAL_HEDEF_KOLAY_YERLESME : IDEAL_HEDEF;
|
||||
}
|
||||
|
||||
const DILIM_ONCELIGI: Dilim[] = ["dengeli", "garanti", "hayal"];
|
||||
|
||||
@@ -112,12 +128,15 @@ function eksigiDagit(pay: DilimHedef, mevcut: DilimHedef, toplam: number) {
|
||||
* en riskli dilim en son). Havuz 24'ün altındaysa hedef havuzun tamamıdır.
|
||||
* Deterministiktir: aynı havuz her zaman aynı hedefi üretir.
|
||||
*/
|
||||
export function dilimHedefiHesapla(havuz: AdayProgram[]): DilimHedef {
|
||||
export function dilimHedefiHesapla(
|
||||
havuz: AdayProgram[],
|
||||
ideal: DilimHedef = IDEAL_HEDEF,
|
||||
): DilimHedef {
|
||||
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),
|
||||
hayal: Math.min(ideal.hayal, mevcut.hayal),
|
||||
dengeli: Math.min(ideal.dengeli, mevcut.dengeli),
|
||||
garanti: Math.min(ideal.garanti, mevcut.garanti),
|
||||
};
|
||||
eksigiDagit(hedef, mevcut, Math.min(HEDEF, havuz.length));
|
||||
return hedef;
|
||||
@@ -166,16 +185,49 @@ function dilimBasinaKirp(havuz: AdayProgram[], n: number): AdayProgram[] {
|
||||
function oncelikliBirlestir(...katmanlar: AdayProgram[][]): AdayProgram[] {
|
||||
const gorulen = new Set<string>();
|
||||
const sonuc: AdayProgram[] = [];
|
||||
for (const katman of katmanlar) {
|
||||
katmanlar.forEach((katman, i) => {
|
||||
for (const p of katman) {
|
||||
if (gorulen.has(p.id)) continue;
|
||||
gorulen.add(p.id);
|
||||
sonuc.push(p);
|
||||
sonuc.push({ ...p, katman: i });
|
||||
}
|
||||
}
|
||||
});
|
||||
return sonuc;
|
||||
}
|
||||
|
||||
// Uyum puanının sıradaki ağırlığı; kalan sıraya yakınlık. İkisi de 0-1.
|
||||
const UYUM_AGIRLIGI = 0.6;
|
||||
|
||||
/**
|
||||
* Havuzu kırpmadan önce dilim içinde sıralar: önce gevşetme katmanı (adayın
|
||||
* seçimine uyanlar öne — bu kural uyum puanından güçlü), sonra
|
||||
* 0,6 × uyum + 0,4 × sıraya yakınlık (yakınlık dilim içinde 0-1'e açılır).
|
||||
* Puanı ve "öne çıkan" cümleleri satıra yazar. Ölçüt yoksa havuza dokunmaz:
|
||||
* sıra ve eval `beklenen` değerleri değişmez. Deterministik (kararlı sort).
|
||||
*/
|
||||
function uyumlaSirala(havuz: AdayProgram[], baglam: UyumBaglami): AdayProgram[] {
|
||||
if (!uyumBaglamiVar(baglam) || havuz.length === 0) return havuz;
|
||||
const puanlar = uyumPuanla(havuz, baglam);
|
||||
const sira = baglam.sira;
|
||||
const enUzak: Record<Dilim, number> = { hayal: 0, dengeli: 0, garanti: 0 };
|
||||
for (const p of havuz) {
|
||||
const d = Math.abs((p.efektifSira ?? sira) - sira);
|
||||
if (d > enUzak[p.dilim]) enUzak[p.dilim] = d;
|
||||
}
|
||||
const anahtar = (p: AdayProgram) => {
|
||||
const uyum = puanlar.get(p.id)?.puan ?? 0.5;
|
||||
const d = Math.abs((p.efektifSira ?? sira) - sira);
|
||||
const yakinlik = enUzak[p.dilim] > 0 ? 1 - d / enUzak[p.dilim] : 1;
|
||||
return UYUM_AGIRLIGI * uyum + (1 - UYUM_AGIRLIGI) * yakinlik;
|
||||
};
|
||||
return havuz
|
||||
.map((p) => {
|
||||
const u = puanlar.get(p.id);
|
||||
return u ? { ...p, uyum: u.puan, oneCikan: u.oneCikan } : p;
|
||||
})
|
||||
.sort((a, b) => (a.katman ?? 0) - (b.katman ?? 0) || anahtar(b) - anahtar(a));
|
||||
}
|
||||
|
||||
// Program adının sonundaki kontenjan eki; YÖK Atlas bu kontenjanları ayrı
|
||||
// program satırı olarak verir.
|
||||
const OZEL_KONTENJAN = /\((KKTC Uyruklu|M\.T\.O\.K\.)\)/;
|
||||
@@ -242,6 +294,10 @@ export function havuzOlustur(
|
||||
? havuz.filter((p) => p.il != null && liste.includes(p.il))
|
||||
: havuz;
|
||||
|
||||
// Uyum puanı bağlamı (öncelikler, özel durum, kampüs, ev ili) — havuzu
|
||||
// daraltmaz, kırpmadan önce sıralar (uyumlaSirala)
|
||||
const baglam = uyumBaglami(params, profil);
|
||||
|
||||
// 0. Profil süzgeci (danışmana söylenenler) — yalnız yeterli havuz bırakırsa.
|
||||
// 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.
|
||||
@@ -264,7 +320,7 @@ export function havuzOlustur(
|
||||
profilliFiltreli = kategoriFiltre(profilliHam);
|
||||
if (profilliFiltreli.length >= HEDEF) {
|
||||
return {
|
||||
havuz: dilimBasinaKirp(profilliFiltreli, PROMPT_LIMIT_DILIM),
|
||||
havuz: dilimBasinaKirp(uyumlaSirala(profilliFiltreli, baglam), PROMPT_LIMIT_DILIM),
|
||||
gevsetildi: [],
|
||||
};
|
||||
}
|
||||
@@ -277,7 +333,7 @@ export function havuzOlustur(
|
||||
const tamFiltreli = kategoriFiltre(tamHam);
|
||||
const kirp = (...katmanlar: AdayProgram[][]) =>
|
||||
dilimBasinaKirp(
|
||||
oncelikliBirlestir(profilliFiltreli, ...katmanlar),
|
||||
uyumlaSirala(oncelikliBirlestir(profilliFiltreli, ...katmanlar), baglam),
|
||||
PROMPT_LIMIT_DILIM,
|
||||
);
|
||||
if (tamFiltreli.length >= HEDEF) {
|
||||
@@ -338,6 +394,9 @@ export function havuzuKompaktJson(havuz: AdayProgram[]): string {
|
||||
),
|
||||
[`kontenjan${SON_YIL}`]: p.kontenjanSon,
|
||||
[`yerlesen${SON_YIL}`]: p.yerlesenSon,
|
||||
// Koddan hesaplanan "öne çıkan" veriler (uyum-puani.ts); model gerekçede
|
||||
// bunlardan birini yazabilir, başka sayı yazamaz (ai/rapor.ts denetimi)
|
||||
...(p.oneCikan && p.oneCikan.length > 0 ? { one_cikan: p.oneCikan } : {}),
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user