---
name: investpilot-cebersresearch-voter
description: "КодИнвест — voter скана на бесплатный research/gemini-flash (CebersResearch :20130, отдельная шина), codex только челленджер; разгрузка codex-очереди"
metadata:
  node_type: memory
  type: project
  originSessionId: 6f344612-b945-4107-b457-8ad2163cd988
  modified: 2026-07-21T06:48:26.024Z
---

**КодИнвест ([[investpilot-overview]]) — voter через CebersResearch, 2026-07-14.** Задача «упростить codex жизнь»: под сканом codex ловил TimeoutError (до 12 послед. voter-вызовов/скан через codex-очередь OmniRoute, сериализуется + общая с Делор/Крипто/Автеро).

**Решение:** voter скана → `research/gemini-flash` через [[cebersresearch-overview]] (`:20130`, OpenAI-совместимый, токен=`OMNIROUTE_API_KEY` — уже держим). Модели `research/*` на ОТДЕЛЬНОЙ шине, НЕ codex-очередь. Router: ветка `research/*`→:20130 (`research_base_url` в build_app); env `INVESTPILOT_RESEARCH_BASE_URL=http://127.0.0.1:20130`.

**Замер (реальные ~7КБ досье, боевой ANALYST_SYSTEM):** gemini-flash 3.7–5.2с, всегда валидный JSON. **gigachat ОТКАЗЫВАЕТСЯ давать финвердикт** (гардрейлы Сбера) — не voter. deepseek флапает пустым.

**Цепочки разведены** (`config.challenger_chain` переписан, +`llm_challenger`/`llm_challenger_fallbacks`):
- voter: `gemini-flash→glm-5.2-fast→nim-llama→grok-build→codex`(хвост)
- челленджер: `codex→grok-build→gemini-flash→glm-fast` — codex там, где дорога ошибка отклонения сделки.
→ codex с ~12 до ~0–3 вызовов/скан. Обратимо через config/env (вернуть = `llm_primary=codex/gpt-5.5-low`).

Живой прогон NVTK → `Голоса: ['research/gemini-flash']`, разбор SHORT conf75→гейт<80→WAIT. 160 pytest. Замер: `scripts/measure_research_voter.py`.

**Способ 2 (сделан в тот же день):** новостной фон через `/v1/search`. `research_snippets` (`analysis/research.py`) был подключён в досье (`web_research`), но МОЛЧАЛ без `research_base_url` (тот же env включил). Баг маппинга: читал `body/source/date`, а `/v1/search` отдаёт `title/url/snippet` → сниппеты терялись; починил (snippet из snippet, source из домена). `build_dossier(SBER)`→web_research 6 элементов со сниппетами. RSS-спам finam/1prime: режут дефолтный aiohttp-UA → браузерный UA + WARNING→debug (`news.py`). Ключ research = OMNIROUTE_API_KEY; в проде приходит через start.sh (sources omniroute.env), НЕ через .env.

Дневной стоп «80%» — НЕ баг: строка из `logs/e2e_risk.log` (тест), живой якорь здоров.

**«Флап» gemini = ПАРСЕР, не модель (14.07).** Скан: codex НЕ таймаутит ✅, но gemini давал не-JSON ~4/8. Причина: `json.loads` strict=True отвергал сырые `\n`/`\t` внутри строк (модель кладёт многострочный текст в why/risks) → «Invalid control character». Фикс: `parse_json_object` (`llm/router.py`) → `strict=False` обе ветки → gemini **8/8 JSON**, ~5с. Модель НЕ меняли. Бенч: glm-5.2-fast под полным досье реально **24–34с** (не 5с) → первым voter не годится. Тест `tests/test_parse_json.py`. 164 pytest.

**codex убран из ВСЕХ цепочек, Notion подключён хвостом (20.07).** Владелец: «codex можно убрать, notion туда подключи». codex-квота была исчерпана на ~24.5 дня. Перед подключением Notion — проверка (не поверил памяти): `notion-web2api` :1722 healthz?deep=1 → `cookie_error`, реальный инференс `temporarily-unavailable` на всех 4 воркспейсах (сейчас реально лежит) + память ([[notion_web2api_overview]]) документирует отказ Notion соблюдать «отвечай ТОЛЬКО JSON» (Делор-прецедент). Вывод: Notion (`research/notion-opus`) НЕ primary, только ХВОСТ фолбэков (безопасно — недоступен/не-JSON → просто пропуск). Новый **primary челленджера — `dashscope/glm-5.2-fast-preview`** (не codex, не grok — независим от voter=gemini-flash и от общих точек отказа codex-квота/grok-cli-auth). Живая проверка: чистый JSON с 1-й попытки, содержательный вердикт (поймал противоречие в дивидендных полях, сослался на track_record). 197 pytest.

**Notion сняли → вернули в ту же ночь (20.07).** Владелец сначала сказал «закрыли AI-направление» → сняли хвост-звенья. Час спустя владелец восстановил доступ → перепроверка (`:1722/healthz?deep=1` реальный `probe:OK`, живой тест на боевом промпте челленджера — оба notion-opus/notion-fable5 дали чистый JSON, прецедент Делора не воспроизвёлся) → `research/notion-opus` возвращён хвостом в те же 4 цепочки. Codex по-прежнему нигде. Урок: статус внешних AI-провайдеров ЛЕТУЧ — не полагаться на память, перепроверять `:1722/healthz?deep=1` при любом сомнении, а не доверять последнему известному статусу.

**Челленджер был МЁРТВ — починен (15.07, D31).** Аудит: 0 пушей за историю, 12/12 отказов «скептик отклонил без причины». Причина: [[codex-bus-system-prompt-gotcha]] — codex-шина игнорит system-JSON, эссе вместо JSON; `_challenge` без ретрая глушил всё. Фикс: схема в user-промпт + ретрай + фолбэк по цепочке + валидация `verdict` + различимые причины (парс-фейл ≠ reject ≠ недоступна). Fail-closed сохранён. Верифицирован живым `scripts/challenger_probe.py --fix` (codex JSON с 1-й попытки, отклонил слабый синтетический LONG аргументированно). Тесты `tests/test_challenger.py`, 173 pytest. Следствие: до 15.07 «бот молчит» ≠ «гейты строгие».
