dr-fanout · diff

git:20260814.06fa906 to git:20260814.d899e4a

125 added, 125 removed. Audit B to B.

---
name: dr-fanout
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 и собрать консенсус
+ # /dr-fanout — fan a Deep Research prompt out to 3+ LLMs and collect a consensus
- > Финал 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]] (строго локально).
+ > The final stage of the Alpha Protocol, automated. Channels: **ChatGPT** (chatgpt.com) · **Gemini** (gemini.google.com) · **Grok** (grok.com). The mechanism = the Claude-in-Chrome MCP (the operator's live logged-in Chrome). Canon: [[alpha-protocol-recall-plus-dr]], decision-multi-llm-vendor-independence (heterogeneous consensus), [[chrome-autonomy-self-drive]], [[browser-work-on-peers-not-hub]] (strictly local).
- ## ⭐ Что уже решено (фундамент, не переисследовать) — обновлено 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, «и так и так»). Не один способ на всех:
- | Вендор | Путь | Почему |
+ ## ⭐ What is already decided (the foundation, don't re-research) — updated 2026-07-16
+ 1. **The browser layer = Firefox-first** (Decision Memo `02-Decisions/decision-2026-07-16-browser-automation-layer.md`, DR26-07-16-HUB-01, confidence high). Chrome 127+ encrypts cookies (ABE) and since April 2026 binds sessions to the hardware (DBSC) → external cookie extraction is impossible without malware techniques. **Firefox cookies are open** (plaintext SQLite, DBSC not implemented) → a dedicated per-service Firefox profile + Playwright `launch_persistent_context`; a Chrome CDP attach is only a fallback for strictly-Chromium sites. The hub stack is already up: `firefox_cookies.py` (`~/.claude/scripts/_shared/`), profiles in `D:\AutomationBrowsers\Firefox\`.
+ 2. **The live Chrome MCP (Claude-in-Chrome) remains the deliberate anti-ban path** for actions that must look like "a human in a real session" (fb-post/x-post go that way). For dr-fanout the choice of execution path (live Chrome MCP vs headless Firefox+Playwright) is being clarified by an ongoing DR (see item 4).
+ 3. **A CLI workaround does NOT give you subscription Deep Research** (verified 07-15): the Codex CLI / Gemini CLI only do web search; real consumer-subscription Deep Research cannot be triggered programmatically (Google's DR agent = a separate paid API). ⇒ the browser front end is the only road to subscription DR, so we make it anti-fragile instead of running away from it.
+ 4. **ToS risk, sharpest at Grok:** the xAI AUP explicitly forbids automated/non-human access (risk of suspension/termination). There are no documented bans for automating YOUR OWN account, but the text is explicit → run the Grok channel at human pace; the decision to "keep / slow down / replace with claude.ai" belongs to the owner.
+ 5. **Grok — we simply keep using it** (the owner's decision, 2026-07-16). The xAI AUP formally forbids automation, but enforcement hunts mass scraping (a $15k/1M-requests penalty), and our pace is naturally tiny (a few DRs per day at most) → we are not the target. The value of a third independent voice > the managed risk. Do NOT build limiters/throttling ([[ak47-simplicity]]) — Grok stays in the normal rotation; if the vendor itself pushes back (a captcha/challenge) — report it and skip that channel, no drama.
+ 6. **The execution path is HYBRID, per vendor** (the owner's decision, 2026-07-16, "both ways"). Not one method for everyone:
+ | Vendor | Path | Why |
|---|---|---|
- | **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]]) — если платный, не заводить без «+» Антона.
+ | **Grok** | live Chrome MCP, human pace | ToS-sensitive → act like a human in a real session (maximum anti-ban, same as fb-post [[chrome-autonomy-self-drive]]); a headless bot here = maximum risk |
+ | **ChatGPT** | a dedicated headless Firefox profile (unattended) OR the live Chrome MCP | milder ToS; report extraction = backend JSON (works in both); for an unattended schedule → Firefox |
+ | **Gemini** | a dedicated headless Firefox profile (unattended) | two-phase (plan → Start research), tolerant of automation; candidate #1 for a fully unattended run |
+ The principle: the harsher a vendor's ToS / ban sensitivity → the closer to "a live human in a session" (Chrome MCP); the more tolerant it is + the more unattended operation matters → the closer to a dedicated Firefox profile (Playwright persistent, the HUB-01 foundation).
+ 7. **✅ The orchestration is CONFIRMED by an external DR** (`DR26-07-14-FLEE-01`, a ChatGPT+Grok synthesis 2026-07-16, digest in `03-Insights/insight-DR-DR26-07-14-FLEE-01-*`). Both vendors independently: the core = a **durable state machine + a job ledger, NOT "a long-lived autonomous browser agent"**; a local ledger FSM is sufficient for a single-owner hub. Both independently advise **NOT to build unattended Grok automation** (the xAI AUP + enforcement is real: >52k bans in 2026, Reuters 07-15) → our matrix in item 6 already honours that (Grok only via live Chrome MCP, never in a daemon). **Start the unattended schedule with 2 vendors: ChatGPT + Gemini.**
+ 8. **Keep the vendor logic THIN and the orchestration SHARED.** UI-specific repos die fast (`chatgpt-automation-mcp` archived 2026-04-27, `browserbase/gemini-browser` archived 2026-05-20). Everything vendor-specific = swappable "adapters" at the bottom; the state machine/ledger above them does not change.
+ 9. **⚠️ OPEN — the official path for Gemini:** the Deep Research Agent / **Interactions API** (`background=True` + polling, collaborative_planning) — production-ready, and it removes the most fragile and slowest browser channel. BUT ⚠️ ADDED COMPLEXITY + unclear billing: is it included in the Ultra subscription or is it separate money (the ChatGPT report says "NOT the same free-with-subscription")? **Check the billing BEFORE building** ([[prefer-included-limits-before-paid-api]]) — if it is paid, don't set it up without the owner's "+".
- ## Жёсткие рамки (читать первыми)
- 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).
+ ## Hard boundaries (read these first)
+ 1. **⭐ The owner's mandate (2026-07-14, supersedes the quota gate of 07-05): any number of DRs, WITHOUT asking.** "Run as many deep researches as you like, don't ask me, don't worry about limits" — with an exhausted quota ChatGPT degrades gracefully (a lighter report, not a refusal), and a heterogeneous fan-out across 3 vendors compensates. I launch them myself and report after the fact. The only caveat: don't burn quota on DUPLICATES — the dedup check in Step 0 is mandatory.
+ 2. **The browser stays strictly local** on the machine running the session. Ask nothing of the other machines.
+ 3. **The owner's accounts:** if a site is logged out → log in per [[social-auth-autonomous]] (credentials in the store); a CAPTCHA/2FA wall → call him with one sentence + a screenshot.
+ 4. **We send NOTHING but the prompt** into the DR composer. Don't touch other chats/settings.
+ 5. **ANTI-RECENTS when collecting a report:** while looking for a finished DR chat/report in a web UI (ChatGPT/Gemini/Grok), do NOT conclude "there is no report" from a quick glance at recents — use the built-in SEARCH by keywords/ID + Projects/archive + confirm the active account by email. Registry first (`_DR-Registry.md`, Step 0), then the UI search, and only then the conclusion "not there". Canon: memory [[web-ui-search-not-recents]] (an incident on 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` и еду.
+ ## Step 0 — the entrance
+ ⭐ **DEDUP BEFORE QUOTA (the owner, 2026-07-14):** before burning DR quota — check whether the report already exists. (1) There is an ID in the prompt → find its line in the registry: `grep "<DR-ID>" "$OBSIDIAN_VAULT/_DR-Registry.md"` — status `collected`/`synthesized` = STOP, no fan-out needed: report "already collected", show the files (`_originals\deep-research\*<DR-ID>*`, `03-Insights\insight-DR-<id>*`), go to Step 4 (synthesis). (2) No ID → grep the registry by the topic's keywords: the same topic sitting in `issued` → reuse THAT ID; in `collected+` → show what exists and ask whether a new run is needed at all. The nightly `dr_collect.py` (hub, 05:05) flips statuses from the exports by itself — the registry is fresher than the session's memory.
+ ⭐ A DR number is mandatory (the owner, 2026-07-03): if the prompt has no `DRYY-MM-DD-MACHINE-NN` ID yet — allocate one: `python $IMPORTS_ROOT/dr_registry.py new "<topic>" --tool chatgpt,gemini,grok` and put the ID as the first line of the prompt (`# DR26-07-03-ZB-01 — <topic>`). The script derives the machine code itself (each computer has its own sequence — no collisions when syncing). Canon: the rulebook entry on DR numbering and the registry.
+ Where the prompt comes from: the current chat (just emitted by the Alpha Protocol) / a file the owner points to. We do NOT ask for a "+" (the 07-14 mandate) — I announce it with one line, `🚀 DR-fanout: distributing <ID> to ChatGPT+Gemini+Grok`, and go.
- ## Шаг 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` первой строкой у всех.
+ ## Step 0.5 — tuning the prompt per vendor (mandatory)
+ Before distributing, append to the prompt body: `§1 THE UNIVERSAL ADD-ON` from [[dr-platform-playbook]] (`08-Templates\dr-platform-playbook.md`) — always, for everyone; **plus the platform block §2 (Grok) / §3 (Gemini) / §4 (ChatGPT)** for each specific vendor. The body (from `deep-research-prompt-template.md`) and §1 are identical for all; the platform block differs DELIBERATELY (it plays to each one's strength: Grok = realtime/X + hard citations, Gemini = plan editing/formality/depth). The `DRYY-MM-DD-MACHINE-NN` ID is the first line for all of them.
- ## Шаги 1-3 — АВТОМАТ submit → probe → collect (per vendor)
- > Ядро надёжности v2, ✅ подтверждено внешним DR (см. п.7). Каждый вендор проходит автомат независимо; сломался на шаге — падает В ФОЛБЭК того шага, не роняя остальных. Золотое правило: **probe перед burn** — ни одна DR-квота не тратится, пока не доказано: (а) режим включён, (б) промпт целиком, (в) ран стартовал.
+ ## Steps 1-3 — the SUBMIT → PROBE → COLLECT state machine (per vendor)
+ > The reliability core, v2, ✅ confirmed by an external DR (see item 7). Each vendor runs the machine independently; a break at one step falls into THAT step's fallback without taking the others down. The golden rule: **probe before burn** — no DR quota is spent until it is proven that (a) the mode is on, (b) the prompt is complete, (c) the run actually started.
>
- > **Состояния** (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).
+ > **States** (the ledger = `_drafts/DR-FANOUT-<DR-ID>-*.md`, key = the DR-ID → resume is idempotent): `staged → mode_verified → submitted → started → waiting → ready → collected → delivered`. Emergency states: `needs_reauth` · `drift_suspected` · `probe_failed` · `aborted`. ⭐ **There are exactly two human gates — `needs_reauth` and `drift_suspected`; everything else is unattended** (the DR consensus).
+ > **Locators:** ARIA/role first → CSS → and only then LLM/vision. ⛔ A semantic/LLM element search is for dry-run/repair mode ONLY, NEVER on a quota-spending submit (the DR consensus).
- Инструменты одним ToolSearch: `tabs_context, navigate, computer, read_page, tabs_create, form_input, get_page_text, read_console_messages`.
+ Tools in one 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).
+ ### STATE 1 — SUBMIT (turn the DR mode on + paste the prompt)
+ A new tab → wait for the load → logged in? (no → [[social-auth-autonomous]]; a 2FA/CAPTCHA wall → screenshot + skip the vendor). Then **find the DR mode BY LOOKING at the page** (not from memory — the UI drifts on all three):
+ - **ChatGPT** (the work Google account): the model selector first → **Pro, the maximum** (currently GPT-5.6) + the maximum thinking level; then the composer → the tools menu ("+"/"Tools") → "Deep research". ⭐ The owner, 07-21: always the smartest model; the name changes, the principle does not.
+ - **Gemini** (the personal Google account): the model = **Pro** (currently 3.1), ⛔ NOT Flash (it silently rolls back — check!); enable **Extended thinking** (the checkbox on the right, near the microphone); "+" → "Deep Research" → the prompt → Enter → the plan → **press OK/Start**.
+ - **Grok** (the vendor account that also holds the owner's Twitter): ⭐ the owner, 07-21 — **Heavy** mode is the DEFAULT (the top subscription was bought; supersedes the earlier "Expert, don't touch Heavy"). There is no separate DR button → add a line to the prompt body, "Search the web extensively and cite sources"; watch that the selector does not fall back to Expert/Fast (a silent downgrade, 07-20). The "DR-grade in Grok Heavy" method (assembled 07-21, DR26-07-21-HUB-02): **Heavy IS Deep Research** — a swarm of 8–16 sub-agents searching in parallel and arguing; Expert is now single-agent and weaker for citation-heavy work; DeepSearch/DeeperSearch were removed and dissolved into Heavy. Without being forced, Heavy answers from memory → the prompt must include: "search the web and X extensively" + 15–25 primary sources + a short quote and an exact URL per claim + "cite ONLY URLs you actually opened" + a final verification pass. Proof of a real run: "Thought for" measured in minutes + an "N sources" counter; an instant answer with no sources = a downgrade, restart. Quotas = a weekly shared pool (Settings → Usage, as a percentage), context 256k–500k, a run takes 5–20+ min. There is no one-click export (select and copy); Share = a PUBLIC link ⛔. The full prompt template is in `_originals\deep-research\DR26-07-21-HUB-02-grok-heavy-playbook-grok.md`, section "(b) Reusable Prompt TEMPLATE"; the synthesis is `insight-DR-DR26-07-21-HUB-02-grok-heavy-as-a-deep-research-engine`.
+ - Pasting the prompt — ONLY through JS, NEVER `computer type` (every Enter = a send, a truncated fragment flies off and the quota burns). ⭐ **The `paste_verify.js` cascade** (next to the skill, from 07-16, it cures the 07-10 defect "execCommand did not take"; the forever-fix for Grok/ProseMirror is 07-17 FLEE-03): read the file `~/.claude/skills/dr-fanout/paste_verify.js`, execute its body through `javascript_tool`, then call `window.__drPasteVerify(PROMPT, "chatgpt"|"gemini"|"grok")`. It walks the methods itself (⭐ **a synthetic paste event for ProseMirror/TipTap** → execCommand → the native React textarea setter → Quill/CE paragraph nodes → directSet), checks length+head+tail after EACH one (for ProseMirror it reads `el.innerText`, NOT the textarea mirror) and returns `{ok, method, gotLen, wantLen, isPM, ...}`.
+ - ⚠️ **Grok 4.5 = a TipTap/ProseMirror contenteditable** (`div.tiptap.ProseMirror`), and the visible `<textarea>` is a HIDDEN MIRROR: filling the textarea (nativeSetter) returns `ok:true`, but the form/React do NOT update from the mirror → the Submit button never renders, Enter is a no-op, the run does not start. **The real editor must be filled with a synthetic paste event** (`ClipboardEvent('paste',{clipboardData:DataTransfer})`) → ProseMirror adopts the text normally → `button[type="submit"]` appears enabled → click it. The cascade now targets ProseMirror FIRST and does this by itself; the textarea is left as the last fallback.
+ - The manual fallback (if the asset is unavailable): for 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}))`; for Gemini (Quill + TrustedHTML CSP) — `<p>` paragraphs via `createElement`/`textContent` + `dispatchEvent(new InputEvent('input'))`.
+ - The execution path per vendor is hybrid (see item 6 of "what is decided"): **Grok = the live Chrome MCP**; **Gemini/ChatGPT = the live Chrome MCP for now, a dedicated Firefox profile for the unattended schedule** (the HUB-01 foundation).
- ### СОСТОЯНИЕ 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`, пропустить вендора, доложить.
+ ### STATE 2 — PROBE (prove it before spending quota) ⭐ the heart of v2
+ Do NOT press Send until three checks are green:
+ 1. **The mode is on:** an active Deep research / Expert chip is visible on the page (confirmed by read_page/screenshot, not by memory).
+ 2. **The prompt is complete:** the verdict is `ok` from `__drPasteVerify` (length + head + tail checked by the cascade). `ok:false` → the cascade walks the methods itself; 2 failures in a row → skip the vendor, the quota is intact, note it in the ledger. (A manual check without the asset: `editor.innerText.length` ≈ the expected length AND the first/last ~60 characters match.)
+ 3. Only now Send/Run.
+ Then **prove the start** (otherwise "sent" ≠ "running"):
+ - ChatGPT: a plan / "starting research" / a growing source counter.
+ - **Gemini is TWO-PHASE:** first it generates a plan and WAITS for the "Start research" button — you MUST press it, or the research never begins. Confirmation: "Great, I'm on it… Researching N websites".
+ - Grok: "Researching…" / searched web N results.
+ - The start was not confirmed after 2 attempts with a fresh look → do NOT blindly restart (that burns quota) → mark `probe-failed` in the ledger, skip the vendor, report it.
- ### СОСТОЯНИЕ 3 — LEDGER (сразу после старта каждого вендора)
- Записать/дополнить `$OBSIDIAN_ROOT/_drafts/DR-FANOUT-<DR-ID>-<slug>.md`: тема · промпт целиком · время старта · по вендору {started|skipped+причина|probe-failed} · URL вкладки. Это единственная страховка от «забыли забрать» при безлюдном прогоне — коллектор (см. ниже) работает по этому файлу.
+ ### STATE 3 — LEDGER (immediately after each vendor starts)
+ Write/extend `$OBSIDIAN_ROOT/_drafts/DR-FANOUT-<DR-ID>-<slug>.md`: the topic · the full prompt · the start time · per vendor {started|skipped+reason|probe-failed} · the tab URL. This is the only insurance against "we forgot to collect it" on an unattended run — the collector (below) works off this file.
- ### СОСТОЯНИЕ 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]].
+ ### STATE 3.5 — REPORT TO THE OWNER: the prompt + the LINKS (mandatory, the owner 07-17)
+ As soon as a vendor reaches `started` — **straight into the chat with him, without waiting for the report**: the full prompt text as a ```text``` block (paste-ready) + a `🔗 <vendor>: <url>` line for EVERY started chat. A live session → in the reply; an unattended run → into the fleet log chat via `bus_send.py`.
+ - Take the URL from the same tab snapshot as the probe (`tabs_context_mcp` / `page.url`) — it already contains the chat id.
+ - **The link = the PRIVATE chat URL** (`chatgpt.com/c/…` · `gemini.google.com/app/…` · `grok.com/chat/…`). ⛔ A public share link (`/share/…`, `g.co/gemini/share/…`) is PUBLICATION to the outside world (it has been indexed by Google) — only on his explicit request.
+ - Failed to capture the URL → say so honestly, with the reason; silently skipping it is not allowed.
+ - Why: he reads from his phone and collects the result himself through that link — it is his entry point. Canon: the rulebook entry on always putting the prompt and the link in the chat, memory [[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 и флипнет статус — ручной сбор нужен, только если отчёт нужен СЕЙЧАС.
+ ### STATE 4 — COLLECT (after ~20-40 min, driven by the ledger)
+ A DR thinks for 10-40 minutes. For each started tab: ready → extract (the ladder below) → save it **verbatim** into `$OBSIDIAN_ROOT/_originals/deep-research/<DR-ID>-<slug>-<vendor>.md` (provenance at the top: source/topic/date/origin) → `dr_registry.py update <DR-ID> --status collected --file "<path>"`. ⭐ **THE PROOF-OF-WORK GATE (07-21, DR26-07-21-HUB-02):** before saving, read the run counter — ChatGPT: the line "Research completed in Xm · N citations · M searches" above the widget; Grok: "N sources" + "Thought for…"; Gemini: the source list. **`0 searches` / `0 citations` / no sources → the status is `dead`, NOT `collected`**, restart with an explicit demand to search, and it does not go into the synthesis. This really happened: ChatGPT Pro "researched" for 9 minutes and produced a beautiful report with tables entirely from memory — outwardly indistinguishable from a real one. Not ready → note it and come back later. Unattended mode: the nightly `dr_collect.py` (hub) picks the DR-ID up from history/Downloads and flips the status itself — manual collection is only needed if the report is wanted NOW.
- **Фолбэк-лестница извлечения** — общий порядок (консенсус 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 за веер.
+ **The extraction fallback ladder** — the general order (the DR consensus): **the official export/share → backend JSON → DOM scraping → escalate to a human**. The DOM is the lowest priority, not the first. Then per vendor:
+ - **ChatGPT** (the report lives in a CROSS-DOMAIN sandbox iframe `connector_openai_deep_research` — JS cannot reach in, and synthetic clicks are ignored):
+ 1. **Backend JSON (the main path, no clicks, ✅ 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())` → a Blob download of the JSON → then in Python on disk: `mapping[<node>].message.metadata.chatgpt_sdk.widget_state` (a JSON string → `json.loads`) → `report_message.content.parts[0]`. Find the node by walking for "Executive Summary".
+ 2. **No widget_state** (some DRs, ✅ DR26-07-11-HUB-02): the report sits directly in `mapping[*].message.content.parts[0]` — walk the mapping and take the longest string over 3000 characters.
+ 3. ⭐ **The widget's "Export to Markdown" menu — WORKS with a synthetic click, unattended (✅ 2026-07-17, HUB-06):** the new connector DR format does not expose widget_state AT ALL (paths 1-2 are dead) and is invisible to find/the accessibility tree → only a COORDINATE click works: the download icon in the widget header (top right, next to expand) → the menu `Copy contents / Export to Markdown / Export to Word / Export to PDF` → **Export to Markdown** → `deep-research-report.md` lands in Downloads (check with `ls`!) → move it into `_originals` with provenance. No human needed.
+ 4. ⚠️ **The rate limit lies silently:** on "Too many requests" the backend returns the mapping WITHOUT widget_state → it looks like "there is no report", while the report is finished and visible on screen. "Empty from the API" ≠ "no report" → check against the SCREENSHOT before concluding, and wait a couple of minutes.
+ 5. ⚠️ Opening `iframe.src` in a separate tab is POINTLESS — the sandbox is empty, the content arrives over postMessage.
+ - **Gemini:** the report lives in a `STRUCTURED-CONTENT-CONTAINER` (a canvas, same-origin) → `innerText` of the node with the heading → a Blob download → fallback: render into a `<pre>` + get_page_text.
+ - **Grok:** the report is in the main stream → `document.querySelector('main').innerText`, then cut off the echoed prompt and the trailing suggestions → a Blob download. ⭐ The trimming anchor: **"Thought for…" is more reliable than the first "Executive Summary"** (verified on the FLEE-01 run — the extract had caught the prompt echo).
+ - **Common to all:** a large text beyond the display truncation (the JS tool cuts at ~1500, get_page_text at ~50k per pass) → a Blob download → Read it from Downloads. ⚠️ **A Blob download can SILENTLY fail to land** (2026-07-14: grok yes, chatgpt/gemini no; `a.click()` throws nothing, the block is invisible) → ALWAYS `ls Downloads` afterwards; it did not land → fall back to `pre.textContent=txt; document.body.replaceChildren(pre)` (TrustedHTML-safe) → get_page_text in chunks. Clipboard paths (navigator.clipboard hangs; execCommand/Ctrl+C needs a gesture) — do not waste attempts on them.
+ - ⭐ **Field confirmation 2026-07-21 (finishing the 07-14 fan-out, 5 reports of 16–85 KB — the Blob NEVER landed once, Chrome multiple-downloads):** default straight to `get_page_text`, don't try the Blob. What we learned: (a) output over 50 KB is persisted BY THE HARNESS itself into `tool-results/toolu_*.json` on disk → you read it with Read and burn no context; under 50 KB arrives in-band; (b) the hard 50000-character-per-pass cap is worked around by shifting the window of visible text (padding / swapping nodes) + stitching two slices on an overlap of the last ~300 characters — that is how a 77k report was assembled; (c) the clipboard does not merely "hang", it returns the OLD contents of the operator's buffer = a false success, so always check the length and the first words; (d) **searching for a chat in Grok by title** is not a UI job (Ctrl+K is dead, the consent banner eats clicks) but a same-origin `fetch('/rest/app-chat/conversations?pageSize=50',{credentials:'include'})` → `{conversations:[{conversationId,title}]}`; (e) **Gemini is an SPA**: a fresh `navigate` to the chat URL loads the report more reliably than a synthetic click in the sidebar (the sidebar lazily renders empty text); (f) returning raw chat titles out of JS trips the content filter (`BLOCKED: Cookie/query string`) → return a short status token, not the data.
+ - ⭐ **Field confirmation, the EVENING of 2026-07-21 (collecting HUB-02):** (a) **your OWN button injected into the page does not bypass the gesture requirement** — a synthetic/coordinate click on it does not count as a user gesture and the blob still never downloads (the onclick counter = 0; don't reinvent this); (b) **extension clicks and keystrokes may not reach the page at all** (an unfocused window): the symptom is Send being pressed while the input field does not clear; the cure is a programmatic `document.querySelector('button[data-testid="send-button"]').click()` from JS, which React accepts as genuine (verified: the submit went through, the composer emptied); (c) a large text out of the DOM — first into a stash `window.__x`, look for the offsets in a second call, and slice it in Python from the persisted `tool-results\`; (d) selecting a node with Range+addRange and pressing Ctrl+C on top leaves the clipboard EMPTY (not to be confused with "the old contents": both happen — which is why you always verify with `Get-Clipboard`).
+ - ⚠️ **A vendor may REFUSE to answer** (Gemini, on an anti-ban outreach topic — it judged that to be circumventing protections). A refusal is a valid result: save it verbatim into `_originals` as a normal file, status `collected`, and in the Decision Memo state explicitly "no consensus, the base is N vendors" instead of passing a single vendor off as a fan-out.
- ## Шаг 4 — синтез-консенсус (Alpha Protocol step 4)
- Прочитать все собранные отчёты → таблица «сошлись / разошлись / уникальное у каждого» → Decision Memo (проблема · знания · DR · варианты · риски · рекомендация). Гетеро-принцип: расхождения НЕ сглаживать — показать Антону как развилки. Memo → `02-Decisions/` (если решение) или отчёт в чат. Леджер закрыть (`status: collected`).
+ ## Step 4 — the synthesis consensus (Alpha Protocol step 4)
+ Read all the collected reports → a table of "agreed / disagreed / unique to each" → a Decision Memo (problem · what we know · the DR · options · risks · recommendation). The heterogeneous principle: do NOT smooth over the disagreements — show them to the owner as forks. The memo goes to `02-Decisions/` (if it is a decision) or into the chat as a report. Close the ledger (`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 "<почему не берём и что изменит решение>"`
+ ⭐ **Step 5 — CLOSE THE RECONNAISSANCE (the owner, 07-27, mandatory).** `synthesized` is not the finish: a report was written, but the system did not change. Every DR is driven to one of two terminal statuses, and both require a `--note`:
+ - `dr_registry.py update <ID> --status applied --note "<what actually changed: a Decision Memo / a production edit / a new routine>"`
+ - `dr_registry.py update <ID> --status parked --note "<why we're not taking it and what would change the decision>"`
- `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.
+ `parked` is a legal and honest ending, not a defeat ([[gate-implement-critical-only]]: not everything researched must be implemented). The gate in `dr_registry.py` v3.3 rejects an attempt with no reason (exit 1). Why the rule exists: on 07-27 the registry had 184 of 246 researches hanging at `synthesized`, while only ~20 reached `02-Decisions` — there was no way to tell "this feeds the system" from "this just lies there". Canon: memory [[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]], применённое к вендорам вместо дисков.
+ ## ⛔ FIELD DATA FROM THE NIGHT OF 2026-07-26 (batch ZB-01…ZB-05, laptop) — read before launching
+ 1. **🔴 ChatGPT Deep Research = `dead` as of 07-26, the channel is excluded from the fan-out.** Three independent confirmations in one night: ZB-01 had two consecutive runs of "Research completed in 6m · **0 citations · 0 searches**" (the second one already AFTER an explicit follow-up "at least 20 searches / 20 sources" in the body), plus the same symptom on ZB-05 in a parallel session. The prompt arrived in full, the Deep research chip was on, the run started and "thought" for 6 minutes — it simply DID NOT SEARCH, handing back a pretty table from the model's memory. **Not a paste defect on our side.** Before putting ChatGPT back into the fan-out — do one probe run and read the counter; `0 searches` → `dead`, we go with 2 vendors and write that explicitly in the synthesis. Don't burn more than two Retries (a third Retry only cures `Error in message stream`, not an empty search).
+ 2. **🔑 Gemini: enter ONLY by account name, the `u/N` index is NOT STABLE.** ⛔ Correction 07-27 (supersedes "always `u/7`"): `https://gemini.google.com/u/7/app` opened under a different account — free tier, the Flash model, an Upgrade button. Indices move between sessions; you cannot memorise "my number". **The working entrance:** `https://gemini.google.com/app?authuser=<the personal account>` (it redirects to the right `u/N` by itself). Detect the account without clicks, MANDATORY before pasting the prompt: `document.querySelector('a[aria-label*="Google Account"]').getAttribute('aria-label')` + a check of `document.body.innerText.includes('Upgrade')` (true = a free account). Without that check the report silently goes out on Flash and just looks "a bit weak". The account switcher lives in a cross-domain iframe — `find`/scrolling cannot reach it.
+ 3. **Gemini silently rolls the model back to Flash-Lite** in every new tab. Look at the selector WITH YOUR EYES before every launch; Deep research moved into "+" → **More tools** → "Deep research" (it is no longer on the first level of the menu).
+ 4. **ChatGPT: the order is "chip → prompt", NOT the other way round** (supersedes the earlier 07-20 note). The "Deep research" chip is an inline node INSIDE ProseMirror that lands at the caret position: click in the middle of the text and it splits the sentence (caught as `chipIdx:470` in the middle of a phrase). The working order: (a) enable Deep research in an EMPTY composer — the chip becomes the first node; (b) put the caret at the END (`range.selectNodeContents(ed); range.collapse(false)`); (c) the synthetic paste event — pasting into a collapsed caret replaces nothing and the chip survives. ⚠️ A repeat paste with `selectNodeContents` does NOT replace the text, it APPENDS (you get a duplicate) → clean it only with real keystrokes `ctrl+a` + `Delete`.
+ 5. **Gemini collection: `querySelector('.markdown-main-panel')` takes the FIRST panel = the research plan, not the report.** You will save 1.7 KB of plan instead of 33.8 KB of report and never notice. The right way: anchor on the report's heading → `h2('<the plan heading>').closest('.markdown-main-panel').innerText`.
+ 6. **Getting a large text out:** `javascript_tool` truncates output at ~1000-1500 characters. The only working path is to stash it in `window.__R`, IMMEDIATELY replace the body with a `<pre>` and IMMEDIATELY call `get_page_text` (cap ~50k; a 33.8k report went through in one pass). Replacing the body breaks the page → `window.__R` is lost on a reload, so the order cannot be changed. Don't try the Blob download (per the 07-21 field notes: it does not land).
+ 7. **Press "Start research" TWICE, with a fresh look between:** the first `find` locates the button, but the click arrives before it is mounted. A second `find` gives a new ref and the second click works. Proof of the start is the canvas "Starting research…" / "Great, you can close this chat", not the fact that you clicked.
+ 8. **🔁 DEDUP — at EVERY vendor, not only in the registry.** The 03:0x incident: the registry showed ZB-03 = `issued`, the dedup over Grok's history came back "clean" (a similar chat turned out to be from 22:49 UTC = BEFORE the batch's prompts were created) → I launched it. But Gemini's Recents already had its own `DR26-07-26-ZB-03` from a parallel session → one wasted Gemini DR run. The registry = the first filter, the history of EVERY vendor you send to = the second, mandatory one. This is [[check-all-places-not-one]] applied to vendors instead of disks.
- 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 и начинаешь «чинить» целый промпт.
+ 9. **The root ChatGPT composer is SHARED across all tabs — your own draft follows you around.** 07-27: I opened a second tab for ZB-04 — ZB-03 from the first tab was sitting there; the paste event APPENDED (8303 characters instead of 4175), and `execCommand selectAll+delete` cleared it visually, but ProseMirror restored the state and appended again (12450). The only cure is a real keyboard: click into the composer → `ctrl+a` → `Delete` → verify `innerText.length===0` → and only then paste.
+ 10. **`ctrl+a`+`Delete` also removes the MODE CHIP** (Web search / Deep research) — the run goes out with no search, and that is invisible in the prompt text. The order for ChatGPT: clear → paste the prompt → **turn the chip back on** → verify → Send. Also: the chip's text lands in the composer's `innerText` sometimes as the prefix `Web search\n` and sometimes as the suffix `\nWeb search` → when checking the length, strip it from BOTH ends, otherwise you get a false mismatch and start "fixing" a perfectly good prompt.
- ## ⭐ ПОЛЕ 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) ДО вывода «разлогинен, зовите Антона».
+ ## ⭐ FIELD NOTES 2026-07-28 (ZB-04-2349, laptop) — prompt transport and report collection solved
+ 1. **🔑 PROMPT TRANSPORT = `window.name`, not inline in javascript_tool.** A 12 KB prompt inlined for three vendors = ~37 KB of context plus an escaping risk. The working path, 0 tokens: `navigate` the tab to a local file holding the prompt → `window.name = await fetch(location.href).then(r=>r.text())` → `navigate` THE SAME tab to the vendor's site → `window.name` arrives intact (verified at 12,224 / 12,279 / 12,467 characters). Serving: a tiny HTTP server from the scratchpad.
+ ⚠️ **The exception is Gemini:** COOP on `google.com` breaks the browsing context, and navigating AWAY from gemini to localhost zeroes `window.name`. The reverse direction (localhost → gemini) works.
+ 2. **🔑 REPORT COLLECTION = a POST to the local server, so the text never enters my context.** The same trick in reverse: inside the vendor's chat stash the text in `window.name` → `navigate` to `http://127.0.0.1:<port>/sink` → from there `fetch('/save?name=raw-<vendor>.txt',{method:'POST',body:window.name})`. The server writes the file, and then I check completeness with Python (sections, URL count) for pennies. Reports of 16 KB / 34 KB / 83 KB were collected that way.
+ ⚠️ **For Gemini** (COOP kills window.name) the **URL fragment** works: `location.href='http://127.0.0.1:<port>/sink#'+encodeURIComponent(txt)` → on the sink page `decodeURIComponent(location.hash.slice(1))` → POST. The fragment is never sent to the server, so privacy is intact.
+ 3. **What does NOT work, don't waste attempts:** a `fetch` from the vendor's page to 127.0.0.1 (CSP `connect-src` — both chatgpt.com and gemini.google.com block it) · submitting a form to localhost (CSP `form-action`) · a CDP `ctrl+v` (the key arrives, the paste does not) · the "Copy contents" button in the UI (it needs window focus, and the window is in the background — the clipboard silently does not change; always compare `Get-Clipboard` against a sentinel).
+ 4. **🔴 ChatGPT Deep Research — a FIFTH consecutive `0 citations · 0 searches`** (4 times on 07-26 + once on 07-28, on the work account; it "thought" for 15 minutes and produced a beautiful report from memory). Web search on the same account and the same model searches fine (90+ queries, 80+ pages, 168 URLs in the report). ⇒ **Don't spend the DR chip on this account: run the ChatGPT channel through Web search directly** + add a line to the prompt body, "list the queries you ran and the URLs you actually opened before the final report". That saves 15 minutes and one run.
+ 5. **ChatGPT DR became TWO-PHASE, like Gemini:** after Send it shows a plan card with `Edit / Cancel / Start` and an auto-start on a ~30s timer. Press the button anyway.
+ 6. **ChatGPT: `execCommand insertText` took, the synthetic paste event did NOT** — exactly the opposite of Grok (where the paste event works first time). Both need the cascade, and the method order differs per vendor. Set the mode chip in an EMPTY composer, then put the caret at the end, then paste — the chip survives.
+ 7. **Gemini: the "Start research" button stays visible and enabled after a successful click.** Proof of the start is not the button disappearing but the canvas "Great, you can close this chat" + "Researching N websites". And Gemini's `bodyLen` jumps by an order of magnitude (327,887 → 14,403 on a re-render), so it is useless as a start signal.
+ 8. **Gemini collection: take the panel with the MAXIMUM length**, not the first one. On a finished report there were three `.markdown-main-panel` elements: 1861 (the plan), 144, and 34,444 (the report). The report panel renders lazily — if it is absent, click the report card in the feed.
+ 9. **Grok Heavy: 485 sources and ZERO inline links.** The sources are handed back as a paragraph listing domains, with 2 anchors on the page. `innerText` loses nothing, but the verifiability of Grok's facts is low — check contested figures by hand (in this run Grok was wrong: it claimed there are no paid boosts, while a $159.99 Story Boost exists).
+ 10. **Two Chromes connected to the MCP.** One of them can be a clean profile, logged out everywhere. Check the account (`/api/auth/session` on ChatGPT, the `aria-label` on Gemini, the word `Sign in` in the text on Grok) BEFORE concluding "logged out, call the owner".
- 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` не доказательство: там пути файлов, не текст чанков.
+ 11. **⭐ The Blob download on chatgpt.com DOES WORK — and it is the only way to take the whole report (07-27, supersedes the 07-21 field note "the Blob does not land").** Measured: a 73,144-character report arrived as a 97,992-byte file, a second one at 60,623 characters, both on the first attempt. `get_page_text` is UNUSABLE at that size: it cuts at 50,000 characters **and cuts off exactly the tail — the Proof of work section**, i.e. the very evidence that the vendor searched. The order: collect the text of the last `[data-message-author-role="assistant"]` into `window.__R` → Blob + `a.click()` → **mandatory `ls Downloads`** → move it with a script, with provenance. The session's context is not spent at all — the text goes disk to disk. ⚠️ The trick of "padding it past 50 KB so that get_page_text persists it to disk" does NOT work: the tool sometimes persists and sometimes truncates inline — the behaviour is unpredictable, don't rely on it.
+ 12. **`exit 0` from `brain_embed_update.py` while the lock is held is NOT a bug and NOT a lie.** It is deliberate in the code: `busy_code = 3 if index_age_hours() > STALE_HOURS else 0` (a 26h threshold). The exit code answers "is the index stale by the clock?", NOT "did my request run?". After writing new notes those are different questions: an index that is fresh by the clock still does not contain them. ⇒ After a reindex, verify FUNCTIONALLY — query `brain_ask.py` with a phrase that exists nowhere but in the new files. The `harari ×N` counter in `_brain_e5_meta.pkl` is not proof: it holds file paths, not chunk text.
- ## Ошибки/грабли (не вошедшее в автомат)
- - ⚠️ **Фоновая/свёрнутая вкладка 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`); запуск требует живой сессии с браузером. Дыра осознана, закрывается после решения Антона по «дежурной браузер-сессии на хабе».
+ ## Errors/pitfalls (things that did not make it into the state machine)
+ - ⚠️ **A background/minimized Chrome tab (verified 2026-07-17):** viewport 0×0, the layout is frozen → synthetic JS clicks and Radix/Angular buttons (Gemini's "Start research", ChatGPT's "+" menu) do NOT fire, and `computer` clicks land in the wrong place. The cure: `tabs_create_mcp` → a new tab (it gets a layout even in a background window) → open the same conversation URL → `find` → `computer left_click ref` (CDP-trusted). The prompt is already sent by then — you only lose "press the button", not the quota.
+ - ⭐ **"started" in the ledger ≠ actually running (incident HUB-06, 07-16→17):** three vendors were marked started while in fact ONE was working. Gemini was stuck on an unpressed "Start research" button (the page held only the prompt, panel=0), and Grok was never submitted at all (the path stayed `/`, the prompt sat in the composer). A night was lost. → **the probe-after-start is mandatory and must be evidential:** the path changed to /chat/ · a progress indicator is visible · the page's volume grew. Pasting ≠ sending; sending ≠ starting. A `submitted` state without a confirmed `started` is not started.
+ - ⭐ **ChatGPT DR stops at the research plan (verified 2026-07-20, ZB-02):** the first run (~12 min, "0 citations · 0 searches") can return ONLY a research plan + an output structure, WITHOUT any real research, and finish (`finished_successfully`, end_turn). This is NOT a paste/start bug — the run really happened, it just degenerated into a plan. The cure: a follow-up in the same chat, "Proceed now: execute this plan and write the FULL final report… Do not stop at the plan" → the second run (65 min in our case) produces a full report with live URLs. When collecting: if the backend JSON's longest part starts with "Research Plan:" and the mapping holds only one widget with the plan — that is the plan, not the report; nudge it, don't save it as collected. (Gemini/Grok don't suffer from this — in Gemini the plan is a separate phase with a button.)
+ - ⚠️ **ChatGPT's DR mode chip lives INSIDE the editor (ZB-02, 07-20):** the `paste_verify` cascade (directSet/execCommand) clears the editor and ERASES the "Deep research" chip → the probe will show `chip:false`. The order: paste the prompt first, THEN turn Deep research on over it (the "+" menu → Deep research), then check the chip and Send. Otherwise an ordinary chat message flies off — the DR quota is intact but the answer is the wrong kind.
+ - ✅ **Grok, the textarea/contenteditable mirror — the ROOT CAUSE was found and cured (FLEE-03, 07-17):** Grok 4.5 = a TipTap/ProseMirror contenteditable (`div.tiptap.ProseMirror`); the visible `<textarea>` is a HIDDEN mirror. Filling the textarea (nativeSetter / value + InputEvent) returns `ok:true`, but the React/PM state does not update from the mirror → Submit never renders, Enter is a no-op (exactly what burned time on 07-10 and 07-17). **The fix in the cascade:** target `.tiptap.ProseMirror` FIRST + a synthetic paste event (`ClipboardEvent('paste',{clipboardData:DataTransfer})`) → PM adopts the text → `button[type="submit"]` appears enabled → click. Verified live on 07-17 (FLEE-03 Grok `/c/e621f761`). If the UI drifts again and the paste event stops working → a new chat + a probe, don't burn time.
+ - ⭐ **ChatGPT DR silently does not search — and a prompt does NOT cure it (2026-07-26, ZB-02 + ZB-05 independently).** The symptom: "Research completed in Xm · **0 citations · 0 searches**", a beautiful report entirely from memory. Measured: 4 runs, 2 different chats, 2 independent sessions, one Pro account; the second run of each pair went out WITH an explicit demand to search — it did not help. ⛔ The rule: **two `dead` results in a row = do not try a third time the same way**, close the channel, build the synthesis on the remaining vendors and state explicitly "the base is N vendors". The discriminating test (cheap, run it BEFORE drawing conclusions about the cause): the same question in an ordinary chat with the **Web search** tool — that goes down a different code path. If Web search works fine (in our case: 24+ queries, "Searched N websites" blocks) → it is the DR path that is broken, and 🤔 most likely the DR quota is exhausted and the vendor degrades silently instead of erroring honestly. A side benefit: Web search + a hard prompt ("list the queries and the URLs you opened before answering") produces a usable, citable report — a working workaround while DR is down.
+ - ⭐ **The root composer at `chatgpt.com/` is shared per account and parallel sessions tear it apart (2026-07-26).** The draft syncs between sessions: in one run someone else's `ZB-05` and `ZB-06` passed through it, a neighbouring session rolled my pastes back with its own React state, and once my line stuck to the tail of SOMEONE ELSE'S prompt (it could not be cleaned — the edits would not hold). ⛔ The rule: when working in parallel, **do not touch the root composer**; run inside YOUR OWN `/c/<id>` (the composer is per-chat and uncontested), and create a new chat only when the root one is empty. Always read the composer before pasting: non-empty + someone else's ID = stop, not "I'll overwrite it".
+ - A logout in the middle of the research → the report may be lost: after logging back in, check the vendor's chat history, a DR is usually saved there.
+ - A long report gets truncated in get_page_text → scroll/expand ("Show more") before reading; compare the end of the text with the end of the report.
+ - ⛔ Never set up a PAID API path as a "fallback" without approval ([[prefer-included-limits-before-paid-api]]).
+ - The same prompt goes to every vendor VERBATIM, except the deliberate platform block §2/§3/§4 (otherwise the consensus is dirty).
+ - ⚠️ **An account can flag automation:** on the FLEE-01 run ChatGPT showed a "Suspicious activity detected" banner when a DR was started from automation (it did NOT block it, the research ran). That is exactly the failure mode both DR vendors predicted. Saw the banner → don't panic and don't hammer retries; note it in the ledger and continue. If it repeats systematically → `drift_suspected`, report to the owner.
+ - ⚠️ **Nobody publishes session longevity** (the DR consensus) → treat a forced re-auth as INEVITABLE, don't build on a timer. `needs_reauth` = a first-class state + an out-of-band ping to the human (the approval channel).
+ - ⏳ **A fully unattended LAUNCH** is the next build step (the architecture is known from the DR: a ledger FSM + a dedicated Firefox profile + cron/systemd; start with ChatGPT+Gemini). For now only COLLECTION is unattended (the nightly `dr_collect.py`); launching requires a live session with a browser. The hole is acknowledged and closes after the owner decides on a "standby browser session on the hub".
- ## /tt — как проверить v2 (после прихода FLEE-01 или при правке)
- Не гонять живой DR ради теста (жжёт квоту). Проверять по частям: (1) probe-логика — на уже открытой вкладке проверить, что детект режима+длины работает БЕЗ Send; (2) извлечение — на УЖЕ собранном прошлом DR (backend JSON / innerText) прогнать парсер, сверить с сохранённым `_originals`; (3) леджер+dr_collect — прогнать на существующем DR-ID. Живой end-to-end — только когда реально нужен ресёрч.
+ ## /tt — how to test v2 (after FLEE-01 lands, or when editing)
+ Don't run a live DR just to test (it burns quota). Test in parts: (1) the probe logic — on an already-open tab, verify that mode + length detection works WITHOUT pressing Send; (2) extraction — run the parser over an ALREADY collected past DR (backend JSON / innerText) and compare against the saved `_originals`; (3) the ledger + dr_collect — run them against an existing DR-ID. A live end-to-end run only when the research is genuinely needed.
---
<!-- CONTACT-FOOTER -->
## About & contact
Built and battle-tested at **Palo Alto AI Research Lab** — a fleet of Claude Code machines
running 24/7 as a second brain and synthetic cofounder. Every skill here survived real
production use before publication.
- 📦 All 101 skills: https://github.com/tonydzi/second-brain-starter-kit
- 👤 Author: **Anton Dziatkovskii** — Telegram [@tonydzi](https://t.me/tonydzi) · WhatsApp [+1 341 222 9178](https://wa.me/13412229178) · X [@Tony_Stef_](https://x.com/Tony_Stef_)
- 🧪 **Engineers: want to test-drive this setup?** Message me — I hand out free starter seeds to engineers who test and report back. Custom skill requests welcome.