Files
iddaai-be/mds/archive/02_deep_fixes_log.md
T
fahricansecer 2f0b85a0c7
Deploy Iddaai Backend / build-and-deploy (push) Failing after 18s
first (part 2: other directories)
2026-04-16 15:11:25 +03:00

79 lines
4.3 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Derin Teknik Düzeltmeler ve Analiz Günlüğü
**Dosya:** `02_deep_fixes_log.md`
**Amaç:** Son geliştirme döngüsünde çözülen karmaşık sorunların teknik detaylarını belgelemek.
---
## 1. Live Match Synchronization & DB Safety
### Sorun Tanımı
Canlı maçlar (Live Matches), ana `matches` tablosuna henüz işlenmemiş olabiliyor. Ancak sistem bunları analiz etmeye çalıştığında:
1. `match_player_participation` tablosuna oyuncu eklemeye çalışıyor -> `matches` tablosunda ID olmadığı için **Foreign Key Constraint Error** alıyordu.
2. Veri tabana yazılamadığı için Python scripti "Lineup not found" hatasıyla patlıyordu.
### Uygulanan Çözüm
**Dual-Persistence Strategy (Çift Yazma Stratejisi):**
- **Logic:** `FeederPersistenceService.saveLineups` ve `saveOdds` metodları artık önce `matches` tablosunda `matchId` var mı diye kontrol ediyor.
- **Varsa:** Hem ilişkisel tablolara (`match_player_participation`) hem de `live_matches` JSON kolonuna yazıyor.
- **Yoksa (Sadece Canlı):** İlişkisel tabloları tamamen pas geçiyor (SKIP), veriyi sadece `live_matches.lineups` ve `live_matches.odds` JSON kolonlarına strüktüre edilmiş olarak yazıyor.
**Fallback Mechanism (Python & NestJS):**
- **NestJS:** `getPlayerCount` metodu önce ilişkisel tabloyu sayıyor. Sayı 0 ise `live_matches` JSON'ını parse edip oradaki oyuncu sayısını dönüyor.
- **Python:** `_run_model` içinde önce SQL sorgusu ile kadro çekmeye çalışıyor. Liste boşsa, `live_matches` tablosundaki JSON kolonunu çekip manuel parse ediyor.
---
## 2. Model Score & Context Mapping (Kritik)
### Sorun Tanımı
Kullanıcı, modelin skor tahminlerinin ve maç sonucu (1/X/2) tercihlerinin tutarsız olduğundan şikayetçiydi ("Home win diyor ama skor 0-1" gibi).
### Tespit Edilen Kök Nedenler
1. **HT/FT Sıralaması:** Model eğitimi `ht*3 + ft` (0=X, 1=1, 2=2) mantığıyla yapılmıştı. Ancak tahmin scripti etiketleri `1/1, 1/X...` gibi rastgele bir sırayla diziyordu. Bu yüzden `1/1` tahmini `X/X` gibi görünüyordu.
2. **Beraberlik (Draw) Körlüğü:** Data Feeder, beraberlik oranını `X` etiketiyle kaydediyordu (Mackolik verisi). Python scripti ise sadece `0` etiketini "Beraberlik" olarak kabul ediyordu. Sonuç olarak model "Beraberlik Oranı: 0.0" görüyordu (yani oran yok). Bu, modelin maçın dengesini yanlış anlamasına neden oluyordu.
3. **Away Bias (Deplasman Yanlılığı):** Backtest verileri, modelin sistematik olarak deplasman takımına fazla gol yazdığını (%15-20 fazla) gösterdi.
### Uygulanan Çözüm
1. **Etiket Düzeltmesi:** `htft_labels` listesi `[X/X, X/1, X/2, 1/X, 1/1, 1/2, 2/X, 2/1, 2/2]` olarak, eğitim verisiyle %100 uyumlu hale getirildi.
2. **Oran Normalizasyonu:** Python scripti artık hem `0` hem `X` etiketlerini beraberlik oranı olarak kabul ediyor.
3. **Skor Kalibrasyonu:** Backtest sonrası optimizasyon katsayıları eklendi.
- `HOME_GOAL_SCALE = 1.00`
- `AWAY_GOAL_SCALE = 0.85`
---
## 3. Akıllı Kupon Servisi (Smart Coupon)
### Yapı
NestJS tarafında `SmartCouponService` ve Python tarafında `smart_coupon_service.py` (CLI) işbirliği ile çalışır.
### Akış
1. **Request:** POST `/api/coupon/analyze-match` { matchId }
2. **Pre-Check 1 (Kadro):** DB'de kadro var mı?
- Yoksa -> `FeederService.refreshMatch(lineups)` -> Tekrar kontrol -> Hâlâ yoksa Hata Fırlat ("Yetersiz Veri").
3. **Pre-Check 2 (Oran):** DB'de oran var mı?
- Yoksa -> `FeederService.refreshMatch(odds)` -> Log bas (Engelleyici değil).
4. **Prediction:** Python scripti çalıştırılır (`--analyze --json`).
- Script: DB veya JSON Fallback'ten veriyi okur.
- Script: Modeli çalıştırır, kalibrasyon katsayılarını uygular.
- Script: JSON döner.
5. **Response:** NestJS JSON'ı parse edip kullanıcıya döner.
---
## Gelecek İçin Notlar
- **Database:** `live_matches` tablosundaki JSON kolonları artık kritik öneme sahip. Bunların şeması `Prisma` tarafında `Json` olarak tanımlı ama iç yapısı kod içinde (`FeederPersistence`) belirleniyor. Yapıyı değiştirirken dikkatli olunmalı.
- **Model:** V17 modeli şu an stabil. V18'e geçilirse `player_model_v17.py` değiştirilmeli ve `smart_coupon_service.py` içindeki scale faktörleri sıfırlanıp tekrar backtest yapılmalı.