From 6e78485228b9c09f4fc5126f1b249defa12e91c5 Mon Sep 17 00:00:00 2001 From: ht Date: Sun, 6 Sep 2026 18:09:06 +0300 Subject: [PATCH] skip malformed tender rows during deduplication --- docs/quality/uygulama-durumu.md | 6 ++++++ server/tender-quality.mjs | 2 ++ tests/tender-quality.test.mjs | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/docs/quality/uygulama-durumu.md b/docs/quality/uygulama-durumu.md index 78614d0..bf12285 100644 --- a/docs/quality/uygulama-durumu.md +++ b/docs/quality/uygulama-durumu.md @@ -1976,3 +1976,9 @@ Doğrulama: 286 test geçti, üretim derlemesi başarılı. Sağlık portföyü kayıt kimlikleri artık kırpılarak tekilleştiriliyor ve 200 karakterle sınırlandırılıyor; yalnızca boşluk farkıyla oluşturulan kopya ürün kayıtları reddediliyor. Doğrulama: HTTP profil testleri 19/19 geçti, üretim derlemesi başarılı. + +### 2026-09-06 · Bozuk ihale satırlarında tekilleştirme dayanıklılığı + +Kaynak havuzundan gelen null, dizi veya kimliksiz satırlar artık tekilleştirme sırasında tüm havuzu düşürmüyor; geçersiz satır atlanıp geçerli ihale kayıtları işlenmeye devam ediyor. + +Doğrulama: 287 test geçti, üretim derlemesi başarılı. diff --git a/server/tender-quality.mjs b/server/tender-quality.mjs index 5cccf8b..5bf27ef 100644 --- a/server/tender-quality.mjs +++ b/server/tender-quality.mjs @@ -11,6 +11,8 @@ export function tenderIdentity(t) { export function uniqueTenders(records) { const found = new Map(); for (const t of records) { + // Kaynaklardan gelen bozuk/null satırlar tüm havuz birleştirmesini düşürmemeli. + if (!t || typeof t !== 'object' || Array.isArray(t) || typeof t.id !== 'string' || !t.id.trim()) continue; const key = tenderIdentity(t), old = found.get(key); if (!old) { found.set(key,{...t,sourceIds:[t.id]}); continue; } const sourceIds = [...new Set([...old.sourceIds,t.id])]; diff --git a/tests/tender-quality.test.mjs b/tests/tender-quality.test.mjs index a6ee3d5..5066ee6 100644 --- a/tests/tender-quality.test.mjs +++ b/tests/tender-quality.test.mjs @@ -11,6 +11,10 @@ test('distinct contract lots and corrections remain separate',()=>{ assert.equal(uniqueTenders([t,t,{...t,id:'b',kisim:'2'}]).length,2); assert.equal(uniqueTenders([{ikn:'2026/123',id:'1'},{ikn:'2026/123',id:'2',baslik:'Düzeltme ilanı'}]).length,2); }); +test('malformed source rows do not crash pool deduplication',()=>{ + const out=uniqueTenders([null,42,{},[],{ikn:'2026/123',baslik:'Eksik kimlik'}]); + assert.deepEqual(out,[]); +}); test('announcement preserves full text and extracts source-backed fields',()=>{ const text='x'.repeat(4500)+' Tarih ve Saati : 10.09.2026 - 10:00 3.3. Teslim edileceği yer : Patoloji laboratuvarı 3.4. Süresi/teslim tarihi : 30 gün 3.5. İşe başlama tarihi : sözleşme'; const d=announcementFields(text);assert.equal(d.aciklama,text);assert.equal(d.saat,'10:00');assert.equal(d.teslimYeri,'Patoloji laboratuvarı');assert.equal(d.teslimatSuresi,'30 gün');