# 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ı.