dr-fanout · diff

git:20260814.44e61cf to git:20260814.5023d8c

6 added, 1 removed. Audit B to B.

---
name: dr-fanout
- description: "Одна команда — разнести Deep Research промпт сразу по нескольким внешним LLM (ChatGPT / Gemini / Grok) через залогиненный браузер Антона (гибрид: Grok=живой Chrome-MCP, Gemini/ChatGPT=Chrome сейчас / выделенный Firefox-профиль для безлюдного расписания — фундамент Firefox-first, Decision Memo 2026-07-16), потом самому забрать отчёты, сохранить в _originals и сделать синтез-консенсус. Автоматизация финала Alpha Protocol (R+DR): раньше Антон руками вставлял промпт в 3 сайта и руками приносил результаты. Триггеры: /dr-fanout, «разнеси ДР», «разошли дипресёрч», «запусти DR в трёх», «fan out the DR», «раздай промпт по LLM», а также САМ после шага 3 Альфа-протокола (мандат Антона 2026-07-14: любое количество DR без спроса — квоты не экономим, деградация ChatGPT мягкая, 3-вендорный веер компенсирует; дубли ловит дедуп Шага 0). Подписки Антона (не платные API), браузер строго локально на этой машине."
+ description: >
+ One command to fan a Deep Research prompt out to several external LLMs at once (ChatGPT /
+ Gemini / Grok / others) through the operator's logged-in browser, then collect the reports,
+ archive the originals, and synthesize a consensus. Trigger on "/dr-fanout", "fan out the DR",
+ "distribute the research prompt". Automates the final stage of the Alpha Protocol: no more
+ hand-pasting one prompt into N sites.
license: MIT
---
# /dr-fanout — раздать Deep Research по 3+ LLM и собрать консенсус
> Финал Alpha Protocol на автомате. Каналы: **ChatGPT** (chatgpt.com) · **Gemini** (gemini.google.com) · **Grok** (grok.com). Механика = Claude-in-Chrome MCP (живой залогиненный Chrome Антона). Канон: [[alpha-protocol-recall-plus-dr]], decision-multi-llm-vendor-independence (гетеро-консенсус), [[chrome-autonomy-self-drive]], [[browser-work-on-peers-not-hub]] (строго локально).
## ⭐ Что уже решено (фундамент, не переисследовать) — обновлено 2026-07-16
1. **Браузерный слой = Firefox-first** (Decision Memo `02-Decisions/decision-2026-07-16-browser-automation-layer.md`, DR26-07-16-HUB-01, уверенность high). Chrome 127+ шифрует куки (ABE) и с апреля 2026 привязывает сессии к железу (DBSC) → внешнее извлечение куки невозможно без malware-техник. **Firefox куки открыты** (plaintext SQLite, DBSC не реализует) → выделенный per-service Firefox-профиль + Playwright `launch_persistent_context`; Chrome CDP-attach только как fallback для строго-Chromium сайтов. Хаб-стек уже поднят: `firefox_cookies.py` (`~/.claude/scripts/_shared/`), профили `D:\AutomationBrowsers\Firefox\`.
2. **Живой Chrome-MCP (Claude-in-Chrome) остаётся осознанным anti-ban путём** для действий «как человек в реальном сеансе» (fb-post/x-post едут так). Для dr-fanout выбор пути исполнения (живой Chrome-MCP vs headless Firefox-Playwright) уточняется идущим DR (см. п.4).
3. **CLI-обход НЕ даёт Deep Research по подписке** (проверено 15.07): Codex CLI / Gemini CLI = только web search; настоящий Deep Research потребительской подписки программно не дёргается (Google DR-агент = платный API отдельно). ⇒ браузерная веб-морда — единственная дорога к DR по подпискам, значит делаем её анти-хрупкой, а не бежим от неё.
4. **ToS-риск, острее всего у Grok:** xAI AUP прямо запрещает автоматический/не-человеческий доступ (риск suspension/termination). Задокументированных банов за автоматизацию СВОЕГО аккаунта нет, но текст явный → Grok-канал гнать в человеческом темпе; решение «оставить/притормозить/заменить на Claude.ai» — за Антоном.
5. **Grok — просто продолжаем использовать** (решение Антона 2026-07-16). xAI AUP формально запрещает автоматизацию, но охота идёт за масс-скрейпингом (штраф $15k/1M запросов), а наш темп естественно крошечный (несколько DR в день максимум) → мы не мишень. Ценность третьего независимого голоса > управляемого риска. НЕ городить лимиты/троттлинг ([[ak47-simplicity]]) — Grok в обычной ротации; если сам вендор упрётся (капча/challenge) — доложить и пропустить этот канал, без драмы.
6. **Путь исполнения — ГИБРИДНЫЙ, под каждого вендора свой** (решение Антона 2026-07-16, «и так и так»). Не один способ на всех:
| Вендор | Путь | Почему |
|---|---|---|
| **Grok** | живой Chrome-MCP, человеческий темп | ToS-чувствителен → действуем как человек в реальном сеансе (макс anti-ban, как fb-post [[chrome-autonomy-self-drive]]); headless-бот тут = максимум риска |
| **ChatGPT** | выделенный Firefox-профиль headless (безлюдно) ИЛИ живой Chrome-MCP | ToS мягче; извлечение отчёта = backend JSON (работает в обоих); для расписания без человека → Firefox |
| **Gemini** | выделенный Firefox-профиль headless (безлюдно) | двухфазный (план→Start research), терпим к автоматизации; кандидат №1 на полностью безлюдный прогон |
Принцип: чем жёстче ToS/бан-чувствительность вендора → тем ближе к «живой человек в сеансе» (Chrome-MCP); чем терпимее + важнее безлюдность → тем ближе к выделенному Firefox-профилю (Playwright persistent, фундамент HUB-01).
7. **✅ Оркестрация — ПОДТВЕРЖДЕНА внешним DR** (`DR26-07-14-FLEE-01`, синтез ChatGPT+Grok 2026-07-16, выжимка `03-Insights/insight-DR-DR26-07-14-FLEE-01-*`). Оба вендора независимо: ядро = **durable state-machine + job-ledger, НЕ «долгоживущий автономный браузер-агент»**; локальный ledger-FSM достаточен для одно-хозяйного хаба. Оба независимо советуют **НЕ строить безлюдную Grok-автоматизацию** (xAI AUP + enforcement реален: >52k банов в 2026, Reuters 15.07) → наша матрица п.6 уже это соблюдает (Grok только живой Chrome-MCP, никогда в демоне). **Безлюдное расписание стартуем с 2 вендоров: ChatGPT + Gemini.**
8. **Вендор-логику держать ТОНКОЙ, оркестрацию — общей.** UI-специфичные репо мрут быстро (`chatgpt-automation-mcp` архив 27.04.2026, `browserbase/gemini-browser` архив 20.05.2026). Всё вендор-специфичное = сменные «адаптеры» внизу; автомат/ledger сверху не меняется.
9. **⚠️ ОТКРЫТО — официальный путь для Gemini:** Deep Research Agent / **Interactions API** (`background=True` + polling, collaborative_planning) — production-ready, снимает самый хрупкий и медленный браузерный канал. НО ⚠️ УСЛОЖНЕНИЕ + неясен биллинг: входит ли в подписку Ultra или это отдельные деньги (ChatGPT-отчёт: «НЕ то же free-with-subscription»). **Проверить биллинг ДО стройки** ([[prefer-included-limits-before-paid-api]]) — если платный, не заводить без «+» Антона.
## Жёсткие рамки (читать первыми)
1. **⭐ Мандат Антона (2026-07-14, supersedes квота-гейт 05.07): любое количество DR, БЕЗ спроса.** «Делай любое количество депрезёрчей, не спрашивай меня, не беспокойся по поводу лимитов» — ChatGPT при выжатой квоте деградирует мягко (лайтовее отчёт, не отказ), гетеро-веер на 3 вендора компенсирует. Запускаю сам, докладываю постфактум. Единственное «но»: не жечь квоту на ДУБЛИ — дедуп-проверка Шага 0 обязательна.
2. **Браузер строго локально** на машине, где идёт сессия. Ничего не просить у других машин.
3. **Аккаунты Антона:** если сайт разлогинен → логин по [[social-auth-autonomous]] (креды в store); CAPTCHA/2FA-стена → позвать Антона одной фразой + скриншот.
4. **Ничего не отправляем КРОМЕ промпта** в композер DR. Не трогать другие чаты/настройки.
5. **ANTI-RECENTS при забО́ре отчёта:** ища готовый DR-чат/отчёт в веб-UI (ChatGPT/Gemini/Grok), НЕ заключай «отчёта нет» из беглого списка recents — используй встроенный ПОИСК по ключам/ID + Projects/архив + подтверди активный аккаунт по email. Сперва реестр (`_DR-Registry.md`, Шаг 0), потом UI-поиск, и только потом вывод «нет». Канон: память [[web-ui-search-not-recents]] (инцидент Woom 2026-07-23).
## Шаг 0 — вход
⭐ **ДЕДУП ПЕРЕД КВОТОЙ (anton 2026-07-14):** прежде чем жечь DR-квоты — проверь, не готов ли отчёт уже. (1) Есть ID в промпте → его строка в реестре: `grep "<DR-ID>" "$OBSIDIAN_VAULT/_DR-Registry.md"` — статус `collected`/`synthesized` = СТОП, fan-out не нужен: доложи «уже собран», покажи файлы (`_originals\deep-research\*<DR-ID>*`, `03-Insights\insight-DR-<id>*`), иди в Шаг 4 (синтез). (2) ID нет → grep реестра по ключевым словам темы: та же тема в `issued` → переиспользуй ТОТ ID; в `collected+` → покажи готовое, спроси, нужен ли вообще новый прогон. Ночной `dr_collect.py` (хаб 05:05) флипает статусы по экспортам сам — реестр свежее памяти сессии.
⭐ Номер DR обязателен (anton 2026-07-03): если у промпта ещё нет ID `DRYY-MM-DD-МАШИНА-NN` — выделить: `python $IMPORTS_ROOT/dr_registry.py new "<тема>" --tool chatgpt,gemini,grok` и поставить ID первой строкой промпта (`# DR26-07-03-ZB-01 — <тема>`). Код машины скрипт определяет сам (своя очередь у каждого компа — дублей при синке нет). Канон: `reglament-numeratsiya-dr-i-reestr`.
Промпт берём: из текущего чата (только что сэмитили по Альфе) / из файла, что укажет Антон. «+» НЕ спрашиваем (мандат 14.07) — объявляю строкой `🚀 DR-fanout: разношу <ID> в ChatGPT+Gemini+Grok` и еду.
## Шаг 0.5 — тюнинг промпта под вендоров (обязательно)
Перед раздачей приклеить к телу промпта: `§1 УНИВЕРСАЛЬНЫЙ ADD-ON` из [[dr-platform-playbook]] (`08-Templates\dr-platform-playbook.md`) — всегда, всем; **плюс платформенный блок §2 (Grok) / §3 (Gemini) / §4 (ChatGPT)** под каждого конкретного вендора. Тело (из `deep-research-prompt-template.md`) + §1 одинаковы у всех; платформенный блок различается НАМЕРЕННО (играет на сильную сторону: Grok=реалтайм/X+жёсткие цитаты, Gemini=правка плана/официоз/глубина). ID `DRYY-MM-DD-МАШИНА-NN` первой строкой у всех.
## Шаги 1-3 — АВТОМАТ submit → probe → collect (per vendor)
> Ядро надёжности v2, ✅ подтверждено внешним DR (см. п.7). Каждый вендор проходит автомат независимо; сломался на шаге — падает В ФОЛБЭК того шага, не роняя остальных. Золотое правило: **probe перед burn** — ни одна DR-квота не тратится, пока не доказано: (а) режим включён, (б) промпт целиком, (в) ран стартовал.
>
> **Состояния** (ledger = `_drafts/DR-FANOUT-<DR-ID>-*.md`, ключ = DR-ID → resume идемпотентен): `staged → mode_verified → submitted → started → waiting → ready → collected → delivered`. Аварийные: `needs_reauth` · `drift_suspected` · `probe_failed` · `aborted`. ⭐ **Человеко-гейта ровно два — `needs_reauth` и `drift_suspected`; всё остальное безлюдно** (консенсус DR).
> **Локаторы:** ARIA/role первыми → CSS → и только затем LLM/vision. ⛔ Семантический/LLM-поиск элемента — ТОЛЬКО в dry-run/repair-режиме, НИКОГДА на квота-сабмите (консенсус DR).
Инструменты одним ToolSearch: `tabs_context, navigate, computer, read_page, tabs_create, form_input, get_page_text, read_console_messages`.
### СОСТОЯНИЕ 1 — SUBMIT (включить DR-режим + вставить промпт)
Новая вкладка → дождаться загрузки → залогинен? (нет → [[social-auth-autonomous]]; стена 2FA/CAPTCHA → скриншот + пропустить вендора). Затем **найти DR-режим ГЛЯДЯ на страницу** (не по памяти — UI плывёт у всех троих):
- **ChatGPT** (аккаунт owner.**a2**@gmail.com): сперва селектор модели → **Pro, максимальная** (сейчас GPT-5.6) + максимальный уровень думания; затем композер → меню инструментов («+»/«Tools») → «Deep research». ⭐ anton 21.07: всегда самая умная модель, имя меняется — принцип нет.
- **Gemini** (аккаунт owner.**a**@gmail.com, личный): модель = **Pro** (сейчас 3.1), ⛔ НЕ Flash (тихо откатывается — проверять!); включить **Extended thinking** (галочка справа возле микрофона); «+» → «Deep Research» → промпт → Enter → план → **дожать OK/Start**.
- **Grok** (аккаунт owner.vendor@example.com — там же Twitter Антона): ⭐ anton 21.07 — режим **Heavy** ДЕФОЛТ (куплена максимальная подписка; supersedes прежнее «Expert, Heavy не трогать»). Отдельной DR-кнопки нет → в тело промпта добавить строку «Search the web extensively and cite sources»; следить, чтобы селектор не свалился в Expert/Fast (тихий деграде ZB-03 20.07). Методика «DR-grade в Grok Heavy» (собрано 21.07, DR26-07-21-HUB-02): **Heavy сам и есть Deep Research** — рой 8–16 суб-агентов, ищут параллельно и спорят; Expert теперь одноагентный и для citation-heavy слабее; DeepSearch/DeeperSearch убраны и растворены в Heavy. Без принуждения Heavy отвечает из памяти → в промпт обязательно: «search the web and X extensively» + 15–25 первичных источников + короткая цитата и точный URL на каждое утверждение + «cite ONLY URLs you actually opened» + финальный проход верификации. Доказательство настоящего прогона: «Thought for» в минутах + счётчик «N sources»; мгновенный ответ без источников = деграде, перезапуск. Квоты = недельный общий пул (Settings → Usage, в процентах), контекст 256k–500k, прогон 5–20+ мин. Экспорта одной кнопкой нет (выделить-скопировать); Share = ПУБЛИЧНАЯ ссылка ⛔. Полный шаблон промпта — в `_originals\deep-research\DR26-07-21-HUB-02-grok-heavy-playbook-grok.md`, раздел «(b) Reusable Prompt TEMPLATE»; синтез — `insight-DR-DR26-07-21-HUB-02-grok-heavy-as-a-deep-research-engine`.
- Вставка промпта — ТОЛЬКО через JS, НИКОГДА `computer type` (каждый Enter = отправка, улетит обрезок, квота сгорит). ⭐ **Каскад `paste_verify.js`** (рядом со скиллом, от Mac16 07-16, лечит брак 07-10 «execCommand не сел»; форевер-фикс Grok-ProseMirror 07-17 FLEE-03): прочитать файл `~/.claude/skills/dr-fanout/paste_verify.js`, выполнить его тело через `javascript_tool`, затем `window.__drPasteVerify(PROMPT, "chatgpt"|"gemini"|"grok")`. Он сам перебирает методы (⭐ **синтетический paste-event для ProseMirror/TipTap** → execCommand → нативный React-сеттер textarea → node-параграфы Quill/CE → directSet), сверяет length+head+tail после КАЖДОГО (для ProseMirror читает `el.innerText`, а НЕ textarea-зеркало) и возвращает `{ok, method, gotLen, wantLen, isPM, ...}`.
- ⚠️ **Grok 4.5 = TipTap/ProseMirror contenteditable** (`div.tiptap.ProseMirror`), а видимый `<textarea>` — это СКРЫТОЕ ЗЕРКАЛО: заполнение textarea (nativeSetter) даёт `ok:true`, но форма/React из зеркала НЕ обновляются → Submit-кнопка не рендерится, Enter=no-op, ран не стартует. **Настоящий редактор надо заполнять синтетическим paste-event** (`ClipboardEvent('paste',{clipboardData:DataTransfer})`) → ProseMirror штатно адоптит текст → `button[type="submit"]` появляется enabled → клик. Каскад теперь целит ProseMirror ПЕРВЫМ и делает это сам; textarea оставлен последним фолбэком.
- Ручной фолбэк (если ассет недоступен): для Grok/ChatGPT — `const ed=document.querySelector('.tiptap.ProseMirror')||document.querySelector('.ProseMirror'); ed.focus(); window.getSelection().selectAllChildren(ed); const dt=new DataTransfer(); dt.setData('text/plain',PROMPT); ed.dispatchEvent(new ClipboardEvent('paste',{clipboardData:dt,bubbles:true,cancelable:true}))`; Gemini (Quill+TrustedHTML CSP) — `<p>`-параграфы через `createElement`/`textContent` + `dispatchEvent(new InputEvent('input'))`.
- Путь исполнения по вендору — гибрид (см. п.6 «что решено»): **Grok = живой Chrome-MCP**; **Gemini/ChatGPT = живой Chrome-MCP сейчас, выделенный Firefox-профиль для безлюдного расписания** (фундамент HUB-01).
### СОСТОЯНИЕ 2 — PROBE (доказать до траты квоты) ⭐ сердце v2
НЕ жать Send, пока три проверки не зелёные:
1. **Режим включён:** на странице видна активная плашка Deep research / Expert (read_page/screenshot подтверждает, а не память).
2. **Промпт целиком:** вердикт = `ok` от `__drPasteVerify` (length + head + tail сверены каскадом). `ok:false` → каскад сам перебирает методы; 2 неудачи подряд → пропустить вендора, квота цела, пинг в леджер. (Ручная проверка без ассета: `editor.innerText.length` ≈ длине И совпали первые/последние ~60 символов.)
3. Только теперь Send/Run.
Затем **доказать старт** (иначе «отправил» ≠ «пошёл»):
- ChatGPT: план/«starting research»/счётчик источников растёт.
- **Gemini ДВУХФАЗНЫЙ:** сперва генерит план и ЖДЁТ кнопку «Start research» — ОБЯЗАТЕЛЬНО дожать, иначе ресёрч не начнётся. Подтверждение: «Great, I'm on it… Researching N websites».
- Grok: «Researching…»/searched web N results.
- Старт не подтвердился за 2 попытки-с-переосмотром → НЕ перезапускать вслепую (жжёт) → пометить в леджере `probe-failed`, пропустить вендора, доложить.
### СОСТОЯНИЕ 3 — LEDGER (сразу после старта каждого вендора)
Записать/дополнить `$OBSIDIAN_ROOT/_drafts/DR-FANOUT-<DR-ID>-<slug>.md`: тема · промпт целиком · время старта · по вендору {started|skipped+причина|probe-failed} · URL вкладки. Это единственная страховка от «забыли забрать» при безлюдном прогоне — коллектор (см. ниже) работает по этому файлу.
### СОСТОЯНИЕ 3.5 — ДОЛОЖИТЬ АНТОНУ: промпт + ССЫЛКИ (обязательно, anton 17.07)
Как только вендор перешёл в `started` — **сразу в диалог Антону, не дожидаясь отчёта**: полный текст промпта блоком ```text``` (paste-ready) + строка `🔗 <vendor>: <url>` на КАЖДЫЙ стартовавший чат. Живая сессия → в ответ; безлюдный прогон → в TG-03 через `bus_send.py`.
- URL брать из того же снимка вкладки, что и probe (`tabs_context_mcp` / `page.url`) — он уже содержит id чата.
- **Ссылка = приватный URL чата** (`chatgpt.com/c/…` · `gemini.google.com/app/…` · `grok.com/chat/…`). ⛔ Публичный share-линк (`/share/…`, `g.co/gemini/share/…`) — это ПУБЛИКАЦИЯ наружу (индексировалось Google), только по явной просьбе Антона.
- Не снял URL → сказать честно, с причиной; молча пропустить нельзя.
- Зачем: Антон смотрит с телефона и забирает результат сам по этой ссылке — она его точка входа. Канон: `reglament-vneshniy-resech-vsegda-promt-i-ssylka-v-chat`, память [[dr-prompt-paste-in-chat]].
### СОСТОЯНИЕ 4 — COLLECT (через ~20-40 мин, по леджеру)
DR думает 10-40 мин. По каждой started-вкладке: готов → извлечь (лестница ниже) → сохранить **verbatim** в `$OBSIDIAN_ROOT/_originals/deep-research/<DR-ID>-<slug>-<vendor>.md` (провенанс сверху: source/topic/date/origin) → `dr_registry.py update <DR-ID> --status collected --file "<путь>"`. ⭐ **ГЕЙТ ДОКАЗАТЕЛЬСТВА РАБОТЫ (21.07, DR26-07-21-HUB-02):** перед сохранением прочитать счётчик прогона — ChatGPT: строка «Research completed in Xm · N citations · M searches» над виджетом; Grok: «N sources» + «Thought for…»; Gemini: список источников. **`0 searches` / `0 citations` / нет источников → статус `dead`, НЕ `collected`**, перезапуск с явным требованием поиска, в синтез не берём. Реально случилось: ChatGPT Pro «исследовал» 9 минут, выдал красивый отчёт с таблицами целиком из памяти — внешне неотличим от настоящего. Не готов → отметить, вернуться позже. Безлюдный режим: ночной `dr_collect.py` (хаб) сам подхватит DR-ID из истории/Downloads и флипнет статус — ручной сбор нужен, только если отчёт нужен СЕЙЧАС.
**Фолбэк-лестница извлечения** — общий порядок (консенсус DR): **официальный export/share → backend JSON → DOM-scrape → эскалация человеку**. DOM — низший приоритет, не первый. Далее по вендорам:
- **ChatGPT** (отчёт в КРОСС-ДОМЕННОМ sandbox-iframe `connector_openai_deep_research` — JS туда не лезет, синтет-клики игнорит):
1. **Backend JSON (основной, без кликов, ✅ 2026-07-14):** page-JS `s=await fetch('/api/auth/session').then(r=>r.json()); conv=await fetch('/backend-api/conversation/<id>',{headers:{Authorization:'Bearer '+s.accessToken}}).then(r=>r.json())` → Blob-download JSON → на диске Python: `mapping[<node>].message.metadata.chatgpt_sdk.widget_state` (JSON-строка → `json.loads`) → `report_message.content.parts[0]`. Узел = walk по «Executive Summary».
2. **Без widget_state** (часть DR, ✅ DR26-07-11-HUB-02): отчёт прямо в `mapping[*].message.content.parts[0]` — walk по mapping, самая длинная строка >3000 симв.
3. ⭐ **Меню виджета «Export to Markdown» — РАБОТАЕТ синтет-кликом, безлюдно (✅ 2026-07-17, HUB-06):** новый connector-формат DR не отдаёт widget_state ВООБЩЕ (пути 1-2 мертвы) и невидим для find/accessibility-tree → только КООРДИНАТНЫЙ клик: иконка download в шапке виджета (правый верх, рядом с expand) → меню `Copy contents / Export to Markdown / Export to Word / Export to PDF` → **Export to Markdown** → `deep-research-report.md` в Downloads (проверить `ls`!) → переложить в `_originals` с провенансом. Человека звать НЕ нужно.
4. ⚠️ **Rate-limit врёт молча:** при «Too many requests» backend отдаёт mapping БЕЗ widget_state → выглядит как «отчёта нет», хотя отчёт готов и виден на экране. «Пусто из API» ≠ «нет отчёта» → сверься со СКРИНШОТОМ до вывода, подожди пару минут.
5. ⚠️ Открывать `iframe.src` отдельной вкладкой БЕСПОЛЕЗНО — песочница пустая, контент прилетает через postMessage.
- **Gemini:** отчёт в `STRUCTURED-CONTENT-CONTAINER` (канвас, same-origin) → `innerText` узла с заголовком → Blob-download → фолбэк: рендер в `<pre>` + get_page_text.
- **Grok:** отчёт в основном потоке → `document.querySelector('main').innerText`, отрезать эхо-промпт и хвост-подсказки → Blob-download. ⭐ Якорь обрезки: **«Thought for…» надёжнее первого «Executive Summary»** (проверено на прогоне FLEE-01 — экстракт зацепил эхо промпта).
- **Общий на всех:** большой текст мимо обрезки дисплея (JS-тул режет ~1500, get_page_text ~50k/проход) → Blob-download → Read из Downloads. ⚠️ **Blob-download может ТИХО не долететь** (2026-07-14: grok — да, chatgpt/gemini — нет; `a.click()` без ошибки, блок невидим) → ВСЕГДА `ls Downloads` после; не долетело → фолбэк `pre.textContent=txt; document.body.replaceChildren(pre)` (TrustedHTML-safe) → get_page_text кусками. Клипборд-пути (navigator.clipboard виснет; execCommand/Ctrl+C нужен жест) — НЕ тратить попытки.
- ⭐ **Полевое подтверждение 2026-07-21 (добор веера 14.07, 5 отчётов 16–85 KB — Blob НЕ долетел ни разу, Chrome multiple-downloads):** дефолтом сразу бери `get_page_text`, Blob не пробуй. Что нового узнали: (а) вывод >50 KB харнес САМ персистит в `tool-results/toolu_*.json` на диск → читаешь Read'ом, контекст не жжёшь; <50 KB приходит in-band; (б) жёсткий кап 50000 симв/проход обходится сдвигом окна видимого текста (паддинг/подмена узлов) + склейкой двух срезов по overlap последних ~300 симв — так собран отчёт 77k; (в) клипборд не просто «виснет», он отдаёт СТАРОЕ содержимое буфера Антона = ложный успех, всегда сверяй длину и первые слова; (г) **поиск чата в Grok по названию** — не UI (Ctrl+K мёртв, OneTrust-баннер ест клики), а same-origin `fetch('/rest/app-chat/conversations?pageSize=50',{credentials:'include'})` → `{conversations:[{conversationId,title}]}`; (д) **Gemini = SPA**: свежий `navigate` на URL чата грузит отчёт надёжнее синтетического клика по сайдбару (сайдбар лениво рендерит пустой текст); (е) возврат сырых заголовков чатов из JS ловит контент-фильтр (`BLOCKED: Cookie/query string`) → возвращай короткий статус-токен, не данные.
- ⭐ **Полевое подтверждение 2026-07-21 ВЕЧЕР (сбор HUB-02):** (а) **вброшенная на страницу СВОЯ кнопка не обходит запрет жестов** — синтетический/координатный клик по ней не считается user gesture, blob так и не качается (onclick-счётчик = 0; не изобретать заново); (б) **клики и клавиши расширения могут вообще не доходить до страницы** (окно без фокуса): симптом — Send нажат, а поле ввода не пустеет; лечение — программный `document.querySelector('button[data-testid="send-button"]').click()` из JS, React принимает его как настоящий (проверено: сабмит ушёл, композер опустел); (в) большой текст из DOM — сперва в копилку `window.__x`, offsets искать вторым вызовом, резать уже в Python из персиста `tool-results\`; (г) выделение узла Range+addRange и Ctrl+C поверх — буфер остаётся ПУСТ (не путать со «старым содержимым»: и такое, и такое бывает — потому `Get-Clipboard` сверять всегда).
- ⚠️ **Вендор может ОТКАЗАТЬСЯ отвечать** (Gemini, тема анти-бан аутрича — счёл обходом защит). Отказ = валидный результат: сохранить verbatim в `_originals` как обычный файл, статус `collected`, а в Decision Memo явно пометить «консенсуса нет, база = N вендоров» и не выдавать single-vendor за веер.
## Шаг 4 — синтез-консенсус (Alpha Protocol step 4)
Прочитать все собранные отчёты → таблица «сошлись / разошлись / уникальное у каждого» → Decision Memo (проблема · знания · DR · варианты · риски · рекомендация). Гетеро-принцип: расхождения НЕ сглаживать — показать Антону как развилки. Memo → `02-Decisions/` (если решение) или отчёт в чат. Леджер закрыть (`status: collected`).
⭐ **Шаг 5 — ЗАКРЫТЬ РАЗВЕДКУ (anton 27.07, обязателен).** `synthesized` — не финиш: отчёт написан, а система не изменилась. Каждый ДР доводится до одного из двух терминальных статусов, оба требуют `--note`:
- `dr_registry.py update <ID> --status applied --note "<что реально поменяли: Decision Memo / правка в проде / новая рутина>"`
- `dr_registry.py update <ID> --status parked --note "<почему не берём и что изменит решение>"`
`parked` — легальный и честный финал, не поражение ([[gate-implement-critical-only]]: не всё исследованное обязано быть внедрено). Гейт в `dr_registry.py` v3.3 роняет попытку без причины (exit 1). Повод правила: 27.07 в реестре 184 из 246 разведок висели `synthesized`, до `02-Decisions` дошло ~20 — отличить «кормит систему» от «просто лежит» было нельзя. Канон: память [[dr-finish-applied-or-parked]], CLAUDE.md §9.1.
## ⛔ ПОЛЕВЫЕ ДАННЫЕ НОЧИ 26.07.2026 (партия ZB-01…ZB-05, ноут HP17) — читать перед запуском
1. **🔴 ChatGPT Deep Research = `dead` на 26.07, канал исключён из веера.** Три независимых подтверждения за одну ночь: ZB-01 два прогона подряд «Research completed in 6m · **0 citations · 0 searches**» (второй — уже ПОСЛЕ явного follow-up «минимум 20 поисков / 20 источников» в теле), плюс тот же симптом на ZB-05 в параллельной сессии. Промпт доезжал целиком, чип Deep research стоял, ран стартовал и «думал» 6 минут — он просто НЕ ИСКАЛ, отдав красивую таблицу из памяти модели. **Не наш дефект вставки.** Перед включением ChatGPT в веер — сделать один пробный ран и прочитать счётчик; `0 searches` → `dead`, идём на 2 вендорах и пишем это в синтезе явно. Не жечь Retry больше двух раз (третий Retry лечит только `Error in message stream`, не пустой поиск).
2. **🔑 Gemini: заходить ТОЛЬКО по имени аккаунта, индекс `u/N` НЕ СТАБИЛЕН.** ⛔ Правка 27.07 (supersedes «всегда `u/7`»): `https://gemini.google.com/u/7/app` открылся под `other.account@example.com` — free-тариф, модель Flash, кнопка Upgrade. Индексы переезжают между сессиями, «мой номер» запоминать нельзя. **Рабочий вход:** `https://gemini.google.com/app?authuser=owner.personal@example.com` (редиректит на нужный `u/N` сам). Детект аккаунта без кликов, ОБЯЗАТЕЛЬНО до вставки промпта: `document.querySelector('a[aria-label*="Google Account"]').getAttribute('aria-label')` + проверка `document.body.innerText.includes('Upgrade')` (true = free-аккаунт). Без этой сверки отчёт молча уедет на Flash и будет выглядеть просто «слабоватым». Переключатель аккаунтов живёт в кросс-доменном iframe — `find`/скролл его не берут.
3. **Gemini молча откатывает модель на Flash-Lite** в каждой новой вкладке. Смотреть селектор ГЛАЗАМИ перед каждым запуском; Deep research переехал в «+» → **More tools** → «Deep research» (в первом уровне меню его больше нет).
4. **ChatGPT: порядок «чип → промпт», а НЕ наоборот** (supersedes прежняя заметка ZB-02 20.07). Чип «Deep research» — это инлайн-нода ВНУТРИ ProseMirror, встающая по позиции каретки: кликнешь в середину текста — расщепит предложение (ловилось как `chipIdx:470` посреди фразы). Рабочий порядок: (а) включить Deep research в ПУСТОМ композере — чип встаёт первым узлом; (б) поставить каретку в КОНЕЦ (`range.selectNodeContents(ed); range.collapse(false)`); (в) синтетический paste-event — вставка в коллапсированную каретку ничего не заменяет, чип выживает. ⚠️ Повторный paste при `selectNodeContents` НЕ заменяет текст, а ДОПИСЫВАЕТ (получишь удвоение) → чистить только живыми клавишами `ctrl+a` + `Delete`.
5. **Gemini-забор: `querySelector('.markdown-main-panel')` берёт ПЕРВУЮ панель = research-план, а не отчёт.** Сохранишь 1.7 KB плана вместо 33.8 KB отчёта и не заметишь. Правильно: якорь на заголовок отчёта → `h2('ПЛАН ИССЛЕДОВАНИЯ').closest('.markdown-main-panel').innerText`.
6. **Вынос большого текста:** `javascript_tool` режет вывод на ~1000-1500 симв. Единственный рабочий путь — сложить в `window.__R`, СРАЗУ подменить body на `<pre>` и СРАЗУ `get_page_text` (кап ~50k, отчёт 33.8k прошёл одним проходом). Подмена body ломает страницу → `window.__R` теряется при перезагрузке, порядок нарушать нельзя. Blob-download не пробовать (полевые заметки 21.07: не долетает).
7. **«Начать исследование» жать ДВАЖДЫ-с-переосмотром:** первый `find` находит кнопку, но клик приходит раньше, чем она смонтирована. Повторный `find` даёт новый ref — второй клик срабатывает. Доказательство старта = канвас «Starting research…» / «Прекрасно. Вы можете закрыть этот чат», а не факт клика.
8. **🔁 ДЕДУП — на КАЖДОМ вендоре, а не только в реестре.** Инцидент 03:0x: реестр показал ZB-03 = `issued`, дедуп по истории Grok дал «чисто» (похожий чат оказался от 22:49 UTC = ДО создания промптов партии) → запустил. А в Gemini Recents уже висел свой `DR26-07-26-ZB-03` от параллельной сессии → лишний прогон Gemini DR. Реестр = первый фильтр, история КАЖДОГО вендора, куда шлёшь = второй, обязательный. Это [[check-all-places-not-one]], применённое к вендорам вместо дисков.
9. **Корневой композер ChatGPT ОБЩИЙ на все вкладки — свой же черновик поедет за тобой.** 27.07: открыл вторую вкладку под ZB-04 — там лежал ZB-03 из первой; paste-event ДОПИСАЛ (8303 симв. вместо 4175), а `execCommand selectAll+delete` визуально очистил, но ProseMirror восстановил состояние и дописал снова (12450). Лечится только живой клавиатурой: клик в композер → `ctrl+a` → `Delete` → сверить `innerText.length===0` → и лишь потом paste.
10. **`ctrl+a`+`Delete` сносит и ЧИП режима** (Web search / Deep research) — прогон уйдёт без поиска, и это не видно в тексте промпта. Порядок для ChatGPT: очистить → вставить промпт → **включить чип заново** → сверить → Send. И ещё: текст чипа попадает в `innerText` композера то префиксом `Web search\n`, то суффиксом `\nWeb search` → при сверке длины срезать его с ОБОИХ концов, иначе ловишь ложный mismatch и начинаешь «чинить» целый промпт.
## ⭐ ПОЛЕ 28.07.2026 (ZB-04-2349, ноут HP17) — транспорт промпта и забор отчёта решены
1. **🔑 ТРАНСПОРТ ПРОМПТА = `window.name`, а не инлайн в javascript_tool.** Промпт 12 КБ инлайном на трёх вендоров = ~37 КБ контекста плюс риск экранирования. Рабочий путь, 0 токенов: `navigate` вкладку на локальный файл промпта → `window.name = await fetch(location.href).then(r=>r.text())` → `navigate` ТУ ЖЕ вкладку на сайт вендора → `window.name` доезжает целиком (проверено 12 224 / 12 279 / 12 467 знаков). Раздача: крошечный HTTP-сервер из скретчпада.
⚠️ **Исключение — Gemini:** COOP на `google.com` рвёт browsing context, и при уходе С gemini на localhost `window.name` обнуляется. Обратное направление (localhost → gemini) работает.
2. **🔑 ЗАБОР ОТЧЁТА = POST на локальный сервер, текст в мой контекст не попадает.** Тот же приём наоборот: в чате вендора сложить текст в `window.name` → `navigate` на `http://127.0.0.1:<порт>/sink` → оттуда `fetch('/save?name=raw-<vendor>.txt',{method:'POST',body:window.name})`. Сервер пишет файл, дальше проверяю полноту Python-ом (разделы, число URL) за копейки. Так забраны отчёты 16 КБ / 34 КБ / 83 КБ.
⚠️ **Для Gemini** (COOP убивает window.name) работает **фрагмент URL**: `location.href='http://127.0.0.1:<порт>/sink#'+encodeURIComponent(txt)` → на sink-странице `decodeURIComponent(location.hash.slice(1))` → POST. Фрагмент на сервер не уходит, приватность цела.
3. **Что НЕ работает, не тратить попытки:** `fetch` с страницы вендора на 127.0.0.1 (CSP `connect-src` — режут и chatgpt.com, и gemini.google.com) · отправка формой на localhost (CSP `form-action`) · CDP `ctrl+v` (клавиша доходит, вставки нет) · кнопка «Copy contents» в UI (нужен фокус окна, а окно фоновое — буфер молча не меняется; всегда сверять `Get-Clipboard` с сентинелом).
4. **🔴 ChatGPT Deep Research — ПЯТЫЙ подряд `0 citations · 0 searches`** (4 раза 26.07 + 1 раз 28.07, аккаунт `owner.work@`, 15 минут «думал» и выдал красивый отчёт из памяти). Web search на том же аккаунте и той же модели ищет нормально (90+ запросов, 80+ страниц, 168 URL в отчёте). ⇒ **Не тратить DR-чип на этом аккаунте: ChatGPT-канал вести сразу через Web search** + в тело промпта строку «перечисли выполненные запросы и реально открытые URL перед финальным отчётом». Экономит 15 минут и один прогон.
5. **ChatGPT DR стал ДВУХФАЗНЫМ, как Gemini:** после Send показывает карточку плана с `Edit / Cancel / Start` и автостартом по таймеру ~30 с. Кнопку дожимать.
6. **ChatGPT: `execCommand insertText` сел, синтетический paste-event НЕ сел** — ровно наоборот, чем у Grok (там paste-event с первого раза). Каскад нужен обоим, порядок методов по вендору разный. Чип режима ставить в ПУСТОМ композере, потом каретка в конец, потом вставка — чип выживает.
7. **Gemini: кнопка «Начать исследование» остаётся видимой и enabled после успешного клика.** Доказательство старта — не исчезновение кнопки, а канвас `Прекрасно. Вы можете закрыть этот чат` + `Researching N websites`. И `bodyLen` у Gemini скачет на порядок (327 887 → 14 403 за ре-рендер), как признак старта не годится.
8. **Gemini-забор: брать панель по МАКСИМАЛЬНОЙ длине**, а не первую. На готовом отчёте `.markdown-main-panel` было три штуки: 1861 (план), 144, 34 444 (отчёт). Панель отчёта рендерится лениво — если её нет, кликнуть карточку отчёта в ленте.
9. **Grok Heavy: 485 sources и НОЛЬ инлайн-ссылок.** Источники отданы абзацем с перечнем доменов, анкоров на странице 2. `innerText` ничего не теряет, но проверяемость Grok-фактов низкая — спорные цифры сверять руками (в этом прогоне Grok ошибся: заявил, что платных ускорителей нет, а Story Boost за $159,99 существует).
10. **Два подключённых Chrome в MCP.** Один может быть чистым профилем, разлогиненным везде. Проверять аккаунт (`/api/auth/session` у ChatGPT, `aria-label` у Gemini, `Sign in` в тексте у Grok) ДО вывода «разлогинен, зовите Антона».
11. **⭐ Blob-download на chatgpt.com РАБОТАЕТ — и это единственный способ забрать отчёт целиком (27.07, supersedes полевую заметку 21.07 «Blob не долетает»).** Замер: отчёт 73 144 симв. приехал файлом 97 992 байта, второй — 60 623 симв., оба с первого раза. `get_page_text` для таких объёмов НЕПРИГОДЕН: режет на 50 000 симв. **и отрезает ровно хвост — раздел Proof of work**, то есть само доказательство, что вендор искал. Порядок: собрать текст последнего `[data-message-author-role="assistant"]` в `window.__R` → Blob + `a.click()` → **обязательно `ls Downloads`** → перенести скриптом с провенансом. Контекст сессии при этом не тратится вообще — текст идёт диск-в-диск. ⚠️ Трюк «добить пэддингом до >50 КБ, чтобы get_page_text persist-нул на диск» НЕ работает: тул иногда персистит, а иногда режет инлайном — поведение непредсказуемо, не закладываться.
12. **`exit 0` от `brain_embed_update.py` при занятом локе — НЕ баг и не враньё.** В коде осознанно: `busy_code = 3 if index_age_hours() > STALE_HOURS else 0` (порог 26 ч). Код отвечает на вопрос «индекс протух по часам?», а НЕ «мой запрос выполнился?». После записи новых заметок это разные вопросы: свежий по часам индекс их всё равно не содержит. ⇒ После реиндекса проверять ФУНКЦИОНАЛЬНО — запросом к `brain_ask.py` на фразу, которой нет нигде, кроме новых файлов. Счётчик `harari ×N` в `_brain_e5_meta.pkl` не доказательство: там пути файлов, не текст чанков.
## Ошибки/грабли (не вошедшее в автомат)
- ⚠️ **Фоновая/свёрнутая вкладка Chrome (проверено 2026-07-17):** viewport 0×0, layout заморожен → синтетические JS-клики и Radix/Angular-кнопки (Gemini «Start research», ChatGPT «+»-меню) НЕ срабатывают, а `computer` кликает мимо. Лечение: `tabs_create_mcp` → новая вкладка (получает layout даже в фоновом окне) → открыть тот же URL разговора → `find` → `computer left_click ref` (CDP-trusted). Промпт при этом уже отправлен — теряется только «дожать кнопку», не квота.
- ⭐ **«started» в леджере ≠ реально запущено (инцидент HUB-06, 16→17.07):** три вендора помечены started, по факту работал ОДИН. Gemini висел на непрожатой кнопке «Start research» (страница = только промпт, panel=0), Grok вообще не отправлен (path остался `/`, промпт в композере). Потеряна ночь. → **probe-after-start обязателен и доказателен:** path сменился на /chat/ · виден индикатор прогресса · объём страницы вырос. Вставка ≠ отправка; отправка ≠ старт. Состояние `submitted` без подтверждённого `started` = не started.
- ⭐ **ChatGPT DR останавливается на research-плане (проверено 2026-07-20, ZB-02):** первый ран (~12 мин, «0 citations · 0 searches») может выдать ТОЛЬКО research-план + output-structure, БЕЗ настоящего ресёрча, и завершиться (`finished_successfully`, end_turn). Это НЕ баг вставки/старта — ран реально шёл, но выродился в план. Лечение: follow-up в тот же чат «Proceed now: execute this plan and write the FULL final report… Do not stop at the plan» → второй ран (у нас 65 мин) даёт полный отчёт с живыми URL. При сборе: если backend-JSON longest-part начинается с «Research Plan:» и в mapping только один widget с планом — это план, не отчёт; пнуть, не сохранять как collected. (Gemini/Grok этим не страдают — план у Gemini отдельная фаза с кнопкой.)
- ⚠️ **Плашка DR-режима ChatGPT живёт ВНУТРИ редактора (ZB-02, 20.07):** каскад `paste_verify` (directSet/execCommand) чистит редактор и СТИРАЕТ чип «Deep research» → probe покажет `chip:false`. Порядок: сначала вставить промпт, ПОТОМ включить Deep research поверх (меню «+» → Deep research), затем сверить чип и Send. Иначе улетит обычный чат, квота DR цела но ответ не тот.
- ✅ **Grok, зеркало textarea/contenteditable — КОРЕНЬ найден и вылечен (FLEE-03, 17.07):** Grok 4.5 = TipTap/ProseMirror contenteditable (`div.tiptap.ProseMirror`); видимый `<textarea>` — СКРЫТОЕ зеркало. Заполнение textarea (nativeSetter/value+InputEvent) даёт `ok:true`, но React/PM-состояние из зеркала не обновляется → Submit не рендерится, Enter=no-op (ровно это жгло время 07-10 и 07-17). **Фикс в каскаде:** целить `.tiptap.ProseMirror` ПЕРВЫМ + синтетический paste-event (`ClipboardEvent('paste',{clipboardData:DataTransfer})`) → PM адоптит текст → `button[type="submit"]` появляется enabled → клик. Проверено вживую 17.07 (FLEE-03 Grok `/c/e621f761`). Если UI снова уплывёт и paste-event не сработает → новый чат + probe, не жечь время.
- ⭐ **ChatGPT DR молча не ищет — и промптом это НЕ лечится (26.07.2026, ZB-02 + ZB-05 независимо).** Симптом: «Research completed in Xm · **0 citations · 0 searches**», отчёт красивый и целиком из памяти. Замер: 4 прогона, 2 разных чата, 2 независимые сессии, один аккаунт `owner.work@` (Pro); второй прогон в каждой паре шёл С явным требованием искать — не помогло. ⛔ Правило: **два `dead` подряд = не гнать третий раз тем же способом**, канал закрыть, синтез строить на оставшихся вендорах и явно писать «база N вендоров». Разделяющий тест (дёшево, делать ДО выводов о причине): тот же вопрос обычным чатом с инструментом **Web search** — он идёт другим код-путём. Если Web search ищет нормально (у нас: 24+ запроса, «Searched N websites» блоками) → сломан именно DR-путь, 🤔 вероятнее всего выжата DR-квота и вендор деградирует молча вместо честной ошибки. Побочная польза: Web search + жёсткий промпт («перечисли запросы и открытые URL перед ответом») даёт пригодный цитируемый отчёт — это рабочий обход, пока DR лежит.
- ⭐ **Корневой композер `chatgpt.com/` — общий на аккаунт и его рвут параллельные сессии (26.07.2026).** Черновик синкается между сессиями: за один прогон там побывали чужие `ZB-05` и `ZB-06`, мои вставки соседняя сессия откатывала своим React-состоянием, а один раз моя строка успела прилипнуть в хвост ЧУЖОГО промпта (вычистить не удалось — правки не держались). ⛔ Правило: при работе в параллель **не трогать корневой композер**; вести прогон внутри СВОЕГО `/c/<id>` (композер пер-чатовый, не оспаривается), новый чат создавать только когда корневой пуст. Перед вставкой всегда читать композер: непустой + чужой ID = стоп, а не «перезапишу».
- Разлогин посреди ресёрча → отчёт может потеряться: после логина проверить историю чатов вендора, DR обычно сохраняется в истории.
- Длинный отчёт обрезается в get_page_text → прокрутить/раскрыть («Show more») перед чтением; сверить конец текста с концом отчёта.
- ⛔ Никогда не заводить ПЛАТНЫЙ API-путь как «фолбэк» без согласования ([[prefer-included-limits-before-paid-api]]).
- Один и тот же промпт всем вендорам ДОСЛОВНО, кроме намеренного платформенного блока §2/§3/§4 (иначе консенсус грязный).
- ⚠️ **Аккаунт может флагнуть автоматизацию:** на прогоне FLEE-01 ChatGPT показал баннер «Suspicious activity detected» при старте DR из автоматизации (НЕ заблокировал, ресёрч пошёл). Это ровно тот failure-mode, что предсказали оба DR-вендора. Увидел баннер → не паниковать и не долбить ретраями; отметить в леджере, продолжать. Повторяется системно → `drift_suspected`, доложить Антону.
- ⚠️ **Session longevity никто не публикует** (консенсус DR) → forced re-auth считать НЕИЗБЕЖНЫМ, не строить на таймере. `needs_reauth` = первоклассное состояние + пинг человеку out-of-band (02/QQQ).
- ⏳ **Полностью безлюдный ЗАПУСК** — следующий шаг стройки (архитектура известна из DR: ledger-FSM + выделенный Firefox-профиль + cron/systemd; старт с ChatGPT+Gemini). Пока безлюден только СБОР (ночной `dr_collect.py`); запуск требует живой сессии с браузером. Дыра осознана, закрывается после решения Антона по «дежурной браузер-сессии на хабе».
## /tt — как проверить v2 (после прихода FLEE-01 или при правке)
Не гонять живой DR ради теста (жжёт квоту). Проверять по частям: (1) probe-логика — на уже открытой вкладке проверить, что детект режима+длины работает БЕЗ Send; (2) извлечение — на УЖЕ собранном прошлом DR (backend JSON / innerText) прогнать парсер, сверить с сохранённым `_originals`; (3) леджер+dr_collect — прогнать на существующем DR-ID. Живой end-to-end — только когда реально нужен ресёрч.