# Анализ генерационных скриптов — 30.06.2026 (сессия 2) **Исполнитель:** Opus 4.8 **Задача:** аудит 4 bash-скриптов, 6 Go-тулов, профилей, CI — как API-данные превращаются в YAML, Go-код и документацию --- ## Вопрос 1: Bash-скрипты — аудит 4 файлов **Прочитал:** все 4 скрипта полностью. | Аспект | 01_yamls | 02_docs_v2 | 03_build | 04_publish | |--------|---------|-----------|---------|-----------| | `set -euo pipefail` | ✅ | ✅ | ✅ | ✅ | | `trap` cleanup | ❌ | ✅ | ✅ | ✅ | | API error handling | 🔴 НЕТ | — | — | — | | User-Agent в urllib | 🔴 НЕТ | — | — | — | | Проверка зависимостей (`command -v`) | ❌ | ❌ | ❌ | ✅ | | Идемпотентность (`rm` старого) | ✅ | ✅ | ✅ | ✅ | | Lock-файлы (параллельный запуск) | ❌ | ❌ | ❌ | ❌ | | Профиль обязателен | ✅ | ✅ | ✅ | ❌ | **Проблемы:** - 🔴 **01_generate_yamls.sh** — python `urllib` ставит только `Authorization`, без User-Agent → дефолтный `Python-urllib/3.x` → DDoS-Guard зарежет. **P0** - 🔴 **01_generate_yamls.sh** — нет обработки 500/битый JSON/пустой ответ → необработанный Python traceback вместо retry. **P0** - 🟠 Пустой `services_list.txt` не ловится — 01_generate_yamls.sh проверяет только существование файла → «успех» без генерации. **P1** - 🟠 Нет `command -v go/python3` ни в 01/02/03 → непонятная ошибка если инструмента нет. **P1** - 🟠 Нет lock-файлов нигде → два параллельных прогона на один `PROFILE_DIR` затрут друг друга. **P1** - 🟡 04_build_and_publish_docs.sh — профиль НЕ обязателен (в отличие от 01-03). **P2** **Предложение:** добавить UA в urllib + retry-обёртку (3 попытки, backoff); guard на непустой список; `command -v` проверки; lock через `flock` на `PROFILE_DIR`. **Хорошо:** 03_build_and_upload_provider.sh — сильная валидация полноты registry перед сборкой; 04_build_and_publish_docs.sh — лучший fallback (docker → venv → system mkdocs). --- ## Вопрос 2: service_spec_gen (API → YAML) **Прочитал:** generate_service_spec.go полностью. - **HTTP-клиент:** ✅ кастомный клиент с `Timeout: 30s`; ✅ User-Agent уже есть. 🔴 **Retry отсутствует** — любой 429/503/сетевой сбой → ошибка → panic в main. **P1** - **Парсинг API:** ✅ структуры полные — `cfsParam` маппит все 19 полей. Потери только в edge-case. Неожиданный формат → `json.Unmarshal` error → panic, без graceful degradation. **P2** - **classifyOperation:** покрыты `create/modify/delete/suspend/resume` → instance, `create_*/modify_*/delete_*` → subresource, остальное → action. 🟠 **Новые префиксы (`restart_*`, `pause_*`, `enable_*`) попадут в action**, а не subresource. **P1** - **Constraints:** ✅ всё сохраняется — `maxLength/minLength/regex/uniqueScope/dependsOn`. 🟡 `normalizeValueList` делает `fmt.Sprintf("%v")` — для вложенных объектов теряет структуру. **P2** - **YAML:** ✅ `yaml.Marshal` с `omitempty`, вложенные структуры корректны. Имя файла через `normalizeIdentifier` — Unicode схлопывается в `_`. **P2** **Предложение:** добавить retry с backoff в `getViaProxy`; расширить `classifyOperation` карту префиксов или сделать её конфигурируемой. --- ## Вопрос 3: gen_v2 (YAML → Go) **Прочитал:** generate_resources_v2.go. - 🟠 **`format.Source` fallback:** при ошибке форматирования пишет `buf.Bytes()` (неотформатированный, возможно невалидный Go) **без warning**. Ошибка всплывёт только на компиляции. **P1** - **computeCreateOnly:** «param в create но не в modify → ForceNew». При отсутствии modify-операции ВСЕ create-параметры → CreateOnly → корректно для immutable subresource. ✅ - 🟠 **Subresource identity:** `DeleteParams` помечаются ForceNew, но `computeCreateOnly` их не учитывает → если delete-параметр не входит в create, возможен некорректный план. **P1** - 🟡 **JSON:** `data_type: json → IsJson + JsonNormalize` работает для object/array, но нет валидации что значение реально валидный JSON. **P2** **Предложение:** не молчать на ошибке `format.Source` — логировать warning (или fail при невалидном Go); проверить пересечение DeleteParams ∩ CreateParams. --- ## Вопрос 4: docs_template_gen_v2 **Прочитал:** docs_template_gen_v2/main.go. - **Генерируется 7 MD-файлов на ресурс:** `.md`, `_example.md`, `_params_create.md`, `_params_modify.md`, `_outputs.md`, `_ops.md`, `_params.md`. Формат — Markdown для mkdocs. ✅ - **Покрытие:** ✅ subresources и actions, есть index. Все YAML-поля используются. ✅ - **HCL-примеры:** из create-операции, required без default → в HCL, опциональные закомментированы. ✅ - 🟠 **Ошибки:** битый YAML → panic, пустые операции — молча пропускаются. **P1** - 🟡 **`-exclude clickhouse`** — дефолт флага + дублирован в 02_..._v2.sh. Хардкод, без объяснения причины. **P2** — вынести в config/комментарий. --- ## Вопрос 5: service_ops_gen / service_params_gen — нужны? **Прочитал:** оба тула + grep по devops. - ❌ **Нигде не вызываются** в bash-скриптах — мёртвый код старой v1-архитектуры. - ✅ **Заменены `service_spec_gen`** (единый YAML на сервис). - **`tools/gen/`** — только placeholder-README, функциональность не реализована. **Предложение:** удалить `service_ops_gen`, `service_params_gen`, `tools/gen/` — **но только по явной команде**. **P2** --- ## Вопрос 6: embed.go и resources_yaml - `//go:embed` встраивает все `*.yaml` в бинарник. **Зачем:** провайдер при старте один раз читает YAML и строит lookup-карты, без зависимости от внешних файлов. - **Используется в 4 местах** resources_core: params_mapping.go, params_validation_mapping.go, required_params.go, params_ref_mapping.go. - **Почему генерируется скриптом:** шаблонный файл без логики, генерируется если отсутствует. - ⚠️ **`devops/profiles/*/generated/resources_yaml/embed.go` — не существует** (per-profile embed не реализован). --- ## Вопрос 7: Профили и CI - **Профили test/prod/dev** идентичны по структуре, различаются `profile.env` (API endpoint, token-файл, версии). - **CI = GitLab CI** (pipeline.yaml), 4 стадии: test → build → sign → publish. Запуск `only: tags`. - ❌ **Автогенерации YAML в CI НЕТ** — YAML генерируются локально/вручную и коммитятся; CI только собирает и публикует. **P1** - **Деплой:** Docker-образ `registry-operator:${TAG}` пушится в Harbor → управляется K8s-оператором. - **Скрипты 10-13:** `13 clean` → `12 latest` → `11 alias` → `10 stability` (N раз — тест стабильности). --- ## Вопрос 8: Практическая проверка покрытия - ✅ **Покрытие 100%:** все 41 активный сервис имеют YAML; исключённый `24 vc_nat` (DEPRECATED) YAML не имеет. Лишних YAML нет. - 🔴 **Ключевая проблема — свежесть содержимого.** 90_postgres.yaml содержит 11 операций, но **`backup`/`reconcile` НЕТ** — API их уже отдаёт, а YAML устарел. **Вывод:** проверка «список vs файлы» зелёная, но **не ловит устаревшее содержимое**. **Предложение (P1):** добавить в CI шаг diff — перегенерировать YAML и сравнить с закоммиченными; при расхождении — фейлить. --- ## Сводка приоритетов ### P0 (блокеры) 1. urllib без User-Agent в 01_generate_yamls.sh → DDoS-Guard 2. urllib без обработки ошибок API (500/битый JSON/пусто) ### P1 (важно) - Нет retry в generate_service_spec.go - `classifyOperation` не знает новые префиксы - `format.Source` молча пишет невалидный Go в gen_v2 - DeleteParams ∩ CreateParams в subresource identity - Нет CI-диффа «API vs закоммиченный YAML» - Нет lock-файлов, нет `command -v`, пустой список не ловится ### P2 (доработки) - Удалить legacy-тулы (по команде) - `-exclude clickhouse` в config - JSON-валидация - Unicode в именах - panic на битом YAML в docs-gen