diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 6723f72..e533b73 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -26,6 +26,13 @@ jobs: pip install ruff==0.15.1 ruff check . + # tests/test_report_export.py and test_mermaid_figures.py exercise build_report's + # error handling, which only gets reached once pandoc exists — without it every one + # of them dies on "pandoc не найден" and the export path goes unverified. They + # passed on the author's Mac and had never run here. + - name: Install pandoc (report export tests) + run: sudo apt-get update -qq && sudo apt-get install -y -qq pandoc + - name: Run unit tests run: python -m pytest tests/ -q diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c914d02..4caf31f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,7 +39,7 @@ Need a stat sources file for an industry not covered (e.g., aerospace, mining, f ### 2-4 hours — Add a new report block -The block library has 105 blocks but specific use cases might need more. +The block library has 106 blocks but specific use cases might need more. **Example:** You want a `decision-tree` block in `compare.md`. diff --git a/QUICKSTART.md b/QUICKSTART.md index 92604a5..054d9ac 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -46,7 +46,7 @@ can audit. ## Next steps -- Full methodology: [`SKILL.md`](SKILL.md) — the 12-phase workflow. -- The catalog: [`references/`](references/) — 105 report +- Full methodology: [`SKILL.md`](SKILL.md) — the 13-phase workflow. +- The catalog: [`references/`](references/) — 106 report blocks, 6 genres. - Want to add sources or APIs? [`CONTRIBUTING.md`](CONTRIBUTING.md). diff --git a/README.md b/README.md index 56efd25..53db94a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Claude: ✓ Reframed your question (3 hypotheses) + decision spec: what you'll ## What this is -A [Claude Code skill](https://docs.anthropic.com/claude/docs/skills) that turns **"research this topic"** into a **12-phase pipeline** with hypothesis testing, parallel sub-agent search, source triangulation, and adversarial review. +A [Claude Code skill](https://docs.anthropic.com/claude/docs/skills) that turns **"research this topic"** into a **13-phase pipeline** with hypothesis testing, parallel sub-agent search, source triangulation, and adversarial review. The output is a folder you can return to in a month. Every claim traces to a specific source file. The plan documents *why* you made every choice. No re-research needed. @@ -122,7 +122,7 @@ zip -r ../deepdive.skill . -x ".*" -x "*.zip"
For other LLMs (Codex, Gemini, local) -The 12-phase methodology is portable. Load `SKILL.md` + `references/*.md` into the LLM's context manually. Skip the sub-agent parts and use separate chat sessions per subtopic. +The 13-phase methodology is portable. Load `SKILL.md` + `references/*.md` into the LLM's context manually. Skip the sub-agent parts and use separate chat sessions per subtopic. [Full instructions →](#use-with-other-llms-codex-gemini-etc) @@ -132,7 +132,7 @@ The 12-phase methodology is portable. Load `SK ## How it works -The skill runs **12 phases** in order: +The skill runs **13 phases** in order: | Phase | Name | What happens | |:---:|:---|:---| @@ -145,6 +145,7 @@ The skill runs **12 phases** in order: | **4** | **Search** | sonnet / medium | | **5** | **Claims-ledger + triangulation** | haiku / low | | **5.5** | **Evidence filter** | sonnet / low | +| **5.7** | **Wiki reconcile** | sonnet / low | | **6** | **Synthesis + multi-angle red team** | opus / high | | **6.5** | **Verify** | haiku / low | | **7** | **Refresh targets** | sonnet / medium | @@ -188,7 +189,7 @@ Want to compare models head-to-head? The [eval harness](eval/README.md) scores a -### 105 Report Blocks +### 106 Report Blocks 10 categories: **FRAME** · **EXPLAIN** · **COMPARE** · **MAP** · **VALIDATE** · **ANALYZE** · **CLOSE** · **PEOPLE** · **NUMBERS** · **CONTEXT** @@ -460,9 +461,9 @@ The file-per-source structure is the key **reuse** mechanism. A single research It's **structured methodology + curated catalog + reusable templates + automation**. -- The 12-phase workflow forces discipline +- The 13-phase workflow forces discipline - 460+ stat sources catalog is curated knowledge -- 105 reusable blocks compose any report shape +- 106 reusable blocks compose any report shape - `scripts/validate_phases.py` machine-checks phase completeness, not just style - A decision spec + mandatory walkthrough (phase 8) ties every research to an actual action, not just a document - Weekly auto-validation keeps the catalog alive @@ -500,8 +501,8 @@ The methodology is portable. ~70% of content is LLM-agnostic markdown templates. |:---|:---:|:---:| | `SKILL.md` frontmatter | ✓ | — | | Sub-agent `Explore` type | ✓ | — | -| 12-phase workflow | — | ✓ | -| 105 report blocks | — | ✓ | +| 13-phase workflow | — | ✓ | +| 106 report blocks | — | ✓ | | 29 search channels | — | ✓ | | 460+ stat sources | — | ✓ | @@ -526,13 +527,13 @@ The methodology is portable. ~70% of content is LLM-agnostic markdown templates.

На русском

-**Deepdive** — скилл для [Claude Code](https://claude.com/claude-code), превращающий «загугли это» в дисциплинированный 12-фазный процесс. +**Deepdive** — скилл для [Claude Code](https://claude.com/claude-code), превращающий «загугли это» в дисциплинированный 13-фазный процесс. ### Что внутри -- **12 фаз workflow**: Reframing → Genre & block selection → Plan → Capability Discovery → Plan-review gate → Поиск → Claims-ledger + триангуляция → Evidence-фильтр → Синтез + multi-angle red team → Verify → Refresh targets → Decision walkthrough +- **13 фаз workflow**: Reframing → Genre & block selection → Plan → Capability Discovery → Plan-review gate → Поиск → Claims-ledger + триангуляция → Evidence-фильтр → Сверка с вики → Синтез + multi-angle red team → Verify → Refresh targets → Decision walkthrough - **6 жанров отчёта**: qa / explainer / decision / landscape / validation / custom -- **105 блоков** в 10 категориях — переиспользуемые секции с шаблонами и анти-паттернами +- **106 блоков** в 10 категориях — переиспользуемые секции с шаблонами и анти-паттернами - **29 каналов поиска** с paywall fallback протоколом (включая api-direct) - **460+ статистических источников** в 14 cross-industry + 19 отраслевых категориях - **47+ API endpoints** для programmatic доступа (free no-auth приоритетны) diff --git a/SKILL.md b/SKILL.md index f605060..9bafc23 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,11 +1,11 @@ --- name: deepdive -description: Meta-research под вопрос или решение. Веб-поиск, академические источники, Q&A отчёт; каждый источник — отдельный файл с цитатами и метаданными для повторного использования. Использовать когда нужна основа под решение, для деск-ресёрча, валидации гипотезы или чтобы понять как устроен X. Триггеры — "deep research", "глубокое исследование", "проведи ресёрч", "сделай ресёрч", "изучи тему", "разбери тему", "исследуй", "копни глубоко", "deep dive", "ресёрчни". +description: "Meta-research под вопрос или решение: веб-поиск, источники, Q&A отчёт с цитатами по файлам для повторного использования. Использовать для деск-ресёрча, валидации гипотезы, «как устроен X». Триггеры: «deep research», «сделай ресёрч», «исследуй», «копни глубоко», «ресёрчни»." --- # Deepdive — meta-research с дисциплиной -Многошаговое исследование под вопрос или решение. Каждый источник = файл, отчёт построен как Q&A, тезисы атомарны и пере-используемы. +Многошаговое исследование под вопрос или решение. Источник = файл, отчёт как Q&A, тезисы атомарны и пере-используемы. ## Когда применять @@ -21,82 +21,42 @@ description: Meta-research под вопрос или решение. Веб-п | medium | 12–18 | 2–3 | нетривиальная тема, среднее решение | | deep | 25–35+ | 4–5 | high-stakes решение, стратегия | -Объяви режим в начале с обоснованием. После Genre+Plan объяви **model routing** одной строкой (какие фазы на какой модели + estimated cost + как перебить: «всё на opus» / «cheap mode»). Детали — `references/model_routing.md`. +Объяви режим в начале с обоснованием. После Genre+Plan объяви **model routing** одной строкой (фазы по моделям + estimated cost + как перебить: «всё на opus» / «cheap mode»). Детали — `model_routing.md`. ## Перед стартом — discover existing -До reframing (опционально — нет файлов, иди дальше): определи целевую папку → если она есть, перечисли содержимое, похожий slug ⇒ спроси «это update?» → прочитай `CLAUDE.md`/`CLAUDE.local.md` и `memory/MEMORY.md`, учти в reframing. Цель: не дублировать сделанное. +До reframing (опционально — нет файлов, иди дальше): определи целевую папку → есть — перечисли содержимое, похожий slug ⇒ спроси «это update?» → прочитай `CLAUDE.md`/`CLAUDE.local.md` и `memory/MEMORY.md`, учти в reframing. Цель: не дублировать сделанное. -**Куда сохранять** (не хардкодь): (1) research-папка из CLAUDE.md или существующая `research/` · `06_Деск-ресёрч/` · `docs/research/` · `notes/research/`; (2) иначе по типу проекта — есть манифест (`pyproject.toml`/`package.json`/`Cargo.toml`/`go.mod`) → `research/`, только документы → `06_Деск-ресёрч/`; (3) не git-репо или пусто → `~/deep-research//`. Путь покажи ОДИН раз, дальше пиши молча. +**Плюс кросс-прогонная вики** — `python scripts/wiki_query.py --topic "<вопрос>"`: прошлые утверждения, уже оценённые источники (credibility не пересчитывать), открытые противоречия между прогонами. Непогашенное противоречие идёт в `plan.md` исследовательским вопросом. См. `wiki.md`. + +**Куда сохранять** (не хардкодь): (1) research-папка из CLAUDE.md или существующая `research/` · `06_Деск-ресёрч/` · `docs/research/` · `notes/research/`; (2) иначе по типу проекта — манифест (`pyproject.toml`/`package.json`/`Cargo.toml`/`go.mod`) → `research/`, только документы → `06_Деск-ресёрч/`; (3) не git-репо или пусто → `~/deep-research//`. Путь покажи ОДИН раз, дальше пиши молча. **Slug:** латиница, цифры, дефисы («Postgres logical replication vs CDC» → `postgres-replication-vs-cdc`). Неочевиден — покажи в начале фазы 2. -## Workflow — 12 фаз (1–8, включая 3.5, 3.7, 5.5, 6.5) +## Workflow — 13 фаз (1–8, включая 3.5, 3.7, 5.5, 5.7, 6.5) -Детали фаз — `references/workflow.md`, модель на фазу — `references/model_routing.md`. Здесь — что фаза обязана оставить после себя. +Детали фаз — `workflow.md`, модель на фазу — `model_routing.md`. Здесь — что фаза обязана оставить после себя. -1. **Reframing** [`opus`/high] — переписать вопрос; собрать **Decision Spec** (решение глагол+объект+срок / потребитель→его следующий шаг / ≥1 if-then вилка «покажет X → делаю A»; ни одной вилки ⇒ честный даунгрейд в shallow); 2–4 опровергаемые гипотезы; для medium/deep — персоны охвата (STORM) и router по типу вопроса (фактологический→плоско / многошаговый→least-to-most / реляционный→графы / сравнительный→матрица). См. `question_reframing.md`. +1. **Reframing** [`opus`/high] — переписать вопрос; **Decision Spec** (решение глагол+объект+срок / потребитель→его следующий шаг / ≥1 if-then вилка «покажет X → делаю A»; ни одной вилки ⇒ честный даунгрейд в shallow); 2–4 опровергаемые гипотезы; medium/deep — персоны охвата (STORM) и router по типу вопроса. См. `question_reframing.md`. 2. **Genre & blocks** [`sonnet`/medium] — жанр (qa/explainer/decision/landscape/validation/custom) + набор блоков, подтвердить одной строкой. См. `genres.md`, `blocks/INDEX.md`. -3. **Plan** [`opus`/medium] — `plan.md`: HEADER → SCOPE → STRUCTURE → EXECUTION → TRACKING (user context, time-box, acceptance criteria, discovered existing, glossary, жанр+блоки, гипотезы, risk register, subtopic↔blocks mapping с least-to-most уровнями для многошаговых вопросов, sourcing strategy, opposition queries, stop-criteria, notes). +3. **Plan** [`opus`/medium] — `plan.md` по шаблону §0–16 из `workflow.md`: HEADER → SCOPE → STRUCTURE → EXECUTION → TRACKING. Несущее: acceptance criteria, гипотезы, risk register, subtopic↔blocks mapping (least-to-most для многошаговых вопросов), sourcing strategy §12, opposition queries, stop-criteria. 3.5. **Capability Discovery** [`sonnet`/low] (deep — обязательна) — audit env vars, подтемы → доступные API, fallback на awesome-lists. См. `capability_discovery.md`. -3.7. **Plan-review gate** [`sonnet`/low] (shallow — skip) — единственная human-in-the-loop точка ПЕРЕД дорогой Фазой 4: показать сжатый план (вопрос, решение, жанр, гипотезы, каналы, стоп-критерий, routing). **deep — ЖДАТЬ явного «Ок»; medium — soft.** Включает **скаут-пасс** (deep — рекомендуется): 3–4 `Explore`-агента на `haiku` ищут не источники, а непокрытые подвопросы; выход — правки `plan.md`, ноль записей в `sources/`. См. `plan_gate.md`. -4. **Поиск** [main `sonnet`/medium; sub-agents: `haiku` web/api, `sonnet` academic/long-source] — (4.0) Source Dispatch по матрице → `plan.md` §12; количественный подвопрос ⇒ primary-канал registry/API. (4.1) Launch: medium/deep — `general-purpose` суб-агенты параллельно, каждому свой диапазон id (`s01-s09`, `s10-s19`…) и своя ось поиска, не только подтема; shallow — главный поток. (4.2) Fetch, дедуп с замером `overlap_rate`. (4.3) Агент сам пишет `sources/NN_slug.md`, в главный поток — только index-строки. После раунда 1 — snowball (backward/forward цитирования). Loop: goal-check (haiku) → bounded deviation с query-мутациями → circuit breaker (2 раунда без нового ⇒ стоп, остаток в Open Questions). **Окно раунда пересобирается, не накапливается** (medium/deep): перед следующим раундом ПЕРЕЗАПИСАТЬ `state.md` (`## Known` статусами со ссылками · `## Gaps` · `## Next`, ≤6 КБ) и планировать по нему, не по транскрипту; агенту идёт только его дыра из `Gaps`. См. `source_dispatch.md`, `subagents_v2.md`. -5. **Claims-ledger + триангуляция** [`haiku`/low] — `claims.csv` (claim_id, sources, source_types, roots, paths, status, confidence, primary_source, source_caveat, dissent, as_of). `triangulated` ⟺ ≥3 источника И ≥2 типа И ≥2 корня (`root:`) И ≥2 пути (`discovery_path:`); иначе `single-type`/`single-root`/`single-path`, потолок medium. Primary-first: без primary — потолок medium. Caveat (`vendor`/`self-reported`/`disputed:sNN`) — потолок medium, `disputed` без арбитра → low. **Защита меньшинства:** непогашенный `dissent` от `Primary`/`credibility ≥ 4` ⇒ `contested` независимо от большинства, обе позиции в отчёт с основанием выбора. Loop: gap-волна на не-triangulated, max 2 круга, иначе `data-insufficient`. См. `source_scoring.md`. -5.5. **Evidence-фильтр: relevance × authority** [`sonnet`/low] (medium/deep — обязательно) — фильтр на ВХОДЕ синтеза. **Relevance:** по паре (claim, source) классификатор Correct/Ambiguous/Incorrect по дословным цитатам → relevant-only цитаты в `evidence/CN.md`; claim без единого relevant-источника → `data-insufficient` или до-поиск. **Authority** (несущие пары: claim в memo/F1/F9, ИЛИ с числом, ИЛИ источник единственный корень, ИЛИ `caveat` ≠ `-`): «вправе ли ЭТОТ источник утверждать ЭТО» по чек-листу признаков → `qualified`/`unqualified-for-this-claim`/`unknown` → `.verify/authority.json`. **`unknown` — карантин:** не единственная опора, не `high`. `sources/NN.md` не трогаются. См. `evidence_filter.md`. -6. **Синтез + multi-angle red team** [red team `opus`/high для deep, `sonnet`/high для medium] — `outline.md` (таблица `section | block | claims` из `plan.md` §8/§11 + фактического `claims.csv`) → собрать `_.md` **секция за секцией по outline**, под каждую только её `claim_id` и её `evidence/CN.md`, не весь пул → числа объявить в `numbers.csv` (`verbatim`/`derived`/`share`; у `derived` — `formula`+`inputs`) → финал «it depends» запрещён (рекомендация однозначная или условная по вилкам) → claim ledger → параллельные враждебные роли как `general-purpose`: R1 Skeptic, R2 Contrarian, R3 Gap-hunter, R4 Исполнитель (исполняет решение только по отчёту + hedge-линт), R5 Адвокат меньшинства (защищает одинокий источник, директива «консенсус не аргумент») → триаж severity → ОДИН раунд ремедиации HIGH → **`memo.md`** (рекомендация, вилки, 3 числа с [sNN]+`as_of`, риск, next actions, строка `Урезано:` — сработавший circuit breaker или даунгрейд объявляется вслух; иначе `Урезано: —`) → финал. Finder ≠ fixer. Гейт: shallow=R1 инлайн, medium=R1+R2+R4 (+R5 при `dissent`), deep=все пять. Ценность даёт разность ролей и изоляция контекстов, не класс модели. См. `adversarial_pass.md`, `synthesis_outline.md`, `source_scoring.md` (`numbers.csv`). -6.5. **Verify** [`haiku`/low] (medium/deep — обязательно) — четыре оси: **liveness** (`check_citations.py` → `.verify/citations.json`); **faithfulness** (entailment claim⊨цитата по парам из `evidence/CN.md` → SUPPORTED/PARTIAL/UNSUPPORTED → `.verify/faithfulness.json`); **qualifier preservation** (утверждения F1/`memo.md`/Z12 против строк `claims.csv` → PRESERVED/BROADENED/SCOPE-DROPPED/UNTRACEABLE → `.verify/qualifiers.json`); **construct provenance** (именованные фреймворки/таксономии/«законы»/термины отчёта против `evidence/`+`sources/` → `sourced`/`author-construct`/`unsourced` → `.verify/constructs.json`; `unsourced` в `memo.md`/F1/F9 блокирует finish — у выдуманного имени нет `claim_id`, поэтому три первых оси его не видят). Битое чинится re-search'ем, overclaim смягчается, неподтверждённое уходит в Open Questions, снятая оговорка возвращается, выдуманное имя получает источник либо метку «наша рамка» — дрейфует отчёт, не ledger. Header F10 несёт все четыре оси плюс строку независимости источников; без него отчёт не «готов». См. `runtime_verification.md`. -7. **Refresh targets** [`sonnet`/medium] (medium/deep) — entities/numbers/hypotheses/topic-markers из отчёта в `refresh_targets.md`: точка входа для будущих `update`. Блок Z11 в `blocks/close.md`. +3.7. **Plan-review gate** [`sonnet`/low] (shallow — skip) — единственная human-in-the-loop точка ПЕРЕД дорогой Фазой 4: показать сжатый план (вопрос, решение, жанр, гипотезы, каналы, стоп-критерий, routing). **deep — ЖДАТЬ явного «Ок»; medium — soft.** Плюс **скаут-пасс** (deep — рекомендуется): 3–4 `Explore` на `haiku` ищут непокрытые подвопросы, а не источники; выход — правки `plan.md`, ноль записей в `sources/`. См. `plan_gate.md`. +4. **Поиск** [main `sonnet`/medium; sub-agents: `haiku` web/api, `sonnet` academic/long-source] — (4.0) Source Dispatch по матрице → `plan.md` §12; количественный подвопрос ⇒ primary-канал registry/API. (4.1) medium/deep — `general-purpose` суб-агенты параллельно, каждому свой диапазон id (`s01-s09`, `s10-s19`…) и своя ось поиска, не только подтема; shallow — главный поток. (4.2) Fetch, дедуп с замером `overlap_rate`. (4.3) Агент сам пишет `sources/NN_slug.md`, в главный поток — только index-строки. После раунда 1 — snowball. Loop: goal-check → bounded deviation → circuit breaker (2 раунда без нового ⇒ стоп, остаток в Open Questions). **Окно раунда пересобирается, не накапливается** (medium/deep): `state.md` ПЕРЕЗАПИСЫВАЕТСЯ перед каждым раундом (`## Known` статусами со ссылками · `## Gaps` · `## Next`, ≤6 КБ), планирование по нему, а не по транскрипту. См. `source_dispatch.md`, `subagents_v2.md`. +5. **Claims-ledger + триангуляция** [`haiku`/low] — `claims.csv` (схема колонок — `source_scoring.md`). `triangulated` ⟺ ≥3 источника И ≥2 типа И ≥2 корня (`root:`) И ≥2 пути (`discovery_path:`); иначе `single-type`/`single-root`/`single-path`, потолок medium. Без primary — потолок medium; caveat (`vendor`/`self-reported`/`disputed:sNN`) — потолок medium, `disputed` без арбитра → low. **Защита меньшинства:** непогашенный `dissent` от `Primary`/`credibility ≥ 4` ⇒ `contested` независимо от большинства, обе позиции в отчёт. Gap-волна на не-triangulated, max 2 круга, иначе `data-insufficient`. См. `source_scoring.md`. +5.5. **Evidence-фильтр: relevance × authority** [`sonnet`/low] (medium/deep — обязательно) — фильтр на ВХОДЕ синтеза. **Relevance:** пара (claim, source) → Correct/Ambiguous/Incorrect по дословным цитатам → relevant-only цитаты в `evidence/CN.md`; claim без relevant-источника → `data-insufficient` или до-поиск. **Authority** (несущие пары: claim в memo/F1/F9, ИЛИ с числом, ИЛИ источник единственный корень, ИЛИ `caveat` ≠ `-`): «вправе ли ЭТОТ источник утверждать ЭТО» → `qualified`/`unqualified-for-this-claim`/`unknown` → `.verify/authority.json`. **`unknown` — карантин:** не единственная опора, не `high`. См. `evidence_filter.md`. +5.7. **Сверка с вики** [`sonnet`/low] (medium/deep — обязательно) — `claims.csv` прогона против кросс-прогонной вики, **до синтеза**: расхождение с прошлым ресёрчем обязано попасть в отчёт, заметить его в Фазе 7 значит заметить поздно. `wiki_pair.py build` собирает пары и сам закрывает всё, что не требует суждения; остаток идёт в `.verify/wiki_pairs.json` → вердикт из четырёх (`same-claim-agree`/`same-claim-conflict`/`different-claim`/`unknown`) → `wiki_pair.py record`. **`unknown` — карантин**, не конфликт. Подтверждённый конфликт = обе позиции в отчёт, потолок `medium`, без арбитра `contested`. Срез по `MAX_ADJUDICATED` называть вслух. Пороги прескрина и правила `record` — `wiki.md`. +6. **Синтез + multi-angle red team** [red team `opus`/high для deep, `sonnet`/high для medium] — `outline.md` (`section | block | claims` из `plan.md` §8/§11 и фактического `claims.csv`) → собрать `_.md` **секция за секцией по outline**, под каждую только её `claim_id` и её `evidence/CN.md`, не весь пул → числа в `numbers.csv` (`verbatim`/`derived`/`share`; у `derived` — `formula`+`inputs`) → финал «it depends» запрещён (рекомендация однозначная или условная по вилкам) → claim ledger → враждебные роли параллельно как `general-purpose`: R1 Skeptic, R2 Contrarian, R3 Gap-hunter, R4 Исполнитель, R5 Адвокат меньшинства → триаж severity → ОДИН раунд ремедиации HIGH → **`memo.md`** (рекомендация, вилки, 3 числа с [sNN]+`as_of`, риск, next actions, строка `Урезано:` — сработавший circuit breaker или даунгрейд вслух; иначе `Урезано: —`) → финал. Finder ≠ fixer. Гейт: shallow=R1 инлайн, medium=R1+R2+R4 (+R5 при `dissent`), deep=все пять. См. `adversarial_pass.md`, `synthesis_outline.md`, `source_scoring.md` (`numbers.csv`). +6.5. **Verify** [`haiku`/low] (medium/deep — обязательно) — четыре оси, вердикты в `.verify/<ось>.json`: **liveness** (`check_citations.py`); **faithfulness** (entailment claim⊨цитата по парам из `evidence/CN.md` → SUPPORTED/PARTIAL/UNSUPPORTED); **qualifier preservation** (F1/`memo.md`/Z12 против строк `claims.csv` → PRESERVED/BROADENED/SCOPE-DROPPED/UNTRACEABLE); **construct provenance** (именованные фреймворки/«законы»/термины против `evidence/`+`sources/` → `sourced`/`author-construct`/`unsourced`; `unsourced` в `memo.md`/F1/F9 блокирует finish). Чинится отчёт, не ledger. Header F10 несёт все четыре оси плюс строку независимости источников; без него отчёт не «готов». См. `runtime_verification.md`. +6.9. **Экспорт отчёта** [`haiku`/low] (medium/deep) — `uv run scripts/build_report.py `: HTML + PDF + DOCX из одного источника. Фигуры — только из `numbers.csv`, ```` ```mermaid ```` из E13/M9 — в «Схема N» через `mmdc`, `[sNN]` резолвятся в приложение из `sources.csv`. Битая ссылка или потерянная сноска роняют сборку. `memo.md` остаётся отдельной страницей. См. `references/report_export.md`. +7. **Refresh targets + постобработка роя** [`sonnet`/medium] (medium/deep) — entities/numbers/hypotheses/topic-markers из отчёта в `refresh_targets.md`: точка входа для будущих `update`. Блок Z11 в `blocks/close.md`. Затем — четыре шага сбора наблюдений роя (`collect_observations.py` → `update_priors.py` → `promote_candidates.py --track` → изредка `--write`): порядок и флаги — `references/swarm_postprocess.md`, читать перед первым вызовом. 8. **Decision walkthrough** [`opus`/high, главный поток] (**всегда**, в shallow — 1 вилка) — отчёт не обсуждается, а исполняется: показать `memo.md` и провести пользователя по вилкам по одной. Исходы: принято (решение + next action + дата) / `blocked` (после 1 целевой gap-волны) / `deferred`. Артефакт `application.md` (любой status) + строка в `~/.claude/research/applications_ledger.csv`. См. `decision_walkthrough.md`. -## Постобработка прогона — сбор наблюдений байесовского роя - -После Фазы 7, для medium/deep, до Фазы 8 или сразу после неё — четыре шага. Каждый использует уже существующие артефакты прогона, новых файлов писать руками не нужно. `run_id` = `` этого прогона (та же папка, что и весь остальной output structure) — использовать один и тот же slug во всех вызовах ниже. - -**1. Собрать наблюдения — по подвопросу, не одним вызовом на весь прогон.** - -Для КАЖДОГО подвопроса из `plan.md` §12 отдельный вызов, с его `qclass` и его реально запрошенными каналами (primary + secondary + fallback, если fallback реально понадобился): - -``` -python3 scripts/collect_observations.py --research-dir / --run-id \ - --requested academic=scientific-claim,data-statistical-gov=scientific-claim -``` - -Один вызов на подвопрос, а не общий список `channel=qclass` на весь прогон — `--requested` парсится в словарь по ключу-каналу: если один и тот же канал встретился в разных подвопросах с разным `qclass` в одной строке, вторая пара молча затрёт первую и наблюдение потеряется. Раздельные вызовы этой проблемы не имеют — каждый аппендит независимо. - -**2. Пересчитать приоры.** - -``` -python3 scripts/update_priors.py -``` - -Дёшево (доли секунды), звать после каждого прогона без исключений — без этого шага накопленные наблюдения не попадают в `priors.json` и следующий прогон не увидит статистику. - -**3. Зарегистрировать ad-hoc источники, ставшие полезными.** - -Источник — ad-hoc, если он найден через Discovery patterns (`source_dispatch.md`), а не из штатного каталога (`api_sources/`, `stat_sources/`, `registry/`). Для каждого такого источника, ставшего `root` или непогашенным `dissent` хотя бы одного claim в `claims.csv`: открыть его `sources/NN.md`, взять `url` и первый сегмент `discovery_path` (это канал), `qclass` — тот, что был у подвопроса в §12: - -``` -python3 scripts/promote_candidates.py --track https://api.example.org/v1 \ - --channel api-direct --qclass market-size --run-id -``` - -Источник, оказавшийся мёртвым/недоступным на момент прогона — тот же вызов с `--dead`, тем же `--run-id`. - -**4. Раз в несколько прогонов — проверить промоушен и демоушен.** - -``` -python3 scripts/promote_candidates.py --write -``` - -Печатает, что промотируется (≥3 улики в ≥3 разных прогонах, живой endpoint, приор канала не деградировал) и что предлагается к удалению (≥3 прогона подряд мёртв). Без `--write` — только печать, ничего не пишет. С `--write` создаёт файлы в `references/api_sources/promoted/` — **посмотреть `git diff`, закоммитить вручную**, скрипт коммит не делает никогда. - -Аллокатор свободного бюджета сверх обязательного минимума — читать `python3 scripts/update_priors.py --qclass ` при выборе канала сверх Primary/Secondary; подробно и с оговорками — `source_dispatch.md`, раздел «Приор при выборе канала сверх обязательного минимума». Полная механика — `docs/specs/2026-08-18-bayesian-swarm-design.md`. - ## Stop-criteria — по содержанию, не по бюджету Лимита на WebSearch/WebFetch нет. -**Стоп когда:** все гипотезы подтверждены/опровергнуты ≥3 разнотипными источниками либо помечены «данных мало» · прошёл ≥1 целевой поиск оппозиции («X criticism / counter-evidence / problems with X») и разобран · покрыты 4+ типа источников · последние 3–5 источников не дают нового. +**Стоп когда:** все гипотезы подтверждены/опровергнуты ≥3 разнотипными источниками либо помечены «данных мало» · прошёл и разобран ≥1 целевой поиск оппозиции («X criticism / counter-evidence / problems with X») · покрыты 4+ типа источников · последние 3–5 источников не дают нового. **Не стоп когда:** источники противоречат (копай за причиной) · все одного типа · есть сильный контр-аргумент без разбора · оппозицию не искали. @@ -110,81 +70,85 @@ python3 scripts/promote_candidates.py --write ├── state.md # Фаза 4 — окно раунда, ПЕРЕЗАПИСЫВАЕТСЯ каждый раунд (medium/deep) ├── sources.csv # индекс источников с оценками ├── claims.csv # Фаза 5 — claim-ledger -├── numbers.csv # Фаза 6 — реестр чисел отчёта, derived пересчитываются (medium/deep) +├── numbers.csv # Фаза 6 — реестр чисел отчёта (medium/deep) ├── outline.md # Фаза 6 — карта section → block → claim_id (medium/deep) -├── sources/NN_slug.md # один файл = один источник (метаданные + дословные цитаты) +├── figures.csv # Фаза 6.9 — фигуры, только по num_id из numbers.csv (medium/deep) +├── sources/NN_slug.md # один файл = один источник (метаданные + цитаты) ├── evidence/CN.md # Фаза 5.5 — relevant-only цитаты под claim (medium/deep) ├── findings/FN_*.md # атомарные тезисы (опц., для крупных) ├── refresh_targets.md # Фаза 7 (medium/deep) ├── memo.md # Фаза 6 — decision-меморандум (всегда) ├── application.md # Фаза 8 — вердикт по вилкам + status (всегда) ├── .verify/ # I/O-контракт: один producer, много consumers -│ ├── authority.json # Фаза 5.5 — qualified/unqualified/unknown + карантины -│ ├── citations.json # Фаза 6.5 liveness -│ ├── faithfulness.json# Фаза 6.5 faithfulness -│ ├── qualifiers.json # Фаза 6.5 qualifier preservation -│ └── constructs.json # Фаза 6.5 construct provenance +│ ├── authority.json # 5.5 — qualified/unqualified/unknown +│ ├── wiki_pairs.json # 5.7 — пары на адъюдикацию (medium/deep) +│ ├── wiki_ingest.json # finish-up — квитанция записи в вики (всегда) +│ └── citations|faithfulness|qualifiers|constructs.json # 6.5, по оси на файл ├── diffs/_delta.md# дельты режима update +├── _.{html,pdf,docx} # Фаза 6.9 — собранный документ └── _.md # финал: qa|explainer|decision|landscape|validation|custom ``` -Отдельный `_changelog.md` не создаётся — он в `plan.md` §16. Шаблоны: `sources/NN.md` и `claims.csv` — `source_scoring.md`; отчёт — `genres.md` + `blocks/`; `findings/FN.md` — блок Z6 в `blocks/close.md`. +Кросс-прогонный слой лежит ВНЕ прогона — `~/.claude/research/wiki/`, один на все ресёрчи. См. `wiki.md`. + +Отдельный `_changelog.md` не создаётся — он в `plan.md` §16. Шаблоны: `sources/NN.md`, `claims.csv` — `source_scoring.md`; отчёт — `genres.md` + `blocks/`; `findings/FN.md` — Z6 в `blocks/close.md`. ## После завершения — finish-up 0. **Детерминированные артефакты, не руками:** `python scripts/build_sources_csv.py --research-dir /` (единый источник колонок) · `python eval/check_citations.py --research-dir / --json --out //.verify/citations` (без `--out` файл уйдёт в `eval/output/` и gate его не найдёт). -0.5. **Числа — два прохода, происхождение и вычисление:** `check_number_provenance.py --research-dir / --strict` (число без производителя; одно значение при разных корнях = ложная независимость) · `check_number_arithmetic.py --research-dir / --strict` (пересчёт `derived`, доли к 100, производное число в memo без строки в `numbers.csv`). -1. **Phase-gate — БЛОКЕР:** `python scripts/validate_phases.py --research-dir / --strict`. Красный ⇒ фаза пропущена ⇒ вернись, доделай, перезапусти. Не показывать путь, не писать резюме, не рапортовать «готово» с красным gate. +0.2. **Компиляция в вики — `python scripts/wiki_ingest.py --research-dir /`**, детерминированно и **на любой глубине**. Пишет квитанцию `.verify/wiki_ingest.json`, без неё phase-gate красный. Изредка `python scripts/wiki_lint.py`. +0.5. **Числа — два прохода, `--research-dir / --strict`:** `check_number_provenance.py` (число без производителя; одно значение при разных корнях = ложная независимость) · `check_number_arithmetic.py` (пересчёт `derived`, доли к 100, производное число в memo без строки в `numbers.csv`). +1. **Phase-gate — БЛОКЕР:** `python scripts/validate_phases.py --research-dir / --strict`. Красный ⇒ фаза пропущена ⇒ вернись, доделай, перезапусти: не показывать путь, не писать резюме, не рапортовать «готово». 2. Пути markdown-ссылками: сначала `memo.md` (вход потребителя), затем отчёт. -3. Резюме в чат 5–8 строк: 3 ключевых ответа + главный контр-аргумент + чего не нашли + итог walkthrough из `application.md`. +3. Резюме в чат 5–8 строк: 3 ответа + главный контр-аргумент + чего не нашли + итог walkthrough из `application.md`. 4. Предложи 2–3 следующих ресёрча. 5. Есть `memory/` — предложи 1–3 кандидата (тезис + confidence + источники; авторитетный источник как `[reference]`). 6. Есть `anthropic-skills:humanizer-ru` — прогони им финальный отчёт (опционально). ## Что НЕ делать -- Не пропускать `discover existing` и reframing. -- Не запускать medium/deep без единой if-then вилки Decision Spec — честный shallow дешевле мёртвого deep-отчёта. -- Не пропускать Фазу 8 «потому что и так ясно» и не отвечать на вилки ЗА пользователя. -- Не пропускать Plan-review gate в medium/deep; для deep гейт без ожидания ответа = не гейт. +- **Не пропускать:** `discover existing` и reframing · Plan-review gate в medium/deep (для deep гейт без ожидания ответа = не гейт) · Фазы 5.5 и 5.7 и multi-angle red team в medium/deep · gap-волну · Фазу 8 «потому что и так ясно» — и не отвечать на вилки ЗА пользователя. +- Фаза 5.7: не объявлять конфликт, не показав обе стороны с их `as_of` и корнями. Не трактовать `unknown` как «сойдёт» — карантин. Не молчать про срез по `MAX_ADJUDICATED`: непроверенные пары ≠ отсутствие противоречий. Не чинить противоречие выбором «более свежего». +- Не редактировать страницы вики руками и не заводить вики внутри проекта: слой один на все ресёрчи. Не гейтить `wiki_ingest` по глубине. +- Не запускать medium/deep без единой if-then вилки Decision Spec. - Не завершать синтез финалом «it depends» без разрешённых условий. - Не оставлять `root:` пустым и не копировать `discovery_path:` между источниками — это 3-е и 4-е условия триангуляции. -- Не разводить fetch-агентов только по подтемам — ещё и по осям поиска (EN-академия / RU + регуляторы / практики / реестры): один шаблон + одна модель + один язык = одна траектория и коррелированные голоса. +- Не разводить fetch-агентов только по подтемам — ещё и по осям поиска (EN-академия / RU + регуляторы / практики / реестры): один шаблон + одна модель + один язык = одна траектория. - Не выбрасывать дубли URL между агентами молча — считать `overlap_rate` в `plan.md` §15: совпадение это замер конформизма, а не подтверждение. -- Не передавать во второй раунд находки соседей — только дыры. +- Не передавать во второй раунд находки соседей — только дыры. Не дописывать `state.md` — он перезаписывается. - Не давать `triangulated` строке с непогашенным `dissent` от Primary/`credibility ≥ 4` (это `contested`) и не гасить dissent понижением credibility несогласного. -- Не трактовать `unknown` в authority как «сойдёт» — карантин. +- Не трактовать `unknown` в authority как «сойдёт» — карантин. Не давать confidence выше `medium` без primary-источника. Не строить выводы на источниках с `total < 8` и не оставлять утверждений без ссылки на `sources/NN.md`. - Не выдавать числу трибуну без производителя: `origin_kind: unknown` / `chain_len ≥ 2` / нет `data_as_of` ⇒ не в `memo.md`/TL;DR/F9 и не `high`. -- Не считать процент/долю/рост прозой: производное число живёт в `numbers.csv` с `formula`+`inputs`. Вычисление в тексте не повторяет никто — оси 6.5 арифметику не проверяют. -- Не писать отчёт одним проходом по пулу и не оставлять `triangulated`/`contested` claim вне `outline.md`: собранное и не внесённое — выброшенная работа, а не редакторский выбор. -- Не вводить именованный фреймворк/«закон» без `[sNN]` или пометки «наша рамка» — выдуманное имя проходит всё, что джойнится по `claim_id`. -- Не дописывать `state.md` — он перезаписывается; растущий по раундам файл это второй транскрипт, а не окно. +- Не считать процент/долю/рост прозой: производное число живёт в `numbers.csv` с `formula`+`inputs` — оси 6.5 арифметику не проверяют. +- Не писать отчёт одним проходом по пулу и не оставлять `triangulated`/`contested` claim вне `outline.md`. +- Не вводить именованный фреймворк/«закон» без `[sNN]` или пометки «наша рамка». - Не искать числа в вебе при наличии покрывающего endpoint в `stat_sources/`/`api_sources/`. -- Не поднимать fetch-агентов Фазы 4 на opus «для качества»: у них Write и изолированный контекст, растёт не качество поиска, а уверенность ошибки. -- Не пропускать gap-волну и не давать confidence выше `medium` без primary-источника. -- Не пропускать multi-angle red team и Фазу 5.5 в medium/deep. +- Не поднимать fetch-агентов Фазы 4 на opus «для качества»: растёт не качество поиска, а уверенность ошибки. - Фаза 5.5: не переписывать `sources/NN.md` (архив), не фильтровать по `total` вместо релевантности фрагмента к claim. -- Фаза 6.5: не доверять наличию ссылки — проверять entailment по дословной цитате; вердикты писать в `.verify/*.json` и не пересчитывать в rubric/F10; пары брать из `evidence/`, не пересканировать `sources/`. Layer 3 судит снятие ОГРАНИЧИТЕЛЯ, не сокращение текста; при сомнении PRESERVED; чинить отчёт, а не ledger; потерянный `claim_id` ⇒ `UNTRACEABLE`. -- Не использовать источники с `total < 8` как основу выводов и не оставлять утверждений без ссылки на `sources/NN.md`. -- Для fetch+save и red team — `general-purpose` с явным диапазоном номеров, не `Explore` (read-only, только разведка). -- Не запускать суб-агентов последовательно — только параллельно в одном сообщении. -- Не сжимать `sources/` в один файл, не выводить результат только в чат, не обходить WebFetch через bash/curl. -- Не рапортовать «готово» с красным phase-gate. +- Фаза 6.5: не доверять наличию ссылки — проверять entailment по дословной цитате; вердикты писать в `.verify/*.json` и не пересчитывать в rubric/F10; пары брать из `evidence/`, не пересканировать `sources/`. Чинить отчёт, а не ledger. +- Для fetch+save и red team — `general-purpose` с явным диапазоном номеров, не `Explore` (read-only, только разведка). Не запускать суб-агентов последовательно — только параллельно в одном сообщении. +- Не сжимать `sources/` в один файл, не выводить результат только в чат. +- Не обходить WebFetch произвольным `bash`/`curl`. Единственный санкционированный fallback — `scripts/fetch_source.py` (Фаза 4.2): он читает robots.txt, санитайзит страницу от prompt injection и проставляет `fetch_tier`. Вывод ручного `curl` в `sources/` не кладётся. +- Не принимать `fetch_source.py` за средство против paywall и анти-бот-защиты: `auth-wall` и `antibot` для него — терминальный вердикт. Дальше — fallback-протокол `channels.md` или endpoint из `api_sources/`. +- Не рисовать в отчёте число, которого нет в `numbers.csv`, и не подбирать палитру фигур на глаз — она валидируется скриптом. +- Не сливать `memo.md` в большой документ. Не считать DOCX форматом для чтения — читают PDF и HTML. ## Режим update -`update ` / «обнови ресёрч X» — **дельта, не replay**. Pre-flight: `plan.md`, `refresh_targets.md`, последний отчёт (нет `refresh_targets.md` — сгенерируй по Z11). Четыре категории дельты с date-фильтром от last_research_date: new entrants · entity diff · numbers refresh · adversarial trigger. Verified-no-change — тоже результат. Выход: `diffs/_delta.md`; новый отчёт — только если дельта существенна (решает пользователь), старый получает `status: superseded by …`. Adversarial trigger HIGH ⇒ повторить только Фазу 6 на opus. Типовой update ~$0.40 против ~$2 за medium. Протокол — `references/refresh_protocol.md`. +`update ` / «обнови ресёрч X» — **дельта, не replay**. Pre-flight: `plan.md`, `refresh_targets.md` (нет — сгенерируй по Z11), последний отчёт. Четыре категории дельты с date-фильтром от last_research_date: new entrants · entity diff · numbers refresh · adversarial trigger. Verified-no-change — тоже результат. Выход: `diffs/_delta.md`; новый отчёт — только если дельта существенна (решает пользователь), старый получает `status: superseded by …`. Adversarial trigger HIGH ⇒ повторить только Фазу 6 на opus. Протокол — `refresh_protocol.md`. + +Update тоже идёт в вики: `wiki_ingest.py` после дельты (квитанция обязательна) и `wiki_pair.py build` — расхождение НЕ по свежести и есть настоящая находка update'а. ## References — когда читать Прогрессивная подгрузка: файл читается когда дошёл до фазы, не превентивно. -**Базовые (читает любой medium/deep прогон):** `workflow.md` (детали 12 фаз) · `question_reframing.md` (Фаза 1 + clarification-триаж) · `plan_gate.md` (Фаза 3.7 + скаут) · `genres.md` (6 жанров) · `blocks/INDEX.md` (105 блоков) · `channels.md` (29 каналов, query patterns, paywall fallbacks) · `source_dispatch.md` (обязательно перед launch суб-агентов) · `model_routing.md`. +**Базовые (читает любой medium/deep прогон):** `workflow.md` (детали 13 фаз) · `question_reframing.md` (Фаза 1 + clarification-триаж) · `plan_gate.md` (Фаза 3.7 + скаут) · `genres.md` (6 жанров) · `blocks/INDEX.md` (106 блоков) · `channels.md` (29 каналов, query patterns, paywall fallbacks) · `source_dispatch.md` (обязательно перед launch суб-агентов) · `model_routing.md` · `wiki.md` (кросс-прогонный слой: чтение в `discover existing`, Фаза 5.7, запись в finish-up). **Условные — грузить, когда прогон дошёл до условия, а не заранее:** `capability_discovery.md` и `awesome_lists_registry.md` — Фаза 3.5 (обязательна только на deep) · `stat_sources/INDEX.md` (33 категории) и `api_sources/INDEX.md` (47+ endpoints) — Фаза 4, когда подвопрос количественный или Source Dispatch ведёт в registry/API · `refresh_protocol.md` — только режим `update`. -**По фазам:** `source_scoring.md` (шкалы, provenance, claims-ledger, dissent, `numbers.csv` — Фаза 5–6) · `evidence_filter.md` (relevance × authority — 5.5) · `subagents_v2.md` (промпты, периметр, `state.md` — 4) · `synthesis_outline.md` (outline + письмо по секциям — 6) · `adversarial_pass.md` (роли R1–R5 — 6) · `runtime_verification.md` (четыре оси + F10 — 6.5) · `decision_walkthrough.md` (Фаза 8). +**По фазам:** `subagents_v2.md` (4) · `fetch_source.py` + `channels.md` §«Bot-block ≠ paywall» (4.2, только когда WebFetch ответил «unable to fetch from …») · `source_scoring.md` (шкалы, provenance, claims-ledger, dissent, `numbers.csv` — 5–6) · `evidence_filter.md` (5.5) · `synthesis_outline.md` (6) · `adversarial_pass.md` (6) · `runtime_verification.md` (6.5) · `report_export.md` (6.9) · `swarm_postprocess.md` (после 7) · `decision_walkthrough.md` (8). -**Блоки (по выбранному жанру):** `frame.md` F1-F10 (TL;DR, scope, claim, verification header) · `explain.md` E1-E14 · `compare.md` C1-C13 · `map.md` M1-M12 · `validate.md` V1-V10 · `analyze.md` A1-A13 · `close.md` Z1-Z12 (counter-args, open questions, so-what-for-you) · `people.md` P1-P7 · `numbers.md` N1-N8 · `context.md` X1-X7. +**Блоки (по выбранному жанру):** `frame.md` F1-F10 · `explain.md` E1-E14 · `compare.md` C1-C13 · `map.md` M1-M12 · `validate.md` V1-V10 · `analyze.md` A1-A13 · `close.md` Z1-Z12 · `people.md` P1-P7 · `numbers.md` N1-N8 · `context.md` X1-X7. -**Stat/API источники (Фаза 4, точечно):** `stat_sources/core/*.md` — 14 cross-industry категорий; `stat_sources/industries/*.md` — 19 отраслевых; `api_sources/` — search, academic (free, no key), financial, companies, crypto, code, social, news, stats, domain_specific. Читай INDEX, потом нужную категорию. Auth через env vars, ключи скилл не хранит; приоритет — free no-key API. +**Stat/API источники (Фаза 4, точечно):** `stat_sources/core/*.md` (14 cross-industry) · `stat_sources/industries/*.md` (19 отраслевых) · `api_sources/`. Читай INDEX, потом нужную категорию. Auth через env vars, ключи скилл не хранит; приоритет — free no-key API. diff --git a/assets/report.css b/assets/report.css new file mode 100644 index 0000000..2ee4451 --- /dev/null +++ b/assets/report.css @@ -0,0 +1,156 @@ +/* deepdive report — направление e-ink/paper + аппарат Тафти. + Иерархия держится на кегле и вертикальном ритме. Ни одной тени, ни одного + градиента: убери цвет — структура не изменится. */ + +:root { + --paper: #f5f2ea; /* тонированная бумага, не #fff — блеск утомляет */ + --ink: #2b2926; /* тёмно-серый, не #000 — контраст ~12:1, не максимальный */ + --muted: #6f6a62; + --rule: #d8d2c6; + --accent: #0072a8; + --warn: #c9560c; + --serif: Charter, "Iowan Old Style", Georgia, "Times New Roman", serif; + --sans: "Avenir Next", "Helvetica Neue", Helvetica, Arial, sans-serif; + + --measure: 62ch; /* колонка 60–75 знаков */ + --margin-col: 15rem; /* поле Тафти под сноски и рисунки */ + --gutter: 2.2rem; +} + +@page { size: A4; margin: 20mm 16mm 18mm 16mm; } + +* { box-sizing: border-box; } + +body { + margin: 0; + padding: 0 3rem 4rem; + background: var(--paper); + color: var(--ink); + font-family: var(--serif); + font-size: 11.5pt; + line-height: 1.62; + -webkit-font-smoothing: antialiased; + hanging-punctuation: first last; +} + +/* ── Сетка: текстовая колонка + поле ─────────────────────────────── */ + +.doc { max-width: calc(var(--measure) + var(--gutter) + var(--margin-col)); margin: 0 auto; } + +section, .lede, .panel, figure, table, h1, h2, h3, p, ul, ol, blockquote { + max-width: var(--measure); +} + +/* ── Титул ───────────────────────────────────────────────────────── */ + +.title-block { padding: 3.5rem 0 1.6rem; border-bottom: 1px solid var(--rule); margin-bottom: 2rem; } +h1 { + font-size: 30pt; line-height: 1.12; font-weight: 400; + letter-spacing: -0.015em; margin: 0 0 0.7rem; +} +.subtitle { font-size: 13pt; color: var(--muted); margin: 0 0 1.4rem; font-style: italic; } +.byline { font-family: var(--sans); font-size: 8.5pt; color: var(--muted); letter-spacing: 0.06em; text-transform: uppercase; } + +/* ── Панель доверия (F10) ────────────────────────────────────────── */ + +.panel { + font-family: var(--sans); font-size: 9pt; line-height: 1.5; + border: 1px solid var(--rule); border-left: 3px solid var(--accent); + padding: 0.85rem 1.1rem; margin: 0 0 2.4rem; color: var(--ink); +} +.panel b { font-weight: 600; } +.panel .axes { display: flex; flex-wrap: wrap; gap: 0 1.4rem; margin-top: 0.35rem; color: var(--muted); } +.panel .flag { color: var(--warn); } + +/* ── Заголовки: размер и ритм, не цвет и не вес 800 ──────────────── */ + +h2 { + font-size: 17pt; font-weight: 400; line-height: 1.25; + margin: 2.8rem 0 0.2rem; letter-spacing: -0.01em; + break-after: avoid; +} +h2 .num { + font-family: var(--sans); font-size: 9pt; color: var(--muted); + display: block; margin-bottom: 0.35rem; letter-spacing: 0.1em; +} +h3 { font-size: 12pt; font-weight: 600; margin: 1.7rem 0 0.2rem; break-after: avoid; } + +p { margin: 0 0 0.85rem; } +.lede { font-size: 13pt; line-height: 1.5; } +.lede::first-letter { font-size: 300%; float: left; line-height: 0.82; padding: 0.06em 0.08em 0 0; } + +/* ── Аппарат Тафти: сноска на поле, ровно напротив своей строки ──── */ + +.sidenote { + float: right; clear: right; + width: var(--margin-col); + margin-right: calc(-1 * (var(--margin-col) + var(--gutter))); + margin-bottom: 0.9rem; + font-family: var(--sans); font-size: 8.5pt; line-height: 1.45; + color: var(--muted); + text-align: left; +} +.sidenote .src { color: var(--accent); font-weight: 600; } +.sidenote .asof { display: block; margin-top: 0.15rem; font-size: 7.5pt; } + +/* Метка источника в тексте — маленькая, не разрывает строку */ +.ref { + font-family: var(--sans); font-size: 7.5pt; font-weight: 600; + color: var(--accent); vertical-align: 0.28em; text-decoration: none; + padding-left: 0.1em; white-space: nowrap; +} + +/* ── Уверенность: носитель — засечка, не цвет ────────────────────── */ + +.conf { font-family: var(--sans); font-size: 7.5pt; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); white-space: nowrap; } +.conf::before { content: ""; display: inline-block; width: 0.5rem; height: 0.5rem; margin-right: 0.3rem; vertical-align: 0.02em; border: 1px solid var(--muted); } +.conf.high::before { background: var(--ink); border-color: var(--ink); } +.conf.medium::before { background: linear-gradient(90deg, var(--muted) 50%, transparent 50%); } +.conf.low::before { background: transparent; } + +/* ── Рисунки ─────────────────────────────────────────────────────── */ + +figure { margin: 1.9rem 0; break-inside: avoid; } +figure img, figure svg { width: 100%; height: auto; display: block; } + +/* Схема — не график: растягивать её на всю колонку значит раздувать шрифт + подписей до кегля заголовка. Ширина по содержимому, потолок — колонка. */ +figure.diagram svg { width: auto; max-width: 100%; margin: 0 auto; } +figcaption { + font-family: var(--sans); font-size: 8.5pt; line-height: 1.45; color: var(--muted); + margin-top: 0.5rem; padding-top: 0.4rem; border-top: 1px solid var(--rule); +} +figcaption b { color: var(--ink); font-weight: 600; } + +/* ── Таблицы: линии только горизонтальные ───────────────────────── */ + +table { border-collapse: collapse; width: 100%; font-size: 9.5pt; margin: 1.5rem 0; break-inside: avoid; } +th, td { text-align: left; padding: 0.42rem 0.7rem 0.42rem 0; border-bottom: 1px solid var(--rule); vertical-align: top; } +th { font-family: var(--sans); font-size: 8pt; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); border-bottom-color: var(--ink); } +td.num { font-variant-numeric: tabular-nums; text-align: right; } +tr.gap td { color: var(--muted); font-style: italic; } + +/* ── Врезка «что бы изменило вывод» ──────────────────────────────── */ + +.callout { + border-top: 2px solid var(--ink); border-bottom: 1px solid var(--rule); + padding: 0.9rem 0 1rem; margin: 2rem 0; +} +.callout h3 { margin-top: 0; } + +/* ── Приложение источников ───────────────────────────────────────── */ + +.sources { font-size: 9.5pt; } +.sources dt { font-family: var(--sans); font-size: 8.5pt; font-weight: 600; color: var(--accent); margin-top: 0.8rem; } +.sources dd { margin: 0.1rem 0 0; } +.sources .meta { font-family: var(--sans); font-size: 8pt; color: var(--muted); } + +/* ── Печать ──────────────────────────────────────────────────────── */ + +@media print { + body { padding: 0; font-size: 10.5pt; } + .sidenote { font-size: 7.5pt; } + h2 { break-after: avoid; } + figure, table, .callout { break-inside: avoid; } + a { color: inherit; text-decoration: none; } +} diff --git a/docs/_config.yml b/docs/_config.yml index c1d0101..d3bcd87 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -3,7 +3,7 @@ # or by GitHub Pages for the docs/ folder. title: Deepdive -description: A structured 12-phase meta-research skill for Claude Code. 29 channels, 460+ stat sources, 105 report blocks. +description: A structured 13-phase meta-research skill for Claude Code. 29 channels, 460+ stat sources, 106 report blocks. url: https://socialpranker.github.io baseurl: /deepdive diff --git a/docs/index.html b/docs/index.html index 9da2a11..2d667b8 100644 --- a/docs/index.html +++ b/docs/index.html @@ -9,11 +9,11 @@ - + - + @@ -1009,7 +1009,7 @@

investigation.

- A 12-phase meta-research skill for Claude Code. Hypothesis testing, + A 13-phase meta-research skill for Claude Code. Hypothesis testing, parallel sub-agent search, source triangulation, adversarial review. Output is a folder you can return to a month later — every claim traces to a source file with quotes and scoring. @@ -1023,7 +1023,7 @@

-
12
+
13
Workflow phases
@@ -1031,7 +1031,7 @@

Search channels

-
105
+
106
Report blocks
@@ -1105,7 +1105,7 @@

With this

-

12 phases.
Every one transparent.

+

13 phases.
Every one transparent.

Each phase has a defined output and a checkpoint. You confirm key decisions. The skill records what it chose and why in plan.md. @@ -1175,14 +1175,14 @@

Refresh

A curated catalog.
Auto-validated weekly.

- 460+ statistical sources, 47+ API endpoints, 29 named channels, 105 report blocks. + 460+ statistical sources, 47+ API endpoints, 29 named channels, 106 report blocks. Weekly cron in GitHub Actions validates endpoints and discovers upstream additions.

/blocks -
105 / 10 categories
+
106 / 10 categories

Report Blocks

Reusable sections with templates, anti-patterns, and composition rules. Each block has a fixed shape — you compose a report by naming the blocks it contains.

@@ -1349,7 +1349,7 @@

Frequently asked.

Is this just prompt engineering?
- It's structured methodology plus a curated catalog plus reusable templates plus automation. The 12-phase workflow forces discipline. 460+ stat sources is curated knowledge. 105 reusable blocks compose any report shape. Weekly auto-validation keeps the catalog alive. 25+ upstream awesome-lists give a discovery layer. Prompts are an implementation detail, not the value. + It's structured methodology plus a curated catalog plus reusable templates plus automation. The 13-phase workflow forces discipline. 460+ stat sources is curated knowledge. 106 reusable blocks compose any report shape. Weekly auto-validation keeps the catalog alive. 25+ upstream awesome-lists give a discovery layer. Prompts are an implementation detail, not the value.
@@ -1393,7 +1393,7 @@

const translations = { en: { 'meta.title': 'Deepdive — Claude Code Skill for Documented Investigation', - 'meta.description': 'A 12-phase meta-research skill for Claude Code. Stop ad-hoc Googling, start documented investigation. 460+ stat sources, 47+ APIs, 105 report blocks, weekly auto-validation.', + 'meta.description': 'A 13-phase meta-research skill for Claude Code. Stop ad-hoc Googling, start documented investigation. 460+ stat sources, 47+ APIs, 106 report blocks, weekly auto-validation.', 'nav.how': 'how it works', 'nav.catalog': 'catalog', @@ -1403,7 +1403,7 @@

'hero.tag': '§ claude code skill · v2.0 · MIT licensed', 'hero.h1': 'Stop ad-hoc
Googling.
Start documented
investigation.', - 'hero.lede': 'A 12-phase meta-research skill for Claude Code. Hypothesis testing, parallel sub-agent search, source triangulation, adversarial review. Output is a folder you can return to a month later — every claim traces to a source file with quotes and scoring.', + 'hero.lede': 'A 13-phase meta-research skill for Claude Code. Hypothesis testing, parallel sub-agent search, source triangulation, adversarial review. Output is a folder you can return to a month later — every claim traces to a source file with quotes and scoring.', 'hero.cta_primary': 'install in 30s →', 'hero.cta_secondary': 'github', @@ -1447,7 +1447,7 @@

'demo.success': 'REPORT READY → research/postgres-replication-vs-cdc/2026-05-21_decision.md', 'how.tag': '§ 02 · workflow', - 'how.title': '12 phases.
Every one transparent.', + 'how.title': '13 phases.
Every one transparent.', 'how.intro': 'Each phase has a defined output and a checkpoint. You confirm key decisions. The skill records what it chose and why in plan.md.', 'how.p1.title': 'Reframing', 'how.p1.desc': 'Restates the question. Identifies the decision it supports. Formulates 2-4 falsifiable hypotheses.', @@ -1474,8 +1474,8 @@

'inside.tag': '§ 03 · catalog', 'inside.title': 'A curated catalog.
Auto-validated weekly.', - 'inside.intro': '460+ statistical sources, 47+ API endpoints, 29 named channels, 105 report blocks. Weekly cron in GitHub Actions validates endpoints and discovers upstream additions.', - 'inside.f1.num': '105 / 10 categories', + 'inside.intro': '460+ statistical sources, 47+ API endpoints, 29 named channels, 106 report blocks. Weekly cron in GitHub Actions validates endpoints and discovers upstream additions.', + 'inside.f1.num': '106 / 10 categories', 'inside.f1.title': 'Report Blocks', 'inside.f1.desc': 'Reusable sections with templates, anti-patterns, and composition rules. Each block has a fixed shape — you compose a report by naming the blocks it contains.', 'inside.f1.more': '+71 more', @@ -1528,7 +1528,7 @@

'faq.q4': "What if I don't have CLAUDE.md or a project context?", 'faq.a4': 'The skill detects context in 3 tiers: explicit (CLAUDE.md research_root setting) → autodetect (pyproject.toml, package.json) → fallback (~/deep-research/). No project, no problem.', 'faq.q5': 'Is this just prompt engineering?', - 'faq.a5': "It's structured methodology plus a curated catalog plus reusable templates plus automation. The 12-phase workflow forces discipline. 460+ stat sources is curated knowledge. 105 reusable blocks compose any report shape. Weekly auto-validation keeps the catalog alive. 25+ upstream awesome-lists give a discovery layer. Prompts are an implementation detail, not the value.", + 'faq.a5': "It's structured methodology plus a curated catalog plus reusable templates plus automation. The 13-phase workflow forces discipline. 460+ stat sources is curated knowledge. 106 reusable blocks compose any report shape. Weekly auto-validation keeps the catalog alive. 25+ upstream awesome-lists give a discovery layer. Prompts are an implementation detail, not the value.", 'faq.q6': 'Can I use this commercially?', 'faq.a6': 'Yes — MIT licensed. Use it, modify it, integrate it into products. Attribution appreciated but not required.', @@ -1544,7 +1544,7 @@

}, ru: { 'meta.title': 'Deepdive — навык Claude Code для задокументированного исследования', - 'meta.description': 'Навык meta-research для Claude Code из 12 фаз. Не ад-хок поиск в Google, а исследование с источниками. 460+ статистических источников, 47+ API, 105 блоков отчёта, авто-валидация раз в неделю.', + 'meta.description': 'Навык meta-research для Claude Code из 13 фаз. Не ад-хок поиск в Google, а исследование с источниками. 460+ статистических источников, 47+ API, 106 блоков отчёта, авто-валидация раз в неделю.', 'nav.how': 'как работает', 'nav.catalog': 'каталог', @@ -1554,7 +1554,7 @@

'hero.tag': '§ навык claude code · v2.0 · лицензия MIT', 'hero.h1': 'Хватит
ад-хок гуглить.
Начни задокументированное
исследование.', - 'hero.lede': 'Навык meta-research для Claude Code из 12 фаз. Проверка гипотез, параллельный поиск суб-агентами, триангуляция источников, adversarial review. На выходе — папка, к которой можно вернуться через месяц: каждое утверждение ведёт к файлу-источнику с цитатами и оценкой.', + 'hero.lede': 'Навык meta-research для Claude Code из 13 фаз. Проверка гипотез, параллельный поиск суб-агентами, триангуляция источников, adversarial review. На выходе — папка, к которой можно вернуться через месяц: каждое утверждение ведёт к файлу-источнику с цитатами и оценкой.', 'hero.cta_primary': 'установить за 30 секунд →', 'hero.cta_secondary': 'github', @@ -1598,7 +1598,7 @@

'demo.success': 'ОТЧЁТ ГОТОВ → research/postgres-replication-vs-cdc/2026-05-21_decision.md', 'how.tag': '§ 02 · workflow', - 'how.title': '12 фаз.
Каждая прозрачна.', + 'how.title': '13 фаз.
Каждая прозрачна.', 'how.intro': 'У каждой фазы — свой output и контрольная точка. Ключевые решения ты подтверждаешь сам. Что и почему выбрал — скилл записывает в plan.md.', 'how.p1.title': 'Reframing', 'how.p1.desc': 'Переформулирует вопрос. Находит решение, которое он поддерживает. Формулирует 2–4 опровергаемых гипотезы.', @@ -1625,8 +1625,8 @@

'inside.tag': '§ 03 · каталог', 'inside.title': 'Кураторский каталог.
Авто-валидация раз в неделю.', - 'inside.intro': '460+ статистических источников, 47+ API endpoints, 29 именованных каналов, 105 блоков отчёта. Еженедельный cron в GitHub Actions проверяет endpoints и подхватывает новые из awesome-листов.', - 'inside.f1.num': '105 / 10 категорий', + 'inside.intro': '460+ статистических источников, 47+ API endpoints, 29 именованных каналов, 106 блоков отчёта. Еженедельный cron в GitHub Actions проверяет endpoints и подхватывает новые из awesome-листов.', + 'inside.f1.num': '106 / 10 категорий', 'inside.f1.title': 'Блоки отчёта', 'inside.f1.desc': 'Переиспользуемые секции с шаблонами, анти-паттернами и правилами композиции. У каждого блока — фиксированная форма; отчёт собирается перечислением блоков.', 'inside.f1.more': '+71 ещё', @@ -1679,7 +1679,7 @@

'faq.q4': 'А если нет CLAUDE.md или контекста проекта?', 'faq.a4': 'Скилл определяет контекст по 3 уровням: явный (CLAUDE.md с research_root) → автодетект (pyproject.toml, package.json) → fallback (~/deep-research/). Нет проекта — не проблема.', 'faq.q5': 'Это просто prompt engineering?', - 'faq.a5': 'Это структурированная методология плюс кураторский каталог плюс переиспользуемые шаблоны плюс автоматизация. Workflow из 12 фаз дисциплинирует. 460+ стат-источников — это куратный домен. 105 блоков складываются в любую форму отчёта. Авто-валидация раз в неделю держит каталог живым. 25+ awesome-листов дают слой discovery. Промпты — это implementation detail, не ценность.', + 'faq.a5': 'Это структурированная методология плюс кураторский каталог плюс переиспользуемые шаблоны плюс автоматизация. Workflow из 13 фаз дисциплинирует. 460+ стат-источников — это куратный домен. 106 блоков складываются в любую форму отчёта. Авто-валидация раз в неделю держит каталог живым. 25+ awesome-листов дают слой discovery. Промпты — это implementation detail, не ценность.', 'faq.q6': 'Можно использовать коммерчески?', 'faq.a6': 'Да — лицензия MIT. Используй, модифицируй, встраивай в продукты. Атрибуция приветствуется, но не обязательна.', diff --git a/eval/README.md b/eval/README.md index 8265c0d..9c5ae72 100644 --- a/eval/README.md +++ b/eval/README.md @@ -17,7 +17,7 @@ ## Почему скоринг артефактов, а не API-скрипт -Скрипт меряет то, что скилл реально произвёл (все 12 фаз, роутинг, субагенты, +Скрипт меряет то, что скилл реально произвёл (все 13 фаз, роутинг, субагенты, файлы `sources/`), а не воспроизведение его логики в коде. Цена этого — один ручной шаг: точные токены прогона живут в харнессе Claude Code, скрипт их не видит, поэтому `real_cost_usd` ты вписываешь руками из `/cost`. diff --git a/phases.yaml b/phases.yaml index a1b8c2d..437c25e 100644 --- a/phases.yaml +++ b/phases.yaml @@ -77,6 +77,20 @@ phases: model: sonnet effort: low depth_gate: medium + # Phase 5.7 confronts this run's claims with the cross-run wiki BEFORE synthesis, not + # after: a disagreement with an earlier research is something the report has to carry, + # and noticing it in Phase 7 would be noticing it too late to write about. Everything + # that needs no judgement — a merely newer figure, a unit mismatch, a different scope — + # is decided mechanically by wiki_pair.py, so only what survives that costs a model + # call and the expensive failure (a manufactured contradiction) has no path to the + # report. The wiki itself is written later, in finish-up, at every depth. + # See references/wiki.md. + - id: "5.7" + name_ru: "Сверка с вики" + name_en: "Wiki reconcile" + model: sonnet + effort: low + depth_gate: medium - id: "6" name_ru: "Синтез + multi-angle red team" name_en: "Synthesis + multi-angle red team" diff --git a/references/blocks/INDEX.md b/references/blocks/INDEX.md index 9c9dd19..d84818e 100644 --- a/references/blocks/INDEX.md +++ b/references/blocks/INDEX.md @@ -1,6 +1,6 @@ # Block Library — INDEX -105 блоков в 10 категориях. Композируемые секции для финального отчёта. +106 блоков в 10 категориях. Композируемые секции для финального отчёта. ## Как использовать @@ -24,7 +24,7 @@ | NUMBERS | [numbers.md](numbers.md) | N1-N8 | Количественные: метрики, market sizing, forecasts | | CONTEXT | [context.md](context.md) | X1-X7 | Внешний контекст: регуляторика, гео, культура | -## Полная таблица всех 105 блоков +## Полная таблица всех 106 блоков ### FRAME @@ -39,7 +39,7 @@ | F7 | `executive-summary` | 1-страничный TL;DR для стейкхолдеров | Decision/landscape для не-технических | | F8 | `glossary-link` | Ссылка на внешний/общий глоссарий | Если есть проектный glossary | | F9 | `background` | Почему вопрос стоит так — предыстория, причины, 5-10 строк | Medium/deep, все жанры (дефолт) | -| F10 | `verification-header` | Citation integrity (liveness + faithfulness) | Medium/deep, после Фазы 6.5 verify | +| F10 | `verification-header` | Четыре оси: liveness × faithfulness × qualifiers × constructs + независимость источников | Medium/deep, после Фазы 6.5 verify | ### EXPLAIN @@ -184,7 +184,7 @@ ## Progressive loading discipline -При 105 блоках критично не загружать всё в контекст. +При 106 блоках критично не загружать всё в контекст. ``` Главный поток: diff --git a/references/blocks/explain.md b/references/blocks/explain.md index c0a53ae..1b5dc7c 100644 --- a/references/blocks/explain.md +++ b/references/blocks/explain.md @@ -392,40 +392,39 @@ **Когда:** Process explainer. Поток данных или процесса со многими ветвями. -**Что внутри:** ASCII flow diagram или Mermaid (если рендер есть). +**Что внутри:** Mermaid `flowchart` — основная форма. ASCII — фолбэк, когда документ не собирается (ответ в чат, черновик без `build_report.py`). -**Антипаттерн:** Слишком сложная диаграмма — нечитаемо в ASCII. Если узлов >10 — разбей на 2 диаграммы. +**Антипаттерн:** Резать схему на две «потому что много узлов» — узлы режет `mmdc`, а не автор; делить надо тогда, когда в одной схеме два разных вопроса. Схема без подписи `%% caption:` — читатель не знает, на что смотрит. **Композиция:** Вместо `mental-model` для процессов, не статичных систем. Или дополнение. **Шаблон:** -```markdown +````markdown ## Flow -``` - ┌─────────┐ - │ Request │ - └────┬────┘ - │ - ▼ - ┌────────────┐ - │ Validate? │ - └─┬──────┬───┘ - │ ok │ fail - ▼ ▼ - ┌─────┐ ┌──────────┐ - │ ... │ │ 4xx done │ - └──┬──┘ └──────────┘ - ▼ - ... +```mermaid +%% caption: путь запроса от приёма до ответа +flowchart TD + A[Request] --> B{Validate} + B -->|ok| C[Authz] + B -->|fail| D[4xx] + C --> E{Rate limit} + E -->|ok| F[Handler] + E -->|over| G[429] + F --> H[(Primary DB)] + H --> K[Response] + D --> K + G --> K ``` **Описание ветвей:** -- **Validate ok:** <что происходит> - **Validate fail:** <что происходит> +- **Rate limit over:** <что происходит> - ... -``` +```` + +**Рендер:** `scripts/build_report.py` вырезает fence до pandoc, отдаёт `mmdc`, вклеивает SVG как «Схема N» в HTML/PDF/DOCX. Схема, которую рендер не взял, роняет сборку — дырой в документ не уедет. Установка рендерера — `references/report_export.md`. --- diff --git a/references/blocks/frame.md b/references/blocks/frame.md index 78ede07..980e8bc 100644 --- a/references/blocks/frame.md +++ b/references/blocks/frame.md @@ -230,3 +230,47 @@ **Почему это важно для ответа:** <короткая связка — как эта предыстория влияет на то, как нужно читать остальной отчёт> ``` + +## F10 — `verification-header` + +**Когда:** medium/deep — обязателен, ставится Фазой 6.5. В shallow — только строка liveness (Layers 2–4 не гонялись). Без него отчёт не «готов»: заголовок и есть заявление о том, насколько ему можно верить. + +**Что внутри:** Блокквот в самом верху отчёта, до `tldr` [F1]. Четыре оси одной строкой — liveness × faithfulness × qualifiers × constructs — плюс вторая строка независимости источников для medium/deep. Цепочка «источник → claim → отчёт» рвётся в любом звене, поэтому оси не заменяют друг друга и показываются вместе. + +Все цифры берутся из `.verify/*.json` и `claims.csv` и **никогда не пересчитываются руками**. Как они производятся и что означает плохое значение каждой — `references/runtime_verification.md`. + +**Антипаттерн:** Показывать заголовок как оценку («9/10, хорошо»). Каждая цифра — сигнал провала, а не балл. Отдельно: ноль `contested` по конфликтной теме — не достижение, а признак, что несогласных не искали. Метрика, которую улучшают, переставая делать работу, — не метрика. + +**Композиция:** Самый первый элемент отчёта, до [F1]. В экспорте (Фаза 6.9) верстается панелью доверия на первой странице. + +**Шаблон:** + +```markdown +> **Citation integrity: 21/23 live · faithfulness 20/22 supported · qualifiers 22/22 preserved · constructs 7/7 sourced · 0 red flags · 2 paywalled** +> Verified : liveness via check_citations.py (every OPEN source resolved live); +> faithfulness via Layer 2 judge over evidence/ (2 PARTIAL softened); qualifiers via Layer 3 +> over F1/memo.md/Z12 (no scope drift); constructs via Layer 4 (1 marked as ours). +> [liveness detail](.verify/citations.md) · [faithfulness detail](.verify/faithfulness.md) · [qualifier detail](.verify/qualifiers.md) · [construct detail](.verify/constructs.md) +> +> **Source independence: authority 12/14 qualified (2 quarantined) · numbers 9/9 dated · +> overlap 0.12 · 0 circulation flags · 1 contested claim** +> s11, s23 quarantined (no author, origin unknown) — neither is a sole support. +> CL6 contested: minority s60 (regulator filing) vs 3 secondary — both positions in §4. +``` + +Когда флаги нашлись и были погашены: + +```markdown +> **Citation integrity: 23/23 live · faithfulness 23/23 supported · qualifiers 21/23 preserved · 1 red flag + 1 overclaim + 2 qualifiers restored** +> s14 (dead URL → replaced ); C4 (PARTIAL → claim softened to match source); +> CL7 (BROADENED → "on fixtures with embedded state" restored in TL;DR). +``` + +Когда ось ниже порога и пользователь решил выпускать всё равно (только medium): + +```markdown +> ⚠ **Citation integrity: liveness 0.64 · faithfulness 0.71 · qualifiers 0.88 — liveness below floor (0.70).** +> s07, s11 (transport UNKNOWN), s19 (OPEN dead → claim demoted); C9 (UNSUPPORTED → Open Questions). +``` + +shallow: строки faithfulness/qualifier/construct опускаются, если слои не гонялись. diff --git a/references/blocks/map.md b/references/blocks/map.md index 08dfbca..f244f5d 100644 --- a/references/blocks/map.md +++ b/references/blocks/map.md @@ -309,41 +309,39 @@ Axes: **Когда:** Relationships in field. Кто с кем связан. -**Что внутри:** ASCII или текстовое описание связей. +**Что внутри:** Mermaid `graph LR` — основная форма. ASCII или таблица отношений — фолбэк без сборки документа. -**Антипаттерн:** Граф с >15 нодами — нечитаемый в ASCII. Тогда — таблица отношений или Mermaid. +**Антипаттерн:** Граф, где связи не типизированы, — картинка «все со всеми». Каждое ребро несёт тип (`partners`/`competes`/`integrates`/`acquired`) и расшифровывается в легенде под схемой. **Композиция:** Дополнение к `categories`. Когда связи между игроками важнее категоризации. **Шаблон:** -```markdown +````markdown ## Network -``` - ┌──── A ────┐ - │ │ - partners│ │partners - ▼ ▼ - B C - │ │ - competes competes - ▼ ▼ - D ────────► E - integrates +```mermaid +%% caption: связи игроков рынка на <дата> +graph LR + A -- partners --> B + A -- partners --> C + D -- competes --> E + D -- integrates --> A ``` **Типы связей:** -- **Partners (●—●):** формальное партнёрство, есть public announcement -- **Competes (●→●):** прямой конкурент по >50% продукта -- **Integrates (●→●):** один использует другого как dependency -- **Acquired (●═●):** owned +- **partners:** формальное партнёрство, есть public announcement +- **competes:** прямой конкурент по >50% продукта +- **integrates:** один использует другого как dependency +- **acquired:** owned **Ключевые наблюдения:** - A — central hub, partners с большинством - D и E — бывшие competitors, теперь integrates after pivot - ... -``` +```` + +**Рендер:** см. E13 — тот же конвейер `build_report.py` → `mmdc` → «Схема N». --- diff --git a/references/channels.md b/references/channels.md index 7c8f5a6..fa7b570 100644 --- a/references/channels.md +++ b/references/channels.md @@ -581,12 +581,51 @@ access: api-free-no-key # | api-free-with-key | api-paid | api-fallback-html - Записать в `gaps` источника в JSON суб-агента ``` +## Bot-block ≠ paywall + +Два разных отказа, и путают их постоянно. Протокол выше — про **paywall**: контент есть, но за деньги или логином. Отдельный случай — когда контент публичный и бесплатный, а закрыт именно AI-агент: `robots.txt` с `Disallow` для `GPTBot`/`ClaudeBot`/`CCBot`. WebFetch такие правила соблюдает и отвечает «unable to fetch from …», из-за чего живой открытый источник выглядит мёртвым. + +Замер 21.08.2026 на 7 URL: WebFetch не взял 6 из 7 (nytimes, theverge, wired, stackoverflow, reuters, reddit — прошёл только arxiv). Из этих шести `scripts/fetch_source.py` вернул контент на первом тире для трёх (nytimes 13 КБ, theverge 36 КБ, wired 42 КБ) — все три отдают страницу обычному клиенту и режут только AI-токены. Остальные три — не бот-блок, а auth-волл: reuters 401, reddit 403 «log in or use your developer token», stackoverflow 403 Cloudflare. + +Отсюда правило: **сначала классифицируй отказ, потом выбирай протокол.** + +| Отказ | Признак | Куда идти | +|---|---|---| +| AI-исключение | WebFetch «unable to fetch», robots режет AI-токены, `*` разрешён | fetch ladder, Фаза 4.2 | +| Paywall / auth-волл | 401/402, «sign in», «subscribers only», «developer token» | `fallback_routes.yaml` → протокол выше | +| Анти-бот-челлендж | 403, Cloudflare, «verify you are human» | `fallback_routes.yaml` → API/фид, не сила | +| Site-wide `Disallow` | robots закрывает путь для всех клиентов | `gaps`, спросить пользователя | + +## Открытые двери закрытых сайтов + +`references/fallback_routes.yaml` — курируемая карта «домен → официальный API / фид / архив», которую `fetch_source.py` печатает сам при вердиктах `antibot` и `auth-wall`. Карта ручная не по лени: у `api_sources/` нет поля с веб-доменом (аудит 24.08.2026 — `Endpoint base:`/`Auth:`/`Docs:` есть у всех 47 файлов, домена нет ни у одного), и связь бывает двух видов — `self` (API на том же домене) и `proxy` (сторонний агрегатор отдаёт чужой контент). Машинно это не выводится. + +**Главная находка замера 24.08.2026: фид переживает блокировку HTML.** Пайплайн фида отдельный и анти-бот-слоем обычно не прикрыт. + +| Сайт | HTML | Фид / API | +|---|---|---| +| stackoverflow.com | 403 Cloudflare | Atom 200 · 115 КБ; StackExchange API 200 без ключа | +| economist.com | paywall | RSS 200 · 151 КБ | +| theguardian.com | — | RSS 200 · 96 КБ | +| nytimes.com | robots режет 7 AI-токенов | RSS 200 · 55 КБ | +| wsj.com / ft.com | paywall | RSS 200 | +| reddit.com | 403 | только OAuth — `.rss` тоже 403 под тремя UA | +| reuters.com | 401 | RSS мёртв (404), только агрегаторы (GDELT, NewsAPI) | + +Оговорки: + +- **Фид ≠ статья.** Заголовок, дата, аннотация, URL — да. Полный текст — нет. Цитата из аннотации помечается как аннотация. +- **Архив отвечает на «что там было», не «что там сейчас».** Брать `as_of` снимка в `data_as_of`. +- **`verified` без даты и кода ответа — не `verified`.** Протухший маршрут хуже отсутствующего: он съедает раунд поиска и выглядит как рабочий. +- Известные дыры карты: twitter/x (API платный), youtube (только через SerpAPI), wikipedia (не заведён, хотя MediaWiki API открыт). + ## Forbidden patterns (не использовать) Эти подходы НЕ применять, даже как fallback: -- Bypass через bot-protection (Cloudflare CAPTCHA, etc) — не работает в WebFetch, не пытайся -- Credential reuse / login bypass — НИКОГДА -- Scraping с violation robots.txt — этическое нарушение +- Решение CAPTCHA и Cloudflare-челленджей, stealth-фингерпринтинг под анти-бот — в `fetch_source.py` этого нет намеренно, и дописывать не надо. 403 — сигнал идти в API сайта, а не наращивать маскировку. +- Credential reuse / login bypass / обход paywall — НИКОГДА. Auth-волл это терминальный вердикт. +- Site-wide `Disallow` в robots.txt (запрет для всех клиентов, а не для AI-токенов) — не переступать самому. `--ignore-robots` есть, но ставит его пользователь, и override пишется в `fetch_note:` источника. +- Произвольный `curl -A 'Mozilla/…'` в обход WebFetch — не потому что «нельзя ходить», а потому что мимо `fetch_source.py` теряются проверка robots, санитайзер prompt injection и `fetch_tier` в провенансе. ## Когда канал «не работает» diff --git a/references/fallback_routes.yaml b/references/fallback_routes.yaml new file mode 100644 index 0000000..47f27aa --- /dev/null +++ b/references/fallback_routes.yaml @@ -0,0 +1,240 @@ +# Обходные маршруты к источникам, чей HTML закрыт для скрейперов. +# +# Читается scripts/fetch_source.py при вердиктах `antibot` / `auth-wall`: HTML не +# отдали — но тот же контент почти всегда доступен через официальный API, фид или +# архив. Это не обход защиты, а нормальный вход, который сайт держит открытым. +# +# Формат намеренно ручной. api_sources/ не имеет поля с веб-доменом (аудит +# 24.08.2026: `Endpoint base:`/`Auth:`/`Docs:` есть у 47/47 файлов, домена нет ни +# у одного), а связь «домен → endpoint» бывает двух разных видов и машинно не +# выводится: +# self — API живёт на том же домене, что и закрытый сайт (stackoverflow) +# proxy — сторонний агрегатор отдаёт контент чужих доменов (GDELT, SerpAPI) +# +# `verified` — дата живой проверки с кодом ответа. Не проверял — не пиши. +# Протухшее лучше удалить, чем оставить: маршрут, который молча не работает, +# хуже отсутствующего, потому что съедает раунд поиска. + +version: 1 +updated: 2026-08-24 + +# Пробуются для любого домена, которого нет в `domains`. Дёшево и часто срабатывает: +# фид генерится отдельным пайплайном и обычно не прикрыт тем же анти-бот-слоем. +wellknown_feeds: + - /feed + - /feed/ + - /rss + - /rss.xml + - /index.xml + - /atom.xml + - /feeds/posts/default + +# Последний общий рубеж — снимок вместо живой страницы. `as_of` снимка обязателен +# в источнике: архив отвечает на вопрос «что там было», не «что там сейчас». +archive: + availability: "https://archive.org/wayback/available?url={url}" + note: "429 при частых запросах — это троттлинг, не отсутствие снимка. Повторить позже." + +domains: + + stackoverflow.com: + kind: self + note: "HTML — 403 Cloudflare. API и Atom-фид открыты и без ключа." + routes: + - type: api + url: "https://api.stackexchange.com/2.3/search/advanced?site=stackoverflow&q={q}&sort=votes&order=desc&filter=withbody" + auth: none + catalog: code/stackexchange.md + verified: "2026-08-24 · 200" + - type: feed + url: "https://stackoverflow.com/feeds/tag/{tag}" + auth: none + verified: "2026-08-24 · 200, 115 КБ" + + reddit.com: + kind: self + note: > + Единственный рабочий вход — OAuth. Анонимный .json — 403; .rss в замере + 24.08.2026 тоже отдал 403 под тремя разными UA (честный, stealthy, Chrome), + что сходится с social/reddit.md: блок идёт по IP/TLS, а не по заголовку. + Фид сюда НЕ вписан намеренно — он нестабилен. + routes: + - type: api + url: "https://oauth.reddit.com/r/{sub}/top?t=week" + auth: "oauth · REDDIT_CLIENT_ID + REDDIT_CLIENT_SECRET" + catalog: social/reddit.md + verified: "не проверено — нет тестового приложения" + + news.ycombinator.com: + kind: self + routes: + - type: api + url: "https://hn.algolia.com/api/v1/search?query={q}" + auth: none + catalog: social/hn_algolia.md + verified: "2026-08-24 · 200" + + nytimes.com: + kind: self + note: "robots режет все 7 AI-токенов. HTML берётся тиром http; фид — резерв." + routes: + - type: feed + url: "https://rss.nytimes.com/services/xml/rss/nyt/{section}.xml" + auth: none + verified: "2026-08-24 · 200, 55 КБ" + + wsj.com: + kind: self + note: "Жёсткий paywall на статьях, но фид отдаёт заголовки и аннотации — для триажа хватает." + routes: + - type: feed + url: "https://feeds.a.dj.com/rss/RSSWorldNews.xml" + auth: none + verified: "2026-08-24 · 200" + + ft.com: + kind: self + note: "Paywall на статьях; фид открыт." + routes: + - type: feed + url: "https://www.ft.com/{section}?format=rss" + auth: none + verified: "2026-08-24 · 200" + + economist.com: + kind: self + note: "Paywall на статьях; фид открыт и объёмный." + routes: + - type: feed + url: "https://www.economist.com/{section}/rss.xml" + auth: none + verified: "2026-08-24 · 200, 151 КБ" + + theguardian.com: + kind: self + routes: + - type: feed + url: "https://www.theguardian.com/{section}/rss" + auth: none + verified: "2026-08-24 · 200, 96 КБ" + + bbc.co.uk: + kind: self + routes: + - type: feed + url: "https://feeds.bbci.co.uk/news/{section}/rss.xml" + auth: none + verified: "2026-08-24 · 200" + + arstechnica.com: + kind: self + routes: + - type: feed + url: "https://arstechnica.com/feed/" + auth: none + verified: "2026-08-24 · 200, 79 КБ" + + techcrunch.com: + kind: self + routes: + - type: feed + url: "https://techcrunch.com/feed/" + auth: none + verified: "2026-08-24 · 200" + + theverge.com: + kind: self + routes: + - type: feed + url: "https://www.theverge.com/rss/index.xml" + auth: none + verified: "2026-08-24 · 200, 40 КБ" + + wired.com: + kind: self + routes: + - type: feed + url: "https://www.wired.com/feed/rss" + auth: none + verified: "2026-08-24 · 200, 45 КБ" + + medium.com: + kind: self + routes: + - type: feed + url: "https://medium.com/feed/tag/{tag}" + auth: none + verified: "2026-08-24 · 200" + + reuters.com: + kind: proxy + note: > + RSS мёртв — https://www.reuters.com/arc/outboundfeeds/rss/ отдал 404, + legacy feeds.reuters.com не резолвится. Прямого входа нет: HTML 401 и на + http-, и на browser-тире. Только агрегаторы, покрывающие wire-контент. + routes: + - type: api + url: "https://api.gdeltproject.org/api/v2/doc/doc?query={q}&format=json" + auth: none + catalog: news/gdelt.md + verified: "не перепроверено 24.08" + - type: api + url: "https://newsapi.org/v2/everything?q={q}" + auth: "api-key · NEWSAPI_KEY" + catalog: news/newsapi.md + + arxiv.org: + kind: self + note: "HTML берётся и WebFetch, и http-тиром. API — когда нужен batch или метаданные." + routes: + - type: api + url: "https://export.arxiv.org/api/query?search_query={q}" + auth: none + catalog: academic/arxiv.md + verified: "2026-08-24 · 429 троттлинг, endpoint живой" + + github.com: + kind: self + routes: + - type: api + url: "https://api.github.com/search/repositories?q={q}" + auth: "bearer · GITHUB_TOKEN (без токена 60 req/h)" + catalog: code/github.md + + crunchbase.com: + kind: self + note: "Legacy public endpoint отдаёт 403; v4 Data API — платный, contact-sales." + routes: + - type: api + url: "https://api.crunchbase.com/api/v4/searches/organizations" + auth: "api-key · платный" + catalog: companies/crunchbase.md + + patentscope.wipo.int: + kind: proxy + note: > + Веб-интерфейс за капчей, ToS прямо запрещает автоматические запросы, + программный API платный (600–19 500 CHF/год). Не пытаться — брать + пересекающиеся PCT-данные из EPO. + routes: + - type: api + url: "https://ops.epo.org/3.2/rest-services/" + auth: "oauth2 · EPO Consumer Key + Secret" + catalog: patents/epo_ops.md + - type: api + url: "https://data.epo.org/linked-data/query" + auth: none + catalog: patents/epo_lod.md + + wikipedia.org: + kind: self + note: "MediaWiki API открыт и без ключа; в api_sources/ файла нет — дыра каталога." + routes: + - type: api + url: "https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch={q}&format=json" + auth: none + verified: "2026-08-24 · 200" + +# Домены без покрытия — известные дыры, а не пропуски по недосмотру. +# twitter.com / x.com — API платный от $100/мес, бесплатного входа нет. +# youtube.com — только через SerpAPI (платный ключ), своего файла нет. diff --git a/references/fetch_ladder.md b/references/fetch_ladder.md new file mode 100644 index 0000000..2fc4318 --- /dev/null +++ b/references/fetch_ladder.md @@ -0,0 +1,27 @@ +# Fetch ladder — когда WebFetch не достаёт + +Дополнение к `workflow.md` Фаза 4.2. Читать, когда WebFetch реально вернул +«unable to fetch» или пустоту — не заранее. + +```bash +uv run scripts/fetch_source.py -o /.fetch/NN.md --meta /.fetch/NN.json +``` + +Два тира, останавливается на первом, который отдал реальный контент: + +| Тир | Что это | Когда берёт | +|---|---|---| +| `http` | HTTP-запрос с Chrome TLS и заголовками | robots-исключение для AI, простой UA-фильтр | +| `browser` | headless Chromium, исполняет JS страницы | контент рисуется клиентским JS | + +Коды выхода: `0` контент · `3` robots.txt закрывает путь всем клиентам · `4` auth-волл или анти-бот · `5` сетевая ошибка. + +- **Лестница — второй заход, не первый.** WebFetch дешевле, быстрее и сразу отдаёт markdown. `fetch_source.py` на втором тире поднимает браузер: это секунды и память на каждый URL. +- **Exit 4 — терминально для HTML, но не для источника.** `auth-wall` (401/402, «sign in to read», «developer token») и `antibot` (403, Cloudflare) значат, что дверь закрыта и ломать её не надо. Скрипт сам печатает открытые двери того же сайта: маршруты из `references/fallback_routes.yaml` (официальный API, фид, архивный снимок) плюс живой пробой well-known-путей фида для доменов вне карты. Идти по ним сверху вниз; ничего не сработало — `channels.md`, потом `access: closed`. +- **Фид часто жив, когда HTML мёртв.** Замер 24.08.2026: stackoverflow HTML 403 Cloudflare — его же Atom-фид 200 и 115 КБ. Фид генерится отдельным пайплайном и обычно не прикрыт анти-бот-слоем. То же у WSJ, FT и Economist: статьи за paywall, фид открыт — заголовков и аннотаций хватает на триаж и на список кандидатов. +- **Фид не заменяет статью.** Из него берутся заголовок, дата, аннотация и URL — но не полный текст. Цитату из аннотации помечать как таковую, не выдавать за цитату из статьи. +- **PDF не markdown-ится, а сохраняется как есть.** Скрипт определяет тип по `Content-Type` и магии `%PDF-`, кладёт файл с расширением `.pdf` и ставит `content_kind: pdf` в источник. Дальше — штатный `Read` с диапазоном `pages`; он читает PDF нативно. Для академического канала это основной путь: препринты и рабочие бумаги приезжают PDF-ами, а не страницами. Фид так же сохраняется дословно в `.xml` — markdownify уничтожает структуру, ради которой фид и брали. +- **Exit 3 — стоп по умолчанию.** Это `Disallow` для всех клиентов, а не AI-специфичное исключение. Флаг `--ignore-robots` существует, но это решение пользователя: суб-агент его не ставит — пишет в `gaps` и идёт дальше. +- **Код 200 ≠ успех.** Скрипт классифицирует по паре (статус, содержимое): заглушка под 200 это `antibot`, а не источник. Не подменять эту проверку на «файл записался» — scrapling пишет файл и выходит нулём даже на 401. +- **Что уезжает в источник.** Из `--meta` в frontmatter `sources/NN.md` идут `access:`, `fetched:`, `fetch_tier:` и `fetch_note:`, если он есть. Тир — часть провенанса: страница, взятая браузером поверх AI-исключения, не равна отданной добровольно. +- Извлечение всегда идёт в режиме `main_content_only` — он же санитайзер prompt injection (режет скрытые и `aria-hidden` элементы, `