---
name: delor-sport-dashscope-lessons
description: "Делор спорт — LLM-обучение (постмортем/подкрепление) на DashScope + (с 2026-07-13) сам анализ тоже одна модель DashScope вместо консенсус-панели. ВАЖНО: DashScope-таймауты (запись 4) + баг ложного сеттлинга по 0:0/недоигранному счёту кормивший уроки фейковыми результатами — тай-гейт commit c69ab64 (запись 5) НЕ покрыл всё, live-check v0.27 (запись 6) НЕ покрыл всё, добит v0.28 (запись 7, третий статус 'finished' — до этого генуинно завершённые матчи молча выпадали из сеттла обратно в 'prematch') — сверь перед тем как полагаться на sport_lessons как на работающее. ТАКЖЕ (запись 8): пики перекошены в низкий риск/простые рынки (исходы/фора/тотал) — частично баг (гейт «упоминание команды» резал падежи, commit b101915), частично by-design (гейт уверенности + бедный грундинг под нишевые рынки). Запись 9: on-demand Q3 deep-review (не анализ, не консенсус) переведён на research/chatgpt через CebersResearch вместо мёртвого cerebras, commit ac3f5e0. Запись 10 (commit cffd21a): распространено и на фон (sport_deep_review_background=True) — Q3 срабатывает лишь на уже выживших пиках (~4/день системно), не по всем матчам тика, риск для браузерной сессии низкий"
metadata: 
  node_type: memory
  type: project
  originSessionId: 6620ea3d-79ed-46e4-b5ea-65828f0cc0b8
---

Делор, commit ceb4eb9 (2026-07-12): спорт-советник получил качественный слой самообучения — зеркало `cryptopilot/feedback/learn.py`, но **только на моделях DashScope** (по требованию владельца).

**Что уже было (не дублировано):** `pick_insights.py` — бесплатный статистический слой (hit-rate/ROI по срезам, гейт Уилсона n≥10) — эквивалент `outcome_miner.py` CryptoPilot.

**Что добавлено:** `advisor/domain/sport/lessons.py::postmortem_pick`(LOSS)/`reinforce_pick`(WIN) — LLM разбирает ОДИН сеттленный пик, извлекает короткое условное правило (тот же квалити-гейт: обязательны условие/число), кладёт в `sport_lessons`. Ретрив (0 LLM) подмешивается в промпт консенсуса рядом с `build_insights_block`. **НЕ голос консенсуса** — независимость/кворум не тронуты (правило [[sport-reliability-quality-pref]]).

**Модели — изолированная DashScope-цепочка** (primary+fallback ВНУТРИ одного провайдера, никакого выхода на другие): `dashscope/glm-5.2-fast-preview` + `dashscope/qwen3.7-max-2026-06-08` — та же пара уже в проде investpilot. Конфиг: `sport_llm_lesson_enabled/_model/_fallback`, `sport_lesson_max_per_tick=5`.

**Вызывается из `results_ledger.settle_pending`** (теперь **async** — попутно найден и исправлен старый баг: `run_cleanup_tick` вызывался без `await`). Best-effort, не блокирует сеттл остальных пиков.

**Заодно вернул спорт в прод** (см. [[delor-chat-only-mode]]) — `sport_collector_enabled=True` + launchd delor-sport enable/bootstrap; UI (кнопка «⚽ Спорт») возвращён точечно в chat-only.

**Проверено:** 1105 тестов (+12); живой DashScope-вызов дал реальное правило («не ставить ТБ2.5 в матчах топ-6 АПЛ при разрыве ≤5 очков»); прод рестарт — 9 циклов, коллектор 2297 матчей; tg-web-e2e (/moex тихо, кнопка Спорт живой обзор, чат отвечает).

Детали, найденный баг регистрации роутера, отвергнутые варианты — Obsidian Projects/Делор Changelog+Decisions `D-sport-dashscope-lessons`.

---

**2026-07-13, commit 25ad82d — консенсус-панель самого АНАЛИЗА тоже снесена (не только уроки).** Жалоба «Делор не присылал матчи» вскрыла: последний пик/уведомление — `2026-06-21`, три недели тишины, никак не связано с прошлым коммитом. Корень — консенсус-панель `analyze_match_consensus` (`>=2/6` голосов) держалась на мёртвых провайдерах: `cerebras/*` (RU-бан IP мини, см. [[cerebras-groq-ru-ban]]) + `fmd/gpt-5.4` (404, нет credentials в OmniRoute). Кворум не набирался почти никогда.

**Владелец решил снести консенсус СОВСЕМ** (не чинить голоса) — теперь `analyze_match_consensus` тоже одна модель + фолбэк, **та же DashScope-пара**, что и у контура обучения выше (`sport_llm_model`/`sport_llm_model_fallback`, отдельные от `sport_llm_lesson_model`/`_fallback`, хоть и совпадают значениями). Качество держат прежние детерминированные гейты (`bad_slices` теперь режет безусловно, без голосового эскейп-хетча) + faithfulness/coherence verify_llm + Q3 deep-reviewer — они и раньше не зависели от подсчёта голосов.

