Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ jobs:
- name: Lint (ruff)
run: ruff check src/ tests/

- name: Docs references (docs = code)
# Механическая форма AGENTS §8: изменённый .md обязан добавить проверяемую
# ссылку на код (`src/...py`, `path::symbol`, `install.py --flag`, env-имя).
# Проверяется дифф PR, а не весь файл. Локальный аналог: --staged.
run: >
python scripts/check_docs_refs.py
--base "${{ github.event.pull_request.base.sha || 'origin/main' }}"

- name: Client snippets cold start (G5)
# Каждый сниппет из `install.py --print-config` запускается на чистом
# раннере: initialize + tools/list. Покрывает все 5 клиентов, включая
Expand Down
16 changes: 15 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,8 @@ impact-guard).
пропускается автоматически.
7. CI проверен не «на словах»: `gh run list --branch <ветка>` и
`gh run view <id> --log-failed`. Джобы: `test` (ubuntu + windows, Python 3.14),
`clean-state`, `manifest-parity`, `docker-build`, `transport-equiv-e2e`.
`clean-state`, `manifest-parity`, `docker-build`, `transport-equiv-e2e`; шаг
`Docs references` внутри `test` проверяет дифф документации (§8).
8. Для изменений в индексе/провайдерах — живой smoke:
`python scripts/smoke_e2e.py --project .` (реальные сервисы, без моков).
9. `bash scripts/verify_clean_state.sh` (clone + venv + install + полный прогон) →
Expand All @@ -345,6 +346,19 @@ impact-guard).
документации в PR ссылается на факт кода (`файл:символ`), который она отражает.
Правка «только цифра» без ссылки отклоняется до коммита (чек-лист
`.github/pull_request_template.md`).
- **Guard изменения docs:** `scripts/check_docs_refs.py --base <sha>` (шаг CI
`Docs references`; локально вручную `--staged`) требует, чтобы изменённый `.md`
добавил **проверяемую** ссылку: существующий путь внутри репо (`.githooks/…` тоже),
`path::symbol` — символ **объявлен** в файле (`def`/`class`/присваивание), а не
упомянут; `path:NNN` — строка в пределах файла; `install.py --flag` — флаг известен;
имя переменной, которое код **читает** из окружения (`os.getenv`/`process.env`).
Косметика допускается только в файле, который уже ссылался на код и не вносит новых
утверждений (новая цифра/путь/флаг; перенесённая строка с уже существующей цифрой —
не новое утверждение). Тесты: `tests/test_docs_refs_gate.py` (35), включая матрицу
обхода: выдуманный путь/символ/флаг/переменная, префикс реального имени, `::return`,
traversal, junction, C-quoted не-ASCII путь, лимиты 200 файлов/20 000 строк.
Гейт доказывает существование факта, **не** его релевантность утверждению —
эту границу держит ревьюер.
- **Guard дрейфа флагов/клиентов:** `scripts/check_docs_vs_installer.py` — каждый
`--flag` и `--client X` из `README.md`/`docs/*/{INSTALL,CLIENTS,DATA_MAP}.md`
обязан существовать в `install.py`/`adapters/clients/snippets.py` (`tests/
Expand Down
14 changes: 14 additions & 0 deletions AGENT_DIARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -1941,3 +1941,17 @@ BREACH: MSC-P-19 | date: 2026-10-03 | rule: §12 | guard_at_time: no | detected_
**3. Код установщика в диффах есть.** `gh pr diff 120 | grep auto_yes` → удалённая строка `range(0 if auto_yes …)`, добавленная `range(1 if auto_yes …)` и тест `test_auto_yes_runs_each_step_once`. `gh pr diff 121 | grep "def _"` → `models_enabled`, `_doctor_report`, `_doctor_cli`, `_clean_targets`, `_clean_cli` (имена не `cmd_*`; поиск по `cmd_clean|cmd_doctor` пуст по этой причине).
**4. Гипотеза «clean-state до фикса валидировал пустую установку» — опровергнута.** `scripts/verify_clean_state.sh` вообще не вызывает `install.py`: он сам создаёт venv и делает `pip install -e .`; `grep "install.py --yes"` по `.github/` и `scripts/` пуст. Значит баг `--yes` с v3.0 не влиял ни на один прогон CI — ровно поэтому его никто и не поймал; поймал только ручной прогон по README.
**Урок:** «CI зелёный» и «инструкция работает» — разные утверждения. Пока установщик не запускали как пользователь (по README, в пустом каталоге), его неинтерактивная ветка была мёртвой, а все гейты оставались зелёными.

## [2026-11-14] docs = code стало механическим: гейт на ИЗМЕНЕНИЕ, а не на файл
**Проблема:** правило «каждая правка docs ссылается на факт кода» держалось на ревью. Два существующих guard'а смотрели файл целиком (флаги — `check_docs_vs_installer.py`, переменные — `check_docs_vs_config.py`) и не видели, что именно изменилось в PR.
**Сделано:** `scripts/check_docs_refs.py` (режимы `--base` / `--staged` / `--diff-file`). Изменённый `.md` обязан добавить **проверяемую** ссылку: существующий путь внутри репо, `path::symbol` (символ **объявлен**, а не упомянут), `path:NNN` (строка в пределах файла), `install.py --flag` (флаг известен), имя переменной, которую код **читает** из окружения. Косметика проходит только если файл уже ссылался на код и добавленные строки не вносят новых утверждений (перенесённая строка с уже существующей цифрой — не новое утверждение). Исключения: `docs/archive|blog|research/**`, `experiments/**`, реестры по имени файла (`docs/*/CHANGELOG.md` тоже). Лимиты: >200 файлов или >20 000 строк → `exit 3`.
**CI:** шаг `Docs references` в job `test`, база — `github.event.pull_request.base.sha`.
**Независимое ревью (свежий контекст) нашло 4 блокера — все закрыты:**
1. env подтверждался подстрокой (`MSCODEBASE_DOCS` ⊂ `MSCODEBASE_DOCS_MARGIN` → проходил) → теперь множество имён, реально читаемых через `os.getenv`/`process.env`, сравнение по целому имени;
2. на Windows-консоли гейт падал трейсбеком на `✗` (cp1252) и негативные тесты «проходили» из-за крэша → `stdout.reconfigure(utf-8, errors=replace)` + ASCII-маркеры; прогон с `PYTHONIOENCODING=cp1252` → 35 passed;
3. git C-quoted пути (не-ASCII/пробел) не распознавались → молчаливый `rc=0`; теперь `unquote_git_path` + тест;
4. перенос строки с уже существующей цифрой блокировался → «новое утверждение» = текст, которого не было в файле до правки.
Плюс major'ы: `experiments/**` и `docs/*/CHANGELOG.md` добавлены в исключения; env больше не привязан к трём префиксам (`ONNX_FIXED_PADDING` теперь валиден); неизвестный флаг больше не отбрасывает валидную ссылку в той же строке.
**Доказательства:** 35 тестов; 7 мутаций (символ/флаг/containment/файловый cap/строковый cap/claim-клауза/env-точность) — **каждая краснеет**; реплей 36 линейных коммитов `main` с `*.md` → **0 заблокированных** (до правок было 10/36); G5+G6+G7 = 45 markdown-файлов, 0 без ссылки.
**Принятые риски (записаны в правиле):** A1 «реальный, но нерелевантный символ», A2 ссылка только в fenced-блоке, A3 документы не в `.md`. Гейт доказывает существование факта, не его релевантность.
**Урок:** guard на изменение точнее, чем guard на файл, но он ловит только «ссылки нет» и «ссылка выдумана»; «ссылка не по делу» остаётся человеку — и это надо писать в самом правиле, иначе её начнут считать доказанной.
Loading
Loading