**Отменяет старое правило** [[sport-reliability-quality-pref]] «консенсус ≥2/4 не ослаблять» — правило обновлено под новую архитектуру. **Побочно снесено как осиротевшее** (grep подтвердил — использовалось ТОЛЬКО панелью): `models/atessa.py`, `models/risky_guard.py` (см. [[risky-llm-provider-isolation]] — статус обновлён), `models/cebers_research.py` (план ошибочно думал, что нужен ещё KB — неверно).

**Проверено:** 1065 тестов; живой смоук 3 реальных матча — DashScope ответил на всех; прод рестарт — первый боевой тик дал `picks=1` (три недели было 0), новый пик реально ушёл push-уведомлением ОБОИМ подписчикам за секунды; tg-web-e2e Спорт живой + чат отвечает. Детали — Obsidian Decisions `D-sport-single-model`.

---

**2026-07-13 (2), commit a3e74a0 — любительские лиги (Setka Cup/TT Cup/Лига Про) вернулись в фон**, отдельно от смены модели выше — см. [[delor-sport-amateur-leagues-h2h]] (новый источник грандинга: собственная H2H-статистика вместо веб-поиска, с честным гейтом на объём данных; сама модель-анализатор не менялась).

**2026-07-13 (3), commit 56965c8 — учебный контур (postmortem/reinforce) наконец ВИДЕН пользователю.** До этого коммита `settle_pending` вызывал уроки, но результат отбрасывался молча. Теперь результат+урок уходят в TG — см. [[delor-sport-outcome-notify]] (доставка через БД-очередь, не напрямую, т.к. settle_pending живёт в процессе без доступа к Bot).

**2026-07-13 (4), commit efbf398 — ВАЖНАЯ КОРРЕКЦИЯ: контур в проде реально НЕ производил уроков.** Когда уведомления сделали видимыми, вскрылось: `sport_lessons` — 0 строк, ОБА реальных win/loss с 12 июля провалили LLM-вызов («sport postmortem LLM failed»). Живой DashScope-вызов из проверки коммита ceb4eb9 (выше, «дал реальное правило») был ручным/изолированным смоуком в момент низкой нагрузки — НЕ репрезентативен для боевого поведения. Причина — `metrics.db` показал провалы `dashscope/glm-5.2-fast-preview`/`qwen3.7-max` кластерящиеся у старого потолка `OmniRouteClient(timeout_seconds=60.0)`. Поднят до 120с (только `sport_analyst.py`, фон) — живая повторная проверка честно показала неполный эффект (один прогон — обе модели протаймаутили и на 120с). Владелец решил не копать глубже; 120с как есть, без гарантии что `sport_lessons` начнёт наполняться. Детали — Decisions `D-dashscope-postmortem-timeout`.

**2026-07-13 (5), commit c69ab64 — ВТОРАЯ КОРРЕКЦИЯ: даже те немногие «уроки», что доходили, часто рождались из ФЕЙКОВЫХ убытков.** Владелец прислал скрин: постмортем засчитал ATP Challenger квали как ❌ 0:0, хотя матч ещё не закончился. Корень — `results_ledger.pending_picks_to_settle` считал матч «завершённым» по пропаже из live-ленты Fonbet (нет настоящего статуса finished), беря последний известный счёт без проверки правдоподобия. Аудит: 25/69 (36%) сеттленных пиков имели буквально «0:0», включая физически невозможные для баскетбола/тенниса. Фикс — гейт `_plausible_final_score` (виды без ничьей — тай никогда не финал; виды с ничьей — не раньше 45 мин от старта), плюс пересчёт: 29 испорченных строк → 26 в `void`, 3 в `pending`, 1 мусорный `sport_lessons` деактивирован. **hit-rate в UI подскочил с 36% до 72%** — реальная эффективность советника была занижена багом сеттлинга, а не слаба сама по себе. Детали — Decisions `D-sport-settle-tie-gate`.

**2026-07-13 (6), v0.27 — ТРЕТЬЯ КОРРЕКЦИЯ: тай-гейт не покрывал НЕ-ничейные недоигранные счета.** Владелец сообщил: снова взял в обучение незакончившийся матч (теннис «Крюгер vs Мартинес», «win» по «1:0» — только один сет). Живой прямой запрос к Fonbet в момент разбора подтвердил `place: "live"`, второй сет шёл (6-2 5-4) — тай-гейт не спасал, т.к. счёт не ничейный. Явный запрос владельца: не очередная эвристика, а реальные данные о завершении. Фикс — `FonbetCollector.check_still_live()`: прямой per-match запрос (не урезанная bulk-лента) перед КАЖДЫМ сеттлом; live-подтверждение → не сеттлим и обновляем счёт; confirmed-gone → сеттлим; проверка целиком упала (протухшие cookies) → тоже НЕ сеттлим (честная неопределённость, не откат на старую эвристику). Детали — Decisions `D-sport-settle-live-check`.

**2026-07-13 (7), v0.28 — ЧЕТВЁРТАЯ КОРРЕКЦИЯ: генуинно завершённые матчи молча выпадали из сеттла обратно в «prematch».** Отдельный риск, найденный (не жалобой, а разбором предыдущего фикса): `fonbet_parser.parse_events` классифицировал статус бинарно (`live` vs всё остальное → `prematch`), а `pending_picks_to_settle` требует `status='live'` для кандидата на сеттл. Как только Fonbet переставал слать `place=live` у завершившегося матча, статус в БД слетал на `prematch`, и пик оставался только с 48ч void-таймаутом — теряя реальный результат/урок. Живой монитор (~10 идущих матчей, прямой запрос каждые 40с) поймал реальную транзакцию: `place: "live"` → `place: "notActive"` ровно в момент завершения (Fonbet не использует отдельное значение «finished»). Фикс — третий статус `"finished"` при `place=='notActive'`; `pending_picks_to_settle`/`shadow_pending_to_settle` сеттлят `finished` сразу, без эвристики. Прод-проверка: 3 матча со `status='finished'` в БД сразу после рестарта. Детали — Decisions `D-sport-settle-finished-status`.

**2026-07-14 (8), commit b101915 — перекос пиков в низкий риск/простые рынки: найден и починен один реальный баг, но не вся картина.** Владелец заметил: советует почти только low-риск и почти только исходы/фору/тотал; включённое накануне уведомление на mid ни разу не сработало. Разбор (по запросу «разберись глубже», не по жалобе): живой прогон продового payload+модели на реальном матче (Англия–Аргентина) поймал легитимный, честно процитированный пик, выброшенный ДО faithfulness/coherence — гейтом G19 (`_is_quality_sport_pick`, `no_team_name`). Причина: точное сравнение токенов, а reasoning модели упоминал команду в родительном падеже («статистике Англии») против именительного в данных матча («Англия») — разные строки. Фикс: `_team_name_mentioned()` — точное совпадение + fallback на общий 4-символьный префикс токена (терпит падежи, не путает разные команды). **НЕ полное объяснение:** основной перекос — by-design следствие гейта уверенности (нужна цитата факта) + бедного грундинга под нишевые рынки (угловые/карточки/точный счёт) — эта часть НЕ тронута, осознанный trade-off «качество > объём», не баг. Детали — Decisions `D-sport-team-name-stem-match`.

**2026-07-14 (9), commit ac3f5e0 — on-demand Q3 deep-review переведён на ChatGPT (CebersResearch) вместо мёртвого cerebras.** Владелец спросил, может ли живая браузерная сессия ChatGPT в CebersResearch (`research/chatgpt`) быть полезна спорт-анализу — явно БЕЗ возврата снесённой консенсус-панели. Найден готовый слот под именно такую роль: Q3 deep-reviewer (`_deep_review_picks`) — один вызов на КАЖДЫЙ уже выживший пик, keep/reject+полировка, fail-open — терпит хрупкую браузерную сессию (редко, не по всем матчам, падение не критично). Побочно найден баг: on-demand primary (`sport_llm_deep_reviewer=cerebras/zai-glm-4.7`) — мёртвый провайдер (RU-бан), каждый тап «🧠 Свежий анализ» тихо проваливался на `nvidia/llama` fallback. Технический нюанс: OmniRoute не знает про `research/*` модели, просто сменить конфиг было нельзя — понадобился новый класс `ResearchGatewayLLM` (прямой HTTP на `:20130`, тот же интерфейс, что `AdvisorLLM`, кидает `AdvisorLLMError` → fallback в `ChainAdvisorLLM` работает без изменений). Скоуп сознательно ограничен on-demand путём (`handlers.py`) — фон (`analyze_top_n`, и так `sport_deep_review_background=False`) не тронут. Живой прогон на реальном матче подтвердил: `research/chatgpt` реально вызывается, JSON парсится, `deep_reviewed=True`. Детали — Decisions `D-sport-chatgpt-deep-review`.

**2026-07-14 (10), commit cffd21a — фон тоже переведён на research/chatgpt, sport_deep_review_background включён.** Прямое продолжение записи (9): владелец сразу попросил распространить на фон. Пересмотр: изначальное опасение «объём вызовов другой порядок» относилось к частоте ПЕРВИЧНОГО анализа (~20 матчей/10 мин), а Q3-ревью вызывается только на УЖЕ выживших пиках — по `sport_cli stats` это ~4/день системно, не по каждому матчу тика — так что риск для хрупкой браузерной сессии низкий. `sport_deep_review_background: False → True`; старая причина выключения (COST — премиум gpt-5.5 на весь тик) больше не применима (меньше вызовов + ChatGPT по подписке, не токен-метраж). `sport_llm_deep_reviewer` (мёртвый cerebras) теперь не читается нигде — оставлен как health-check слот в `llm_health.py`, известный безвредный хвост. **Честная оговорка по проверке:** живой прогон `analyze_top_n` на 9 реальных матчах подтвердил, что конфиг подхватился и конструкция не падает, но ни один матч не дал выжившего пика — реальный вызов ChatGPT ИЗ ФОНОВОГО пути напрямую не пойман (частота ~4/день), полагаемся на уже доказанный on-demand механизм (запись 9). Детали — Decisions `D-sport-chatgpt-deep-review` (расширенная запись).
