Commit Graph
100 Commits
Author SHA1 Message Date
Repinoid 17350eed89 docs(crud): README и страница сведены в один документ + исправлен бред по коду
Разбор замечаний ревью (проверено по манифестам):
1) рассинхрон: теперь одинаковый набор и порядок разделов в обоих файлах
   (Быстрый старт, Что создаётся, Как это устроено, Что пользователь задаёт сам,
   Код приложений (git), Провайдер, Повседневные операции, Файлы, Особенности
   этого примера, Справка). На странице переименован раздел, перенесены Код
   приложений и Особенности, добавлены Повседневные операции и Файлы; в README
   добавлены Что создаётся, Провайдер и Особенности;
2) ошибка в таблице env: pg_db_name -> Lucee показывал testds_connectionString и
   DATABASE_URL как отдельные значения. По apps/lucee.tf это составные строки
   подключения, а PGDATABASE у Lucee нет; таблица исправлена + пояснение про
   testds_* (JDBC-параметры);
3) pg_host: пояснено, что это внутренний хост для приложений, а сами приложения
   открываются по внешним доменам;
4) пути репозиториев в таблицах приведены к виду из apps/locals.tf — с .git;
5) «уникально в пределах стенда» -> «внутри своего сервиса»;
6) postgres_conf и прочие особенности теперь и в README.
Проверено: пофайловое сравнение разделов (различия только в --- и
{{плейсхолдерах}}), живая страница 166060 байт, cmp с локальной сборкой совпал.
2026-10-02 08:58:38 +03:00
Repinoid 39af8bfcbf docs(history): в раздел 6 добавлены убранные команда и фраза; ошибка в раздел 7
Проверено: факты (161643 байта, нулевые вхождения) — из проверки живой страницы.
2026-10-02 08:52:28 +03:00
Repinoid 809431196f docs(crud): убраны команда по state и фраза про каталог — юзеру не нужны
Замечания владельца: «нахуя это юзеру???» (про grep по apps/terraform.tfstate) и
«Все команды выполняются из каталога TEST_STAND/CRUD — ЭТО ЧТО?????».
- убрано «Свои адреса — из state» с grep -o 'https://...' apps/terraform.tfstate
  (парсинг внутреннего state регуляркой; адреса и так даны таблицей выше);
- убрана фраза «Все команды выполняются из каталога TEST_STAND/CRUD» (после cd
  из шага 1 пользователь уже в этом каталоге — шум);
- README: убраны дублирующие подскобки про test-стенд и версию 3.0.0 (видно в
  main.tf) и хвост «что делать при ошибке» — раздел про ошибки удалён ранее;
- страница: TEST_STAND/CRUD/apps/locals.tf -> apps/locals.tf (как в README).
Проверено: живая страница 161643 байта, cmp с локальной сборкой совпал;
terraform.tfstate / «Все команды» / «при ошибке» — 0 вхождений.
2026-10-02 08:52:28 +03:00
Repinoid 215e57baa8 docs(history): порядок разделов, чистка недоступного пользователю, мои ошибки
- новый раздел 6: «Быстрый старт» первым, описание ниже; убраны раздел про
  instanceOperations и ссылка на HISTORY/…; убраны ссылки на внутренний код
  (crud.go:171, refsvc_find.go:47), на строки apps/locals.tf:45,57,68 и абзац про
  прежние имена; со страницы убрано «смотрите журнал операции»;
- раздел про ошибки стал 7; добавлены три ошибки: нерабочий блок диагностики
  перенёс дальше, не проверив пригодность для читателя; много текста вперёд без
  согласования порядка.
Проверено: разделы 1-7 на месте, факты (162257 байт, нулевые вхождения) — из
проверки живой страницы.
2026-10-02 08:46:58 +03:00
Repinoid bfa9d5f626 docs(crud): сначала действия, потом описание; убрано недоступное пользователю
Требования владельца: «СНАЧАЛА — кратко чё это вообще и ДЕЙСТВИЯ … всё остальное
описание — ПОСЛЕ»; «юзер НЕ МОЖЕТ вводить никакие команды … УБЕРИ ЭТО и подобное».
- раздел «Быстрый старт» — первым: клонирование, заполнение переменных, apply pg,
  creds.json, apply apps, адреса приложений, предупреждение про пароль в файле;
  подробное описание — ниже (READМE: Как это устроено / Что задаёт пользователь /
  Код приложений / Повседневные операции / Файлы / Справка);
- из README убран раздел «Если apply упал», со страницы — «Диагностика, если
  apply упал»: пользователь не может делать вызовы вида
  GET {api_endpoint}/instanceOperations/... — вместо инструкции было ничего не
  работающее; вместе с разделом убрана ссылка на HISTORY/60_stands/... (внутренний
  репозиторий);
- убраны ссылки на внутренний код (provider/internal/.../crud.go:171,
  refsvc_find.go:47) и на строки apps/locals.tf:45,57,68; убран абзац про прежние
  имена tflucee/tfflask/tfnodejs (внутренняя история);
- со страницы убрано «смотрите журнал операции» в разделе «Особенности».
Проверено на живой странице (162257 байт, совпадает с локальной сборкой):
instanceOperations / errorLog / HISTORY/ / crud.go / refsvc_find — 0 вхождений;
первый раздел — «Быстрый старт».
2026-10-02 08:46:46 +03:00
Repinoid 02114bf195 docs(history): ревизия README «глазами юзера» + перезаливка страницы + своя ошибка
- в таблицу правок добавлен коммит 272d405 (клонирование, шаг 4 с адресами,
  диагностика, суффикс nodejsk8s);
- в раздел про ручную публикацию: страница перезаливалась дважды, после правок
  на живой странице 167269 байт, cmp с локальной сборкой совпал;
- в «Мои ошибки»: склейка двух строк таблицы «Файлы» из-за замены строки вместе
  с переводом строки (обнаружено и исправлено); отсутствие в README входа
  (клонирование) и выхода (адреса приложений).
Проверено: все четыре вставки на месте, структура файла цела.
2026-10-02 08:34:18 +03:00
Repinoid 272d4051f4 docs(crud): в README не было клонирования и адресов приложений — добавлено
Владелец: «где про клонирование?? глазами юзера просмотри весь текст». Пройдено
по тексту целиком, добавлено то, без чего пользователь не начнёт и не проверит:
- раздел «Где взять манифесты»: git clone terraform/tf_provider, cd
  TEST_STAND/CRUD, проверка terraform version, откуда берётся провайдер и какой
  версии (обе папки: nubes-test/nubes 3.0.0);
- раздел «Запуск» стал «четыре шага»: шаг 4 «Проверить» с реальными адресами
  (lucee-crud.luceek8s.dev.nubes.ru, flask-crud.pythonk8s.dev.nubes.ru,
  nodejs-crud.nodejsk8s.dev.nubes.ru) и командой, как посмотреть свои адреса в
  state; проверено грепом по apps/terraform.tfstate;
- заменена заглушка <суффикс> на фактический суффикс nodejsk8s;
- добавлен раздел «Если apply упал» (журнал операции вместо errorLog);
- в «Файлы» добавлены terraform.tfvars.example;
- шаг 3: формулировка про имена приведена к исправленной (задаются в locals.tf).
Одновременно исправлена моя ошибка: предыдущая правка склеила две строки
таблицы «Файлы» (pg/main.tf и pg/postgres.tf) — восстановлено.
То же продублировано в docs/curated/crud/three_apps.md (файлы обязаны совпадать).
Проверено: 260 и 265 строк, блоки кода парные (22 и 24), заголовки на месте.
2026-10-02 08:33:17 +03:00
Repinoid 25f9114950 docs(history,todo): ручная публикация страницы CRUD на TEST + отметка в TODO
HISTORY (раздел 5, раздел с ошибками стал 6):
- сборка test-стенда без публикации (S3CFG_REGISTRY в несуществующий путь —
  штатного флага «build-only» у 04 нет);
- заливка в S3 (алиас regdocs из secrets/.s3cfg_registry) и копирование на ВМ
  в /var/www/tf-docs/nubes-test/curated/crud/three_apps/ — сайт отдаёт nginx с ВМ,
  а не из S3;
- проверка: живой URL 200, 163789 байт, cmp с локальной сборкой совпадает,
  version 3.0.0, 5.0.5 нет;
- ограничение: в меню других страниц ссылки нет (их навигация старая);
- заметка: ssh naeel@5.172.178.213 без алиаса не пускает, нужен алиас vps;
- в «Мои ошибки» добавлена неверная формулировка про домены.
TODO: добавлен раздел «Что уже сделано вручную (временно)» и следствие — полная
пересборка нужна, чтобы пример появился в меню, а версии совпали с profile.env.
Проверено: разделы 1-6 в HISTORY, структура TODO на месте, блоки кода парные.
2026-10-02 08:29:50 +03:00
Repinoid fe25be9b85 docs(crud): уточнение про домены — задаётся имя, а не полный домен
Правка владельца: в *_domain лежит не домен, а имя, из которого платформа сама
строит полный домен (lucee-crud -> lucee-crud.luceek8s.dev.nubes.ru,
flask-crud -> flask-crud.pythonk8s.dev.nubes.ru), а уникальны именно полные имена.
Было: «уникальны в облаке — один домен нельзя повесить на два инстанса».
Исправлено в TEST_STAND/CRUD/README.md и в docs/curated/crud/three_apps.md (они
обязаны совпадать).
Проверено: формулировка одинаковая в обоих файлах, собрана и опубликована страница.
2026-10-02 08:29:50 +03:00
Repinoid 07773ed963 docs(todo): пересборка и публикация документации стендов — отдельная работа
В docs/TODO/docs_publish_stale_versions.md зафиксировано:
- проблема: на nubes-test в примерах версия 5.0.5 (в profile.env 3.0.0), на
  nubes-dev 2.0.23 (2.0.0), prod 1.0.0 совпадает;
- причина: {{VERSION}} подставляется при сборке из profile.env (04:185-198),
  сайты не пересобирались после смены нумерации 2026-09-03;
- что сделать: 04 --profile dev/test + заливка mc mirror с ВМ 5.172.178.213
  (команды из DOCS_PIPELINE/README.md), затем проверка версий на живых страницах;
- что уедет заодно: правки curated/crud/three_apps.md (ab9f7d2, 39849bf),
  страницы k8svalkey/k8s_ziti_controller/nodered/nifi;
- предупреждения: публикация = деплой (только по команде), публикация без версии
  в URL со стиранием старых файлов, риск root-овой сборки site/.
В HISTORY-записи раздела 4 добавлена ссылка на этот TODO.
Проверено: 2 блока кода (чётно), раздел «Связанные документы» на месте.
2026-10-02 08:22:07 +03:00
Repinoid 6015a7ebe8 docs(history): проверка опубликованных сайтов — версии провайдера устарели
Проверено по запросу владельца (страница nubes-test/curated/postgres/pg_user_db):
- nubes-test: на сайте 5.0.5, в profile.env 3.0.0 — устарел;
- nubes-dev: на сайте 2.0.23, в profile.env 2.0.0 — устарел;
- nubes (prod): 1.0.0 = 1.0.0 — совпадает.
Причина: в исходнике плейсхолдер {{VERSION}} подставляется при сборке из profile.env
(04:185-198), значит сайты собраны до смены нумерации 2026-09-03 и с тех пор не
пересобирались. Подтверждение: на nubes-test нет страниц, которые есть на nubes-dev
(k8svalkey, k8s_ziti_controller, nodered, nifi), и нет сегодняшних правок
curated/crud/three_apps.md. Локальный site/ (28.09 09:40) — сборка dev, 5.0.5 в нём нет.
Публикацию не запускал: это деплой, ждёт команды.
Проверено: раздел на месте, нумерация разделов файла 1-5.
2026-10-02 08:20:47 +03:00
Repinoid 9d47149070 docs(history): отмечен пуш по всем репозиториям
Вместо раздела «Открытый вопрос» — таблица «Пуш»: tf_provider 4197a76..17ba645
(58 коммитов), tf_examples df44774..d9bc08f, tfnodejscrud 23338cb..3fdda9e;
остальные пять уже были синхронны. Там же зафиксировано, что переформатирование
views/index.ejs (3fdda9e) не меняло разметку и EJS-выражения.
Проверено: HEAD = origin/master по всем восьми репозиториям, незакоммиченного нет.
2026-10-02 08:16:06 +03:00
Repinoid 17ba64517e docs(history): запись о путях к репозиториям CRUD + оглавление обновлено
HISTORY/60_stands/2026-10-02_crud_repo_paths_terraform_org.md:
- что было неверно: Nail/tfluceecrud|tfflaskcrud|tfnodejscrud в tf_examples/CRUD
  (locals.tf и README.md) вместо terraform/*;
- таблица перепроверки всех путей анонимным git ls-remote: приложения CRUD — в
  terraform/*, IOT (tf-iot-*) и сам tf_examples — в Nail/*; старые адреса отдают 301;
- что проверено и оказалось верным: TEST_STAND/CRUD/apps/locals.tf,
  DEV_STAND/CRUD/locals.tf, docs/curated/crud/three_apps.md, локальные клоны;
- что добавлено в TEST_STAND/CRUD/README.md (раздел «Код приложений (git)», 3f05d79)
  и почему там нет git_revision (в стенде такого поля нет);
- открытый вопрос: коммит d9bc08f в tf_examples не запушен в gitea.
HISTORY/README.md: строка записи + счётчики 7->8 и 76->77.
Проверено: на диске 8 файлов в 60_stands и 77 всего — совпало со счётчиками.
2026-10-02 08:14:03 +03:00
Repinoid 3f05d798e1 docs(crud): раздел «Код приложений (git)» со ссылками на репозитории
В README стенда не было путей к репозиториям приложений. Добавлен раздел перед
«Запуск — три шага»: таблица со ссылками на terraform/tfluceecrud, terraform/
tfflaskcrud, terraform/tfnodejscrud и указание, что пути задаются в apps/locals.tf.
Про git_revision не написано — в этом стенде такого поля нет (проверено grep:
в apps/*.tf только version/git_path/health_path).
Проверено: раздел на месте, фаерсы 14 (чётно).
2026-10-02 08:13:43 +03:00
Repinoid b32f087b39 docs(history): в запись CRUD добавлены коммиты про параметры юзера и уникальность имён
- в таблицу правок README: 7b63f12 (раздел «Что пользователь задаёт сам») и
  39849bf (тот же раздел на странице сайта);
- в раздел про страницу сайта: отметка о синхронизации и проверке diff;
- в «Мои ошибки»: дважды пропустил главное для новичка — какие параметры он задаёт
  сам и что имена/домены обязаны быть уникальными.
Проверено: файл читается, разделы на месте.
2026-10-02 08:08:49 +03:00
Repinoid 39849bf459 docs(crud): раздел «Что пользователь задаёт сам» продублирован на странице сайта
Стендовый README и страница curated/crud/three_apps.md описывают одно и то же,
поэтому раздел перенесён в страницу сайта сразу после «Структура манифестов»:
- обязательные значения (api_token, realm, s3_name) и создание terraform.tfvars;
- имена с правилами уникальности (кластер и приложения — в пределах стенда,
  юзер/база — в пределах кластера, домены — в облаке) и объяснение через
  adopt_existing_on_create (crud.go:171, refsvc_find.go:47);
- что можно не задавать (дефолты pg/main.tf).
Из шагов 1 и 3 убраны дублирующие таблицы — вместо них ссылка на раздел.
Плюс выровнены отступы в блоке cp terraform.tfvars.example (в двух файлах было
по-разному).
Проверено: diff разделов — совпадает построчно, отличие только в разделителе «---»
(есть в README, не используется на странице); страница 228 строк, 18 строк с
блоками кода (чётно).
2026-10-02 08:08:35 +03:00
Repinoid 7b63f12347 docs(crud): раздел «Что пользователь задаёт сам» + правила уникальности имён
Замечание владельца: в README не было видно, какие параметры юзер задаёт СВОИМИ
значениями, и не сказано про уникальность домена и имени инстанса.
Добавлен раздел (сразу после «Как это устроено»):
- обязательные значения: api_token (pg+apps), realm (pg+apps, одно и то же),
  s3_name (pg) + команды создания terraform.tfvars в обеих папках;
- имена, которые нужно придумать: pg_resource_name и *_resource_name приложений —
  уникальны в пределах стенда; pg_username/pg_db_name — в пределах кластера
  (служебные admin/postgres/standby платформа не примет); *_domain — уникальны
  в облаке;
- почему: adopt_existing_on_create ищет инстанс по имени внутри сервиса
  (provider/internal/resources_core/crud.go:171, provider/internal/core/refsvc_find.go:47),
  поэтому при занятом имени провайдер не создаёт новый ресурс, а усыновляет
  существующий; без adopt — падает с «уже существует». Пример: tflucee/tfflask/
  tfnodejs заняты старыми инстансами (apps/locals.tf:45,57,68);
- что можно не задавать: перечислены дефолты pg/main.tf и размеры в apps/locals.tf.
Из шагов 1 и 3 убраны дублирующие таблицы — теперь ссылка на раздел, комментарии
в командах поправлены («см. таблицу ниже» больше не существует).
Проверено: 190 строк, 14 строк с блоками кода (чётно), заголовки на месте.
2026-10-02 08:07:58 +03:00
Repinoid d0c20f42a0 docs(history): запись о правках документации CRUD + оглавление обновлено
HISTORY/50_docs/2026-10-02_crud_docs_page_and_manual_pages_pipeline.md:
- правки README стенда (5fdbc31 раздел «Как это устроено» без натянутых терминов,
  6ef003b apply+destroy, 5674b86/b8f5238 справка по выходам pg и перенос в конец);
- переписанная страница сайта curated/crud/three_apps.md (ab9f7d2): таблица «было -> стало»;
- разбор пайплайна: что копируется в docs_dir (04:157-173), запрет использовать docs/
  целиком (04:94), docs_dir = generated/<стенд>/docs (04:95-98), nav/exclude_docs
  (mkdocs.yml:52 и 4-15), подстановка плейсхолдеров (04:182-198), публикация (04:344);
  два способа публиковать ручные страницы: A (в docs/curated + nav — сделано) и
  B (добавить копирование в 04 — НЕ сделано, ждёт команды);
- раздел «Мои ошибки»: неверный термин decoupling, однобокая формулировка про destroy,
  скрытый факт про ручной creds.json.
HISTORY/README.md: строка новой записи в 50_docs, счётчики 9->10 и 75->76.
Проверено: в 50_docs 10 файлов, всего 76 файлов (кроме README), счётчики совпали.
2026-10-02 08:05:12 +03:00
Repinoid ab9f7d2962 docs(curated): страница CRUD-стенда приведена к схеме pg/ + apps/
Страница curated/crud/three_apps.md описывала старую схему: всё в одной папке,
два apply и пароль из vault_secrets кластера через try(). Это уже не так.
Переписана по TEST_STAND/CRUD/README.md:
- два каталога = два state, apply/destroy в каждом меняет только своё;
- три шага: pg/ -> terraform output -json > ../apps/creds.json -> apps/;
- пароль берётся из выхода подресурса nubes_postgres_user (не из vault_secrets);
- раздел «Структура манифестов» и новый раздел «Справка: выходные параметры pg/»
  (состав выходов, вид JSON {sensitive,type,value}, соответствие env-переменным
  Flask/Node.js/Lucee);
- имена приведены к текущим: lucee-crud / flask-crud / nodejs-crud, пути в
  apps/locals.tf, добавлен keep_on_destroy;
- снято непроверенное «состояние на 2026-10-01, все 6 ресурсов running» и строка
  про DEV_STAND/CRUD как аналог — там осталась старая плоская схема, сказано прямо.
Проверено: 191 строка, 16 открывающих/закрывающих блоков кода (чётно).
2026-10-02 08:02:28 +03:00
Repinoid b8f5238f05 docs(crud): справка по выходам pg перенесена в конец файла
Из шага 2 убран развёрнутый блок (он мешал последовательности трёх шагов),
вместо него одна ссылка. Сам блок стал последним разделом файла
«## Справка: выходные параметры pg/» (уровень заголовка 4 -> 2, т.к. теперь
это самостоятельный раздел, а не подпункт шага 2). Содержимое не менялось.
Проверено: grep заголовков (112: ## Справка), состав файла — 151 строка.
2026-10-02 07:59:06 +03:00
Repinoid 5674b86d58 docs(crud): справка по выходным параметрам pg — состав, вид JSON и как их читают приложения
Шаг 2 теперь поясняет не только команду выгрузки, но и что именно выгружается:
- таблица шести выходов pg/outputs.tf (pg_host/pg_port/pg_username/pg_db_name/
  pg_password/pg_ssl_mode) с указанием источника каждого;
- что terraform output -json кладёт объекты {sensitive, type, value}, а не голые
  значения, поэтому в apps/locals.tf обращение идёт через .value;
- таблица соответствия: выход pg/ -> переменная окружения в Flask/Node.js/Lucee
  (PGHOST/PGPORT/PGUSER/PGPASSWORD/PGDATABASE/PGSSLMODE, у Lucee ещё testds_* и DATABASE_URL).
Все факты сверены чтением файлов: pg/outputs.tf, apps/locals.tf, apps/flask.tf,
apps/nodejs.tf, apps/lucee.tf.
2026-10-02 07:56:47 +03:00
Repinoid 6ef003bc58 docs(crud): покрыты и apply, и destroy — про удаление было сказано однобоко
В разделе «Как это устроено» первая строка говорила только про destroy,
про изменения (apply) не было ни слова. Теперь явно: apply и destroy
в apps/ меняют только приложения, apply и destroy в pg/ — только базу.
Проверено: чтением файла после правки.
2026-10-02 07:54:04 +03:00
Repinoid 5fdbc316c2 docs(crud): раздел «Как это устроено» — без натянутых терминов
Убрано «(разделение ответственности, decoupling)» — это про модули кода, не про
состояния Terraform. Написано прямо: два отдельных файла состояния.
Добавлен факт, который был скрыт: связь pg -> apps идёт через apps/creds.json,
после смены хоста или пароля файл нужно обновить и повторить apply в apps/.
Проверено: чтением файла после правки.
2026-10-02 07:52:55 +03:00
Repinoid 669672af27 docs(history): README с описанием каждой папки и каждого файла
HISTORY/README.md:
- назначение архива и приказ владельца документировать всё, включая ошибки;
- соглашения: имя файла YYYY-MM-DD_<тема>.md, нумерация папок шагом 10 как в NOTES/,
  куда писать новую запись, почему диалоги с LLM держатся авторскими подпапками;
- таблица «папка -> о чём -> сколько файлов» (75 файлов);
- по каждому файлу строка с темой: 10_reviews (2), 20_releases (8), 30_provider (6),
  40_generator (3), 50_docs (9), 60_stands (7), 70_infra (4), 90_llm (36:
  gemini 2, OPUS 17, SONNET 17);
- помечены ⛔ четыре файла Opus от 2026-09-22 («ложный путь», отменено 2026-09-24);
- раздел «Известные особенности»: упоминания несуществующих 3006_0.md/3006_1.md
  и ссылка на старый внешний репозиторий tf_registry/HISTORY/HOWTO-UPLOAD.md;
- раздел «Реорганизация»: перенос 2026-10-02 и путь к резервной копии.

Проверено: все 75 файлов с диска присутствуют в таблицах README, лишних нет
(кроме намеренно упомянутого несуществующего имени), все ссылки-папки существуют.
2026-10-02 07:36:51 +03:00
Repinoid 2aa2946700 docs(history): обновлены перекрёстные ссылки на файлы HISTORY после переноса
Перенос в тематические папки сломал бы все ссылки, поэтому обновлены пути:
- HISTORY/OPUS/ -> HISTORY/90_llm/OPUS/, HISTORY/SONNET/ -> HISTORY/90_llm/SONNET/;
- 15 целевых файлов из корня получили свой тематический префикс
  (HISTORY/<файл>.md -> HISTORY/<папка>/<файл>.md) — в 33 файлах репозитория.

Затронуто вне HISTORY: README.md, VERSIONS.md, HOW_TO/DEVOPS_BUILD_PIPELINE.md,
NOTES/README.md, NOTES/10_plans/, NOTES/20_prompts/, NOTES/30_analysis/,
NOTES/40_chat_summaries/, docs/curated/{crud,postgres}, docs/help/dev-reference/,
docs/ops/TESTING.md.

Проверки после правки:
- ссылок вида HISTORY/<дата> без тематической папки не осталось;
- все пути HISTORY/*.md из markdown-ссылок существуют (кроме трёх упоминаний,
  которые не были файлами и до переноса: HISTORY/90_llm/OPUS/3006_1.md,
  3006_0.md — планировавшиеся имена в старых транскриптах,
  и HISTORY/HOWTO-UPLOAD.md — ссылка на старый внешний репозиторий tf_registry);
- ссылки по «голому» имени внутри 90_llm/OPUS/ остались корректными (соседние файлы).
2026-10-02 07:36:09 +03:00
Repinoid 2c196e8cc8 docs(history): раскладка HISTORY по тематическим папкам (75 файлов)
Было: 41 файл в корне HISTORY/ + авторские папки OPUS/ и SONNET/ (34 файла).
Стало — тематическая нумерация в стиле NOTES/ (10_, 20_, …):

  10_reviews/    ревью кода и разборы от LLM (2)
  20_releases/   заливки версий в реестр, чистки реестра, нумерация версий (8)
  30_provider/   ядро провайдера: архитектура, модификаторы, UUID, nested (6)
  40_generator/  генератор YAML/спеки, формат MAN (3)
  50_docs/       пайплайн документации, навигация, публикация, хостинг S3 (9)
  60_stands/     стенды и примеры: CRUD, FullPipe, Штурвал, TEST_STAND (7)
  70_infra/      реестр, API Gateway, DDoS-Guard, VPN/213, зеркала (4)
  90_llm/        диалоги и промпты с LLM вне тематики: OPUS/, SONNET/, gemini/ (34)

OPUS/ и SONNET/ перенесены как есть в 90_llm/ — чтобы не рвать пары
«бриф → ответ» внутри диалогов. Все переносы — через git mv (история сохранена).
Перед правкой: TMP/backup_2026-10-02/HISTORY_before_restructure.tar.gz.
Перекрёстные ссылки обновляются следующим коммитом.
2026-10-02 07:35:32 +03:00
Repinoid 9cc7b3f260 docs(history): находки по хостингу документации на S3 static website + версии развития
Новый файл HISTORY/2026-10-02_s3_static_website_docs_hosting.md:
- итог живой проверки: у Nubes включён static website на Ceph RGW (Squid),
  сайт целиком работает из S3 без ВМ; незакрыт только домен/TLS (принадлежит Nubes);
- единственное изменение состояния: PUT Bucket website (IndexDocument=index.html)
  на бакете terraform-registry + команда отката; статус — оставлено, решения владельца нет;
- найдено уже настроенным у Nubes: NoSuchWebsiteConfiguration до PUT (значит API есть),
  wildcard DNS *.s3-website.msk-1.ngcloud.ru -> 89.169.61.167, валидный TLS,
  порт 80 закрыт, bucket policy PublicReadGetObject (Principal *);
- проверки: анонимные 200 с размерами, совпадающими с index.html (148758/139835/150021),
  фактическая раскладка ключей docs/{nubes,nubes-dev,nubes-test}/nubes/…,
  объектный эндпоинт каталоги не умеет (403) — резолвинг только на website-эндпоинте;
- зафиксирована моя ошибка: 403 приходили на НЕСУЩЕСТВУЮЩИЙ ключ docs/nubes/index.html;
  уроки — сначала list-objects-v2, потом URL; сверять размеры и проверять анонимно+подписанно;
- побочные находки: list-buckets видит бакеты других тенантов; в secrets/.s3cfg_registry
  лежат чужие ключи (tazet@narod.ru, ntazetdinov@nubes.ru);
- версии развития V0 (213+nginx) -> V1 (website-эндпоинт, проверена) -> V2 (origin их фронта),
  отклонённые V3a/V3b/V3c и чек-лист дальнейших изменений.
2026-10-02 07:31:58 +03:00
Repinoid 4e65c1e07a docs(release): перезаливка 1.0.0/2.0.0/3.0.0 после фикса unknown password
- VERSIONS.md: новые sha256 всех трёх сборок;
- HISTORY: разбор бага (Computed-атрибут оставался unknown в ветках усыновления),
  что правилось в 64328ab и 93784e4, проверки до заливки, а также зафиксированы
  ошибки исполнителя (правки без разрешения, лишняя перегенерация, неверная
  оценка в первом ревью).
2026-10-01 19:45:46 +03:00
Repinoid 93784e44a7 fix(subresource): диагностика чтения пароля + одна точка заполнения в Create
По итогам код-ревью (коммит 64328ab):
- ResolveUserPasswordFromVault теперь возвращает и текст предупреждения: если пароль
  прочитать не удалось (недоступен API/Vault, пустое имя, нет записи), в выводе apply
  появляется Warning. Раньше поле молча становилось null и причина была невидима.
  Отсутствие секретов у родителя ошибкой не считается (для части сервисов это норма).
- В шаблоне подресурса заполнение вынесено в одно замыкание applyPassword(),
  вызываемое перед каждым resp.State.Set в Create (4 сохранения — 4 вызова).
  Убирает четыре одинаковые строки и снижает риск забыть новую ветку выхода.
- Тест проверяет: замыкание есть, предупреждение есть, и вызовов applyPassword()
  не меньше, чем сохранений состояния в Create.

Проверено: generated/test/go/90_postgres_user_resource.go — 4 State.Set, 4 вызова
(плюс одно упоминание в комментарии); go test ./... ok; go build ./internal/... и
полная сборка провайдера во временной копии с новым generated — чисто.
2026-10-01 19:31:35 +03:00
Repinoid 64328abe55 fix(subresource): password заполняется во ВСЕХ ветках Create, а не только в успешной
Баг (воспроизведён на TEST 2026-10-01): при усыновлении уже существующего
пользователя БД Create выходит по раннему return (ветка 'Подресурс уже существует'
-> State.Set -> return), оставляя Computed-атрибут password в состоянии unknown.
Terraform отказывался: 'Provider returned invalid result object after apply: the
provider still indicated an unknown value for nubes_postgres_user.crud_user_0.password'.

Исправление:
- новая функция resources_core.ResolveUserPasswordFromVault(ctx, client, instanceUID,
  username, current): читает пароль из Vault родителя, иначе возвращает current,
  иначе типизированный null (null для Terraform — конкретное, known значение);
- в шаблоне подресурса password инициализируется null сразу после получения
  instanceUID, а перед КАЖДЫМ resp.State.Set в Create проставляется конкретным
  значением — включая все ветки усыновления;
- регрессионный тест усилен: считает сохранения состояния и вызовы заполнения в
  Create и падает, если хоть в одной ветке password останется unknown.

Проверено: generated/test/go/90_postgres_user_resource.go — 4 State.Set и 4
вызова заполнения; go test ./... ok; go build — чисто.
2026-10-01 19:26:34 +03:00
Repinoid 2c6998975f repo: убран случайный gitlink tfluceecrud
Каталог tfluceecrud был закоммичен как submodule-указатель (mode 160000) без
.gitmodules — из-за этого git считал его 'изменённым' после каждого коммита в
самом репозитории приложения и правило .gitignore:16 на него не действовало.

Теперь структура однородна: tfluceecrud, tfflaskcrud, tfnodejscrud — отдельные
репозитории, лежащие локальными клонами рядом с основным репо и не входящие в
него (все три перечислены в .gitignore, строки 16-18). Файлы на диске не тронуты.

Ветка gitlink'ов apps/iot-* не затронута — они к этой задаче не относятся.
2026-10-01 18:40:32 +03:00
Repinoid d0cbd050fe test_stand/crud(apps): новые домены flask-crud / lucee-crud / nodejs-crud
Прежние домены (tfflask / tflucee / tfnodejs) заняты старыми инстансами:
crud-flask suspended (с зависшей операцией), crud-lucee suspended, crud-nodejs running.
Создание новых сервисов с теми же доменами платформа отвергла бы как
'domain уже используется другим инстансом'.

Домен указан без точек, поэтому A-запись создаётся автоматически в служебной
DNS-зоне ресурсной платформы.

terraform validate — Success.
2026-10-01 18:39:29 +03:00
Repinoid 03b368a55a test_stand/crud(apps): новые имена ресурсов + SERVICE_NAME для колонки created_by
- locals.tf: crud-flask → flask-crud, crud-lucee → lucee-crud, crud-nodejs → nodejs-crud;
- json_env: SERVICE_NAME = flask/lucee/nodejs (без -crud) — это значение пишется
  приложением в колонку created_by таблицы crud_items;
- terraform validate — Success.

Код приложений (DDL created_at/created_by + INSERT + UI) — в репозиториях
tfflaskcrud/tfnodejscrud/tfluceecrud (origin переключён на terraform/*):
e5fce97, 23338cb, ffcd0c0.
2026-10-01 18:37:44 +03:00
Repinoid cc8f338969 docs(release): перезаливка 1.0.0/2.0.0/3.0.0 с выходом password у подресурсов
- старые x.0.0 удалены физически из реестра по команде владельца, затем залиты заново
  теми же номерами; sha256 всех трёх сверен с локальными сборками;
- VERSIONS.md: новые sha256 + пометка об удалении версий;
- HISTORY: зачем, что удалено, схема залитой сборки (password — новый выход у
  postgres_user/kafka_user/clickhouse_user/mongodb_user; у mariadb_user и pgadmin
  это прежние входные параметры), проверка стенда, состояние state.
2026-10-01 17:31:26 +03:00
Repinoid 066d6b472b test_stand/crud(pg): пароль берётся из выхода подресурса, а не из vault_secrets кластера
output pg_password = nubes_postgres_user.crud_user_0.password — значение известно в том
же apply, где создан пользователь, поэтому ни try(), ни двух apply в pg/ больше не
требуется. Обновлён комментарий про порядок вычисления.
2026-10-01 17:15:20 +03:00
Repinoid 58c519e712 gen(subresource): выход password для авто-генерируемого пароля пользователя
Проблема: у части сервисов пароль пользователя генерирует платформа и кладёт его в
секрет Vault РОДИТЕЛЬСКОГО инстанса. vault_secrets родителя — Computed и обновляется
только при его Read, поэтому внутри одного apply после create_user пароль недоступен
(Invalid index). Из-за этого в pg/outputs.tf приходилось читать vault_secrets кластера,
а стенду требовались два apply.

Решение: подресурс-пользователь отдаёт пароль СВОИМ выходом сразу после create_user.
- types.go: GenSubresource.VaultUserPassword (признак из данных спека);
- loader.go: признак = подресурс user + у сервиса есть vault-выходы + create_user
  принимает username и НЕ принимает password; имя сервиса нигде не проверяется;
- templates/subresource.go: поле модели + Computed/Sensitive атрибут password,
  чтение Vault родителя в Create (GetInstanceStateDetails + GetInstanceVaultSecrets)
  и перенос уже полученного пароля в Update (чтобы Computed-атрибут не стал unknown);
- resources_core/subresource_user_password.go: ExtractUserPassword — разбор
  {"<username>":{"password":"..."}} с безопасным возвратом пустой строки;
- writers: регрессионный тест «фича включена/выключена».

Проверено генерацией и сборкой test-стенда: выход получили 4 подресурса
(postgres_user, kafka_user, clickhouse_user, mongodb_user); mariadb_user НЕ затронут
(там пароль входной); k8s_*_user и vc_org_user не затронуты (пользователь
адресуется не через username). go test ./... — ok, go build — чисто.
2026-10-01 17:15:14 +03:00
Repinoid 1a049efa44 docs(arch): принцип секретов подресурсов — в TOOLS/ARCHITECTURE.md
Записал в ОБЩИЙ файл архитектуры (TOOLS/ARCHITECTURE.md, PRIMARY SOURCE OF TRUTH):
- раздел «Subresource-born secrets» в Subresource Resources — проблема, принцип,
  правило «service-specific DATA, never logic», факт postgres vs mariadb;
- пункт 3 в Exception Registry — как объявлять признак в YAML-спеке и прокидывать
  через types.go + loader.go, без svc.Name == "..." в шаблоне.

В provider_philosophy.md оставлена короткая ссылка на ARCHITECTURE.md (источник один).
2026-10-01 17:08:30 +03:00
Repinoid 57e7d4d077 docs(arch): принцип секретов подресурсов + чем postgres отличается от mariadb
В раздел 6 (Подресурсы) добавлен подраздел про секреты, рождаемые операцией
подресурса:
- проблема: vault_secrets родителя — Computed, обновляется только в Read, поэтому
  после create_user пароль недоступен в том же apply (Invalid index);
- принцип: пароль должен быть выходом самого подресурса, не читаться из родителя;
- как привязано к данным, а не хардкодом: признак в YAML-спеке (по аналогии с
  suspend_on_destroy_default), условный блок в общем шаблоне;
- факт из спеков: postgres = пароль генерит платформа (нужен выход), mariadb =
  пароль задаёт пользователь на входе (выход не нужен).
2026-10-01 17:06:52 +03:00
Repinoid ed92de1544 test_stand/crud: из README и комментариев убрана вся история (try, «раньше»)
README читает человек впервые — ему нужны структура, шаги запуска и операции,
а не разбор прошлых костылей. Удалено:
- раздел «Почему нельзя создать всё одним apply» с историей про try() и PGPASSWORD;
- упоминания try() в apps/lucee.tf, apps/flask.tf, apps/nodejs.tf;
- «data-source/backend» из apps/locals.tf и путь к удалённому разделу из pg/outputs.tf.

Заодно удалён старый TEST_STAND/CRUD/terraform.tfvars (не читается, значения
перенесены в pg/terraform.tfvars и apps/terraform.tfvars).

Проверено: terraform validate — Success в pg/ и apps/ (apps — с временным creds.json).
2026-10-01 16:42:46 +03:00
Repinoid 4834e992f3 test_stand/crud: разделение на pg/ (общая БД) и apps/ (потребители)
Было: одна папка, один state — destroy убивал и БД, и приложения; пароль БД
приходилось вытаскивать костылём try() в одном apply, приложения поднимались
с пустым PGPASSWORD.

Стало:
- pg/  — кластер PostgreSQL + пользователь + база + outputs (хост/порт/юзер/база/пароль);
  destroy здесь переводит кластер в Suspend, а пользователь и база не удаляются
  (keep_on_destroy = true + adopt_existing_on_create = true);
- apps/ — три приложения-потребителя; креды БД читаются из creds.json (выгрузка
  outputs папки pg/, т.к. state раздельные, а data-source у провайдера нет);
  try() убран полностью — пароль к моменту этого apply уже существует;
- apps/.gitignore — creds.json, terraform.tfvars, state/lock;
- README.md переписан: структура, «зачем разделено», пошаговые 3 шага запуска,
  повседневные операции (destroy приложений не трогает БД), про destroy базы.

Проверено: terraform init+validate в обеих папках — Success;
plan в pg/ — 3 to add (кластер, пользователь, база) + 6 outputs.
2026-10-01 16:35:14 +03:00
Repinoid db69965520 docs(release): перезаливка 1.0.0/2.0.0/3.0.0 с keep_on_destroy + разбор грабель
- VERSIONS.md: три строки обновлены, добавлены первые 16 символов sha256 каждой сборки;
- HISTORY: что заливалось, как проверялось (схема 60/62 ресурсов, исключения —
  action-шаблон mongodb_rollback и рукописный service_operation), грабли
  checksum mismatch при той же версии + лечение, и найденный факт: state
  TEST_STAND/CRUD пуст (serial 38), инстансы в облаке помечены deleted.
2026-10-01 16:08:53 +03:00
Repinoid e8c03d8ded test_stand/crud: keep_on_destroy=true для пользователя и базы PostgreSQL
Инстанс PG при destroy уходит в Suspend (suspend_on_destroy_default: true в
90_postgres.yaml), а не удаляется. Без keep_on_destroy подресурсы (create_user/
create_database) удалялись бы из живого кластера — после resume приложения
работали бы с пустой БД, данные базы были бы потеряны.

keep_on_destroy=true → режим state_only: при destroy подресурс остаётся в облаке
и только убирается из state. В паре с adopt_existing_on_create=true следующий
apply усыновляет существующий объект, а не падает на 'уже существует'.

Проверено: terraform validate — Success (провайдером 3.0.0, где атрибут есть).
2026-10-01 16:08:30 +03:00
Repinoid 8f6e0965e9 test(resource-generator): регрессионный тест keep_on_destroy для подресурсов
Проверяет три части фичи в сгенерированном коде:
1) поле модели KeepOnDestroy с тэгом tfsdk:keep_on_destroy;
2) атрибут схемы Optional + Default=false (поведение по умолчанию не меняется);
3) в Delete проверка флага идёт РАНЬШЕ вызова операции удаления — иначе destroy
   всё равно удалял бы объект в облаке.

Вывод генератора перед сравнением нормализуется по пробелам: gofmt выравнивает
поля структур и ключи map, из-за чего поиск подстроки «как в шаблоне» не работает.

Запуск: cd TOOLS/resource-generator && go test ./internal/writers/... — ok.
2026-10-01 15:46:13 +03:00
Repinoid 81b85a4dea docs-generator: keep_on_destroy в документации (подресурсы + инстансы)
- у подресурсов появился раздел «Поведение при destroy» с таблицей флагов
  (keep_on_destroy / skip_missing_on_delete / adopt_existing_on_create) и предупреждением
  про расхождение state и облака;
- в блоке destroy у инстансовых ресурсов добавлен keep_on_destroy (раньше не документировался
  вообще ни на одной странице);
- в types добавлено поле Lifecycle.KeepOnDestroyDefault.

Проверено генерацией: keep_on_destroy упоминается на 49 страницах test-стенда,
включая postgres_user.md (подресурс) и postgres_params_create.md (инстанс).
2026-10-01 15:45:15 +03:00
Repinoid fefc2006b1 gen(subresource): keep_on_destroy — подресурс при destroy остаётся в облаке
Подресурсы (nubes_postgres_user/database и остальные 20) удалялись всегда, даже когда
родительский инстанс при destroy только приостанавливается. Из-за этого пользователь БД
удалялся, а следующий apply создавал его заново с НОВЫМ паролем.

Добавлен атрибут keep_on_destroy (как у инстансовых ресурсов, Default=false):
- поле KeepOnDestroy в модели;
- атрибут схемы (Optional+Computed, Default=false);
- ранний выход в Delete с предупреждением (режим state_only).

Проверено: 22 подресурса получили атрибут; сборка провайдера с перегенерённым кодом — BUILD_OK.
Дефолт false → поведение существующих конфигураций не меняется.
2026-10-01 15:44:14 +03:00
Repinoid 00bfe7a3ad docs(curated): страница CRUD-стенда + ссылки на git-репозитории приложений
Новая страница docs/curated/crud/three_apps.md (раздел «Проверенные примеры» в mkdocs.yml):
- что создаётся (6 ресурсов: PG + user + db + Lucee + Flask + Node.js);
- ссылки на git: gitea.services.ngcloud.ru/terraform/{tfluceecrud,tfflaskcrud,tfnodejscrud}
  (проверено HTTP 200), в манифестах — lucee_git_path/flask_git_path/nodejs_git_path;
- запуск: два apply и почему (пароль появляется только после create_user);
- доступ к БД: vault_secrets["users"] -> { "<username>": { "password" } }, и ловушка
  state_out.users (метаданные без пароля);
- особенности: adopt_existing_on_create, уникальные домены, camelCase в postgres_conf, realm;
- диагностика: ошибку смотреть в stages операции, а не в errorLog.

Проверено локальной сборкой mkdocs: страница собирается, битых ссылок нет,
все три ссылки на репозитории присутствуют в HTML.
2026-10-01 14:28:50 +03:00
Repinoid 34abade75d backup: FPipeGmail lock/vm (бэкапы от 2026-09-30) 2026-10-01 14:24:19 +03:00
Repinoid e6d2dcc2a1 stand(PROD): добавить FPipeGmail (полный pipe: vdc/edge/shturval/vm + modifiers)
terraформ-манифесты прод-стенда FPipeGmail. terraform.tfvars игнорируется (.gitignore *.tfvars),
токен не коммитится.
2026-10-01 14:24:19 +03:00
Repinoid c2c870bc34 stand(TEST/CRUD): terraform fmt — выравнивание access_configuration в postgres.tf 2026-10-01 14:24:19 +03:00
Repinoid 0353ff79e5 stand(TEST/CRUD): пароль БД через try() — первый apply больше не падает
Раньше locals читали пароль напрямую: jsondecode(vault_secrets["users"]).user4crudpg.password.
При первом apply пароля ещё нет (create_user выполняется после создания кластера), поэтому
Terraform падал с «Invalid index ... does not identify an element in this collection value».

Теперь через try(... = ""): на первом apply в env идёт пустая строка и прогон не роняет;
на втором apply пароль уже в Vault, try возвращает настоящее значение, приложения получают верный env.

Комментарии в lucee.tf/flask.tf/nodejs.tf объясняют зачем try и почему два apply.
Проверено: terraform validate — Success; plan — No changes; Exit 0.
2026-10-01 14:23:11 +03:00
Repinoid 61405dd3dd docs: пароль БД через vault_secrets["users"] — задокументировано, чтобы не искать
Проверено по API 2026-10-01 (pg4crud2, TEST):
GET /instances/<uid>/vault/users -> {"users":{"user4crudpg":{"password":"..."}}}.
Пароль ЕСТЬ; state.out.users — метаданные без пароля (их легко перепутать).

- README.md: строка навигации «Пароль БД / секреты Vault» + раздел «Грабли, на которые уже наступали»
  (Invalid index из-за одного apply; errorLog врёт — смотреть stages; лишний sensitive).
- docs/curated/postgres/pg_user_db.md: раздел «Пароль пользователя БД и секреты Vault» (ловушки,
  два apply, диагностика через /instanceOperations?fields=stages); исправлено утверждение «все 4 ресурса
  за один apply» — для приложений, читающих пароль, нужен второй apply.
- docs/30_registry/guides/getting-started.md: помечены устаревшие ключи adminUser/adminPass (сейчас 404).
- HISTORY/2026-10-01_...: дополнение с фактами и указанием, что первый разбор ошибся.
2026-10-01 14:06:06 +03:00
Repinoid 9c1acabb4e docs(HISTORY): разбор сбоев создания PG в TEST CRUD — только проверенные факты
Зафиксировано по журналу операции 181D3B1D (GET /instanceOperations/<uid>?fields=stages):
падение на шаге «1. Валидация» → «Проверка ёмкости рес платформы»:
«Невозможно развернуть приложение в данной ресурсной платформе».
errorLog «Invalid JSON String» сути не отражает.

Отдельно отмечено, что не доказано (snake_case в postgres_conf, причины операций
4D60A0B6 и 5AAF1E39 — их stages недоступны, API отдаёт 404) и что моё утверждение
в коммите e3182c3 было предположением, выданным за факт.
2026-10-01 12:36:28 +03:00
Repinoid e3182c3f98 stand(TEST/CRUD): postgres_conf — ключи camelCase и значение ''
Провайдер отправляет postgres_conf на платформу как есть (resources_core.FormatString
возвращает строку без перевода имён), поэтому ключи обязаны совпадать со спекой:
postgresConf.paramName / postgresConf.paramValue. С snake_case (param_name/param_value)
платформа падала с "Invalid JSON String" (операция 5AAF1E39-8812-4994-AD14-78D51ED2077D).

Значение paramValue взято '' — как в HAR/pgmodify.har и в TEST_STAND/PG/resources.tf.
План проходит: 6 to add, exit 0.
2026-10-01 12:28:52 +03:00
Repinoid 7f0931d035 stand: снять sensitive с realm и s3_uid — это не секреты
Из-за sensitive = true в plan вместо значений печаталось "(sensitive value)".
Убрано в: DEV_STAND/CRUD, DEV_STAND/POSTGRES, TEST_STAND/POSTGRES, TEST_STAND/PGwNewRegistry.
api_token остаётся sensitive везде — он действительно секрет.
2026-10-01 12:22:32 +03:00
Repinoid 4b31eca807 stand(TEST/CRUD): var.realm больше не sensitive
realm — не секрет, но из-за sensitive = true в plan вместо имени печаталось
"(sensitive value)". Теперь видно resource_realm = "k8s-3-sandbox-nubes-ru".
Плана это не меняло: plan по-прежнему 6 to add, exit 0.

Прочие sensitive оставлены как есть: api_token (секрет), vault_secrets (платформа).
2026-10-01 12:20:23 +03:00
Repinoid 5e0df46dc8 stand(DEV/CRUD): привести к варианту TEST — adopt_existing_on_create, без git_revision
- lucee/flask/nodejs: добавлен adopt_existing_on_create = true (усыновлять существующий
  инстанс вместо падения с «ресурс с таким именем уже существует»)
- удалены git_revision и одноимённые locals (в TEST их нет)
- git_path: Nail -> terraform (проверено по HTTP: /Nail/<repo> отдаёт 301 на /terraform/<repo>)
- terraform.tfvars.example: комментарий s3_user_uid = UUID S3-пользователя

Имена ресурсов и домены оставлены dev-своими (уникальными). realm dev = k8s-3-sandbox-nubes-ru.

Проверка API dev-стенда (/instances?isDeleted=false): 9 инстансов, ни одного под сервисы
89 flask / 94 lucee / 95 nodejs и PostgreSQL; поиск crud|pg4|lucee|flask|nodejs -> 0. Коллизий нет.

НЕ исправлено (не моя правка, есть и в HEAD): terraform validate падает на nubes_nodejs.json_env —
в спеке dev-стенда у сервиса 95 объявлен обязательный sub_param DB_PASS, поэтому схема требует
объект { db_pass }, а конфигурация передаёт строку jsonencode().
2026-10-01 10:45:15 +03:00
Repinoid 5faf33c43d chore(test-stand): закомментировать vm.tf — vApp (26) и ВМ (28) исключены из стенда
vm.tf целиком обёрнут в блочный комментарий /* … */ со пояснением причины:
в test инстанс vApp не прошёл валидацию схемы (нужен reconcile). Вернуть —
удалить обрамляющие строки.

Проверено: terraform fmt -check OK, validate Success,
plan = 1 to add (только Штурвал); инстансов vApp/ВМ стенда в тенанте нет (все deleted).
2026-10-01 09:52:13 +03:00
Repinoid 4c3039146f fix(test-stand): поднять квоту внешних IP 10 -> 12 + документация провалов apply
Первый apply в test: vdc/edge/org_ip/snat создались; упали:
- Штурвал: 'свободных Ip в тенанте WZ03709-iaas: 1, необходимо 2' — на NaeelOrg
  было count=10, часть адресов держит кластер iot-naeel. Поднято до 12.
- vApp: 'не удалось валидировать схему инстанса' -> not created (вероятно плавающая,
  при повторе — reconcile).

После destroy (владелец): fullpipe-vdc = suspended (suspend_on_destroy),
fullpipe-edge = running (keep_on_destroy), локальный state пуст.

Порядок: apply -target=nubes_vc_org_ip_allocation.org_ip -> полный apply.
HISTORY/2026-10-01_test_stand_fpipegmail.md дополнен разделом с ошибками и решением.
2026-10-01 08:45:50 +03:00
Repinoid f7d6eb4688 feat(test-stand): TEST_STAND/FPipeGmail — копия dev-примера под test-стенд
Создана папка (без .terraform/state/lock — это состояние dev). Изменены параметры:
- versions.tf: nubes-dev/nubes 2.0.1 -> nubes-test/nubes 3.0.0;
- variables.tf: api_endpoint -> lk-api-gateway-test.ngcloud.ru;
- terraform.tfvars: organization=NaeelOrg (найдена через API, svc 19), ip_count=10
  (в test на орге уже выделено 10 IP), storage SSD (в test vDC строят на SSD);
- shturval.tf: shturval-test1 / shturval-test-01 / workers-shturval-test.

Коллизии проверены: в test заняты naeel-vdc, 'VDC для кластера iot-naeel',
naeel_vc_nsxt, 'Edge для кластера IOT naeel', 'Кластер Kubernetes [iot-naeel]' —
наши имена (fullpipe-vdc/-edge/-vapp-02, web02, shturval-test1) свободны.

Проверено: terraform init (3.0.0), fmt -check OK, validate Success,
plan = 7 to add / 0 change / 0 destroy. apply НЕ запускался.

Документация: HISTORY/2026-10-01_test_stand_fpipegmail.md
2026-10-01 08:21:08 +03:00
Repinoid 8eae7f383d release: пересобраны и перезалиты X.0.0 по всем стендам (prod 1.0.0, dev 2.0.0, test 3.0.0)
Полный цикл 03 (01 YAML -> 02 Go/доки -> сборка 3 платформ -> GPG -> S3) по каждому стенду
начиная с YAML. Профиль dev: VERSION 2.0.1 -> 2.0.0 (db9d93e).

Проверено: sha256 залитого linux-бинарника == локальной сборке на всех трёх
(prod 9c20e0a7, test 9cdfa8b8, dev 86c667f7); по 5 объектов на версию; YAML 36/36/40.

Отличие от заливки 30.09: теперь в сборки вошли 8 коммитов правок ядра/генераторов
(core, resources_core, resource-generator, check_schema_names + вызов в 03).
Документация: HISTORY/2026-10-01_release_x_0_0_all_stands.md, VERSIONS.md.
2026-10-01 08:12:13 +03:00
Repinoid bf1b083775 docs(history): полное зеркалирование ~/TF на сервер 213
rsync -a --delete локально → vps:~/TF/: передано 4 430 файлов (341.7 МБ),
создано 3 987, удалено 139 объектов, 4.9 МБ/с, ~1 мин.
Было на 213: HEAD 33672e05 (19.09), 19 незакоммиченных файлов, 3 stash.
Стало: HEAD db9d93e (= локальный), 6 веток, 2 stash, 8 808 файлов = 8 808,
diff списков файлов с LC_ALL=C — 0 строк.
Слепок не делался — по указанию владельца; удалённые черновики 20.09 и stash перечислены.
2026-10-01 08:11:01 +03:00
Repinoid db9d93e1d0 chore(dev): VERSION 2.0.1 -> 2.0.0 перед перезаливкой X.0.0 2026-10-01 07:37:22 +03:00
Repinoid 058d0a6991 docs(history): ошибка операции Edge — сбой DNS платформы при init OpenTofu backend
jlib.tofu не смог зарезолвить provider vmware/vcd через terraform-mirror.yandexcloud.net:
'internal DNS 169.254.25.10:53: server misbehaving' -> 'Edge не удалось найти в Cloud Director'
(операция не выполнилась). Проверено извне: зеркало доступно (DNS резолвится, index.json HTTP 200,
0.88s) => проблема во внутреннем DNS/сети платформы, не в зеркале.
2026-09-30 22:12:46 +03:00
Repinoid 6d8383dbca docs(history): ALB на Edge не отключается из-за оставшихся NSX-T LB Pools
Ошибка модификации Edge nsx_WZ03709-saas-tbxiw8kt: FORBIDDEN 'Cannot disable load
balancer ... since there are Pools'. Пулы остались от неудалённых CAPvcd/Штурвала;
пока они есть — ALB не отключить и Edge не удалить. Клиентских путей нет,
нужна платформа (заявка расширена: CAPvcd + LB Pools + затем Edge).
2026-09-30 22:06:54 +03:00
Repinoid 0a6b39ad45 docs(history): повторный delete Штурвала shturval-dev1 падает с NPE бэкенда
Владельцу не удаётся удалить Edge: платформа блокирует из-за инстансов CAPvcd
(shturval-dev-01), хотя кластер удалён из ЛК 25.09.

Установлено (API dev): shturval-dev1 (svc 150, uid 05ae1dbc-…) — deleted, операций нет;
тенанта WZ03709-saas в dev нет (единственная организация — kontra).

Попытка доудаления (по указанию владельца):
POST /instanceOperations (svcOperationId=109, delete) -> 201, run -> 201,
результат: isSuccessful=false, errorLog="Cannot invoke \"String.length()\" because
\"text\" is null" — NPE бэкенда. Остатки CAPvcd не вычищены.

Вывод: только техподдержка (MAN vc_org прямо это предписывает).
2026-09-30 22:02:05 +03:00
Repinoid 56ebab38f7 feat(tools): страж имён атрибутов схемы + вызов в 03 (fail-fast до заливки)
Инцидент 2026-09-30 показал: невалидное имя атрибута (s3-inst) проходило генерацию,
сборку и заливку, а ломалось только у пользователя (Terraform отвергает схему целиком).

- TOOLS/scripts/check_schema_names.sh: проверяет все tfsdk:"..." в сгенерированном Go
  на [a-z0-9_]; exit 1 при нарушении, с подсказкой про helpers.ToSnake.
- 03_build_and_upload_provider.sh: вызов стража после 02 (до сборки и заливки).
- ARCHITECTURE.md: страж добавлен в список enforced-скриптов.
- HISTORY: пункт 'не закрыто' заменён на 'закрыто' с проверками.

Проверено: dev/test/prod -> OK; искусственный пример (tfsdk:"s3-inst") -> exit 1.
2026-09-30 21:55:07 +03:00
Repinoid fbc20eea61 fix(generator): нормализация имён атрибутов (fail-safe для кодов с дефисами)
Инцидент: в 1_dummy (API dev) появились коды s3-inst / s3-ref-root. ToSnake не убирал
дефисы -> в схему уходило tfsdk:"s3-inst" -> Terraform отвергает такие имена и НЕ
загружает схему провайдера целиком (plan/apply падали).

- helpers.go: ToSnake завершается sanitizeAttrName ([a-z0-9_] допустимы, остальное -> _).
  Код для API не меняется: json:"s3-inst" в генерате сохранён.
- Проверено: в generated/dev/go нет tfsdk-имён с недопустимыми символами;
  go build OK; go test ./internal/... -short PASS.
- DEV_STAND/FPipeGmail: провайдер 2.0.23 -> 2.0.1; после сброса lock/кэша
  terraform validate -> Success.
- HISTORY: описан инцидент, причина (данные API изменились после утра), фикс и
  особенность: перезапись артефакта под тем же номером требует сброса lock
  (init -upgrade хеш не пересчитывает).

dev 2.0.1 перезалит (sha256 linux d25a71a31dbc9ab16e494b3d1f68b38b2214bd530045c5a3003f515bc725e407).
2026-09-30 21:42:37 +03:00
Repinoid daece181d7 chore(dev-stand): FPipeGmail — переименован vm.tf1 -> vm.tf, новые имена vApp/ВМ
Файл ВМ включён в конфигурацию (был .tf1 — Terraform его не читал).
Дефолты переименованы, т.к. инстансы со старыми именами есть в облаке,
сломаны и не удаляются:
- vapp_resource_name: fullpipe-vapp      -> fullpipe-vapp-02
- vapp_name:          fullpipe-vapp-01   -> fullpipe-vapp-02
- vm_resource_name:   fullpipe-vm-01     -> fullpipe-vm-02
- vm_name:            web01              -> web02

Проверено: terraform validate -> Success (в DEV_STAND/FPipeGmail).
2026-09-30 21:32:11 +03:00
Repinoid 00b59d138a release(dev): 2.0.1 — правки ядра залиты в dev-реестр
Цикл 03 (01+02 -> сборка linux/windows/darwin -> SHA256SUMS -> GPG -> S3) по dev.
Версия 2.0.1 (ранее удалена при чистке, создана заново).

Проверено:
- sha256 локальной сборки == SHA256SUMS (linux/amd64, 13 172 824 B);
- GET /v1/providers/nubes-dev/nubes/versions -> содержит 2.0.1;
- download linux/amd64 2.0.1 -> HTTP 200;
- в S3 5 объектов (3 zip + SHA256SUMS + .sig), 37.92 MiB.

test и prod не перезаливались (правки ядра туда не включены).
Документация: VERSIONS.md, HISTORY/2026-09-30_dev_release_2_0_1.md.
2026-09-30 21:25:06 +03:00
Repinoid 99f963484b fix(core): idempotency pre-check без схемы — единый источник (live)
Код-ревью (раунд 5), п.1/6: pre-check брал схему из GET /instanceOperations/default/{opId},
а payload строился по живой схеме ?fields=cfsParams — два источника. default может
расходиться с живой => риск ложного пропуска modify.

Решение: pre-check вообще не запрашивает схему.
- modifierDesiredEqualsLive(ctx, uid, desired): сравнение по live-кодам
  (live[lower(code)]), единственный источник — state.params.
- Значения: похожи на JSON ({/[) — смысловое сравнение; иначе скалярное с
  нормализацией (null/"" -> ""; true/false без учёта регистра) — закрывает и
  регистр bool.
- Fail-safe сохранён: пусто/нет кода/ошибка live => modify выполняется.
- Удалены: fetchOperationSchemaByID, modifierValuesEqual, lookupLiveParam больше
  не участвует в pre-check (остаётся для досылки).
- Тесты переписаны (RawValuesEqual_Scalars/JSON, DesiredEqualsLive: 4 кейса).

Документация: TOOLS/ARCHITECTURE.md -> новый раздел «Modifier Idempotency»
(5 правил контракта); HISTORY — журнал раунда 5.

Проверено: go build ./... OK; go test ./internal/... -short PASS.
2026-09-30 21:07:49 +03:00
Repinoid 4197a76aba 1 2026-09-30 21:01:05 +03:00
Repinoid 575f1e29a4 docs(prompt): промпт Opus — код-ревью правок (раунд 5), ответ <= 10 строк 2026-09-30 20:55:05 +03:00
Repinoid b3cce5bb70 docs(history): раунд 4 — решения Q1-Q5 и их статус 2026-09-30 20:53:41 +03:00
Repinoid 7a6f6650c6 docs(architecture): зафиксированы решения Q1/Q2/Q4
- Q1: POST не ретраится (не идемпотентен; Idempotency-Key у API нет) — решение.
- Q2: при ошибке после POST /instanceOperations и до run операция остаётся черновиком;
  отмены нет (ни в коде, ни в HAR — DELETE /instanceOperations/{uid} отсутствует).
- Q4: единый контракт жизненного цикла — keep_on_destroy + suspend_on_destroy;
  delete_strategy (YAML) = маппинг на них (noop_warn/inverse/error).
2026-09-30 20:53:31 +03:00
Repinoid 9da97663c6 fix(Q5): сохранять instanceUid при ошибке после создания + partial state
Проблема: CreateGenericInstanceUniversalV6 при ЛЮБОЙ ошибке после создания инстанса
возвращал "", а шаблон Create при ошибке не писал ID в state => облачный инстанс
осиротевал (Terraform о нём не знает, повторный apply упирается в страж дубликатов).

- core/instance_create.go: ошибки после получения instanceUid возвращают uid вместе
  с ошибкой (POST /instanceOperations, пустой opUid, разбор cfsParams, resolve,
  отправка параметров, validate, run, waitForOperationFinish, ensureInstanceCreated).
  До создания uid — по-прежнему "".
- templates/instance.go: при err != nil и id != "" -> data.ID + resp.State.Set (partial
  state), затем AddError.
- client_test.go: TestCreateGenericInstance_KeepsUIDWhenOperationCreateFails,
  TestCreateGenericInstance_EmptyUIDWhenInstanceCreateFails.
- ARCHITECTURE.md: пункт про partial state.

Проверено: 02 (dev) + dev-materialize -> 40 файлов resources_gen содержат фикс;
go build ./... OK; go test ./internal/... -short PASS.
2026-09-30 20:53:14 +03:00
Repinoid 54f036e228 docs(history): замер Q3 — угадывание типа по имени не подтверждается
Замер по generated/dev/resources_yaml (40 файлов, только чтение):
- required-параметров: 852; с пустым data_type — 5;
- всего с пустым data_type: 12 (~1.2%); угадывание по имени даёт != '' только
  для 1 тестового (1_dummy.jsonExample) => гипотеза A4 не подтверждается,
  правка косметическая, не исправление дефекта.
2026-09-30 20:48:18 +03:00
Repinoid 5a0bb432ab docs: промпт Opus раунд 4 + журнал правок ядра/модификаторов
- NOTES/20_prompts/prompt_for_opus_remediation_round4.md — 5 коротких вопросов
  (retry POST, осиротевшая операция, zero-value по подстроке, единый словарь
  жизненного цикла, что упущено в ядре); ответ ≤ 25 строк.
- HISTORY/2026-09-30_core_and_modifiers_remediation.md — журнал: 6 коммитов,
  что отклонено (A3/A4/A5) и почему, что отложено (A2/B8/B9).
2026-09-30 20:42:30 +03:00
Repinoid 0e26e98384 docs(uuid-case): зафиксировать фактический механизм сохранения регистра
- core/refsvc.go: комментарий ссылался на несуществующий блок 'Restore user-provided
  casing' в instance.go. Факт: ref_svc исключены из read-back (InputField только при
  RefSvcId==0), UUID внутри JSON нормализуются при отправке (BuildJSON ->
  LowercaseUUIDsInText).
- docs/60_strategy/terraform_case_sensitivity_fix.md: §4 помечен как историческая
  справка (подхода originalVappUid в коде нет); актуальные §10-§11.

Проверено: go build ./... OK; go test ./internal/... -short -> PASS.
2026-09-30 20:38:37 +03:00
Repinoid 8519ba0f44 fix(modifiers): ImportState заполняет Required-атрибуты
Было: ImportState ставил только id + organization/nsxt_uid, оставляя Required-атрибуты
(vip_configure / ip_space_name) в null — Terraform не мог свести импорт с конфигом.

- nsxt_snat: importIpSpaceName(live) — live-значение, иначе канон no-needed.
- org_ip_allocation: importVipConfigure(live) — канонический JSON из live, иначе [].
- Чистые хелперы + тесты TestImportVipConfigure/TestImportIpSpaceName.

Проверено: go build ./... OK; go test ./internal/resources_core/... -short -> PASS.
Terraform import проверяется владельцем.
2026-09-30 20:36:47 +03:00
Repinoid ea75cac1a8 fix(core): idempotency pre-check сравнивает с live, а не с paramValue формы
Проблема: modifierDesiredEqualsCurrent сравнивает desired с paramValue из cfsParams
(дефолт ФОРМЫ операции), а не с состоянием инстанса. Пропуск modify на такой основе
может быть ложным (HAR/edge_.har: needEnableAVI paramValue=false при live=true).

- core/modifier_compare.go: добавлен modifierDesiredEqualsLive (источник —
  instanceLiveParams/state.params; неопределённость => не пропускаем) и хелперы
  modifierValuesEqual / modifierCodeMap; modifierDesiredEqualsCurrent переведён на них.
- core/operation_run_bycode.go: idempotent-путь использует live-pre-check; при ошибке
  чтения live modify НЕ пропускается.
- resources_core/nsxt_snat_resource.go: setSnat -> RunInstanceOperationUniversalByIdempotent
  (лишний modify на повторном apply больше не отправляется).
- modifier_compare_test.go: TestModifierDesiredEqualsLive (совпало/отличается/live недоступен).

Проверено: go build ./... OK; go test ./internal/core/... -short -> PASS.
2026-09-30 20:35:09 +03:00
Repinoid 383f8ea321 fix(core): транзиентный 401 теперь ретраится для GET
isRetryable (core/http.go): добавлен StatusUnauthorized (401) к {429,502,503,504}.
Gateway может временно отклонять валидный JWT — без этого одиночный 401 ронял
read/plan/поллинг.

- client_test.go: юнит-тест TestIsRetryable (401/429/502/503/504 = true; 400/403/404/500 = false).
- ARCHITECTURE.md: раздел API Resilience приведён к фактическому поведению
  (401 реализован; POST не ретраится намеренно).

Проверено: go build ./... OK; go test ./internal/core/... -short OK.
2026-09-30 20:33:48 +03:00
Repinoid c5a4499094 chore(tools): страж хардкодов покрыл provider/ + id сервиса в именованную константу
check_hardcoded_service_ids.sh:
- область расширена с TOOLS/ на TOOLS/ + provider/internal/ (кроме generated resources_gen/);
- второй паттерн: литеральный ref-service id в ResolveRefSvcParamValue/DisplayName(ctx, N,...);
- справка обновлена (убран удалённый serviceSpecificModifiers);
- сервис-специфичные литералы пояснены как 'именованные константы'.

org_ip_allocation_resource.go: ResolveRefSvcParamValue(ctx, 19, ...) -> svcIDVcOrg.

Проверено: bash TOOLS/scripts/check_hardcoded_service_ids.sh -> OK (exit 0).
2026-09-30 20:33:09 +03:00
Repinoid 047d53a67b docs(architecture): привести TOOLS/ARCHITECTURE.md в соответствие с кодом
- Core Principles 2-3: 'универсально/генерируется' отнесено к core/ и resources_gen/,
  а не ко всему сервис-коду.
- API Resilience: 401 НЕ ретраится (isRetryable = 429/502/503/504, только GET) —
  помечено как незакрытый разрыв со спекой.
- Exception Registry: убран удалённый реестр serviceSpecificModifiers
  (yaml-generator/main.go), описаны ручные модификаторы + несуществующий modifiers.yaml.
- Новый раздел 'Lifecycle Vocabulary': три несогласованных словаря destroy.
- Rules: 'two registries' -> один реестр + ручные ресурсы.
2026-09-30 20:32:29 +03:00
Repinoid 2c51b0392d docs(prompt): промпт для DeepSeek Pro — план правок кода/доков/архитектуры + план проверки
DeepSeek верифицирует гипотезы групп A (ядро: 401/POST-ретраи, обрыв modify, zero-value
fallback, нормализация Read) и B (модификаторы/спека), затем даёт план правок кода, правок
документации и архитектурных решений, трёхуровневый план проверки (юнит / plan-apply на
DEV_STAND/FullPipe / регрессия + стражи) и порядок работ по коммитам. Код не пишет — исполнять
будет Copilot. Журнал Opus-диалога дополнен ссылкой на этот шаг.
2026-09-30 20:20:31 +03:00
Repinoid 47e010edf3 docs(opus): дописаны пропущенные ходы журнала (Ход 10a, 12a, 14)
Записаны: запрос «твоё мнение?» по раунду 2; сообщение с путём к файлу раунда 3 и
отменённый уточняющий вопрос агента; запрос «мнение?» по раунду 3 и полное мнение агента
(в т.ч. сомнение в абсолютном выводе «401 не ретраится нигде» и в трактовке отсутствия
ретрая POST как дефекта). Статус обновлён: чат с Opus исчерпан по токенам.
2026-09-30 20:18:41 +03:00
Repinoid 96adf958bc docs(opus): раунд 3 отвечен — запись в журнал диалога
Дословно сырой лог и отчёт: 5 находок по ядру — 401 не ретраится (расхождение с
ARCHITECTURE.md:105-108), ретрай только для GET, обрыв modify после создания операции,
zero-value fallback по подстроке имени, нормализация Read только для jsonEnv/ref_svc.
Находки 1-3,5 не подтверждены замером.
2026-09-30 20:15:43 +03:00
Repinoid e46bc35b98 docs(opus): раунд 3 — фокус переведён на сам провайдер (устойчивость/корректность)
Жёсткий бюджет ради токенов: ≤10 файлов, ≤5 находок по ≤3 строки, плюс одна строка
«что проверяемо только замером». M6 снят, модификаторы — фон. Границы: ядро, resources_core,
шаблоны/хелперы генератора. В журнал добавлены крит-мнение по раунду 2 и текст раунда 3.
2026-09-30 20:11:24 +03:00
Repinoid e1e45423fa docs(opus): раунд 2 отвечен + вводная пользователя — запись в журнал диалога
Дословно: сырой лог и дельта Opus (M1 сверка номеров строк, M2 факт из check_hardcoded_service_ids.sh,
M3 снятие S4 и переклассификация S2, M4 шкала R2>R3>R6>R5, M5 разбор Read/вечного diff,
U1 modifiers.yaml не существует, U2 тройной словарь жизненного цикла, U3 варианты, M6 запрос двух файлов).
Плюс указание пользователя: модификаторы — небольшая часть, главное — сам провайдер.
2026-09-30 20:07:34 +03:00
Repinoid ea75507fe4 docs(opus): раунд 2 — замечания к отчёту Opus + запись в журнал диалога
Замечания M1–M5 (сверка номеров строк, нарушение «без догадок» в R2, натянутые S2/S4,
приоритет R5, пробел по устойчивости Read/вечный diff) и U1–U3 (modifiers.yaml не существует,
рассинхрон suspend_on_destroy/keep_on_destroy, корневая причина ручных модификаторов).
Разрешён дополнительный список файлов; право копать глубже передано Opus.
2026-09-30 19:59:44 +03:00
Repinoid dc85e7b4e0 docs(opus): полная запись диалога 2026-09-30 — промпт + отчёт Opus по архитектуре и модификаторам
Дословно, без сокращений: задание пользователя, разведка агента, содержимое промпта,
сырой лог сессии Opus и его отчёт (расхождения спека↔код S1–S5, риски R1–R6),
открытый вопрос Opus. Статус: диалог не завершён.
2026-09-30 19:57:36 +03:00
Repinoid 752244fa26 docs(prompt): промпт для Opus 4.8 — анализ архитектуры провайдера + ресурсов-модификаторов
Задача: разбор универсальной архитектуры и слоя модификаторов (nubes_vc_org_ip_allocation,
nubes_vc_nsxt_snat). Жёсткие границы доступа (запрет на HISTORY/NOTES/TMP/HAR/docs и git-историю),
исчерпывающий список из 22 файлов (1 спека + код + YAML-спеки + пример применения),
сжатый формат ответа, режим диалога с правом задать уточняющий вопрос.
2026-09-30 19:44:57 +03:00
Repinoid bed269cf27 release: перезаливка провайдера во все 3 стенда — prod 1.0.0, dev 2.0.0, test 3.0.0
Полный цикл 03 (01+02 → сборка 3 платформ → GPG → заливка S3) по каждому стенду:
- prod nubes/nubes 1.0.0;
- dev  nubes-dev/nubes 2.0.0  (VERSION в profile.env: 2.0.24 → 2.0.0);
- test nubes-test/nubes 3.0.0.

Проверено: sha256 залитого linux-бинарника == локальной сборке на всех трёх;
API /versions отдаёт 1.0.0 / 2.0.0 / 3.0.0; в S3 по 5 объектов на версию.

Последствия (приняты владельцем): версии X.0.0 перезаписаны → у пользователей
с .terraform.lock.hcl будет checksum mismatch (лечится terraform init -upgrade).
Подробности: HISTORY/2026-09-30_release_1_0_0_2_0_0_3_0_0_all_stands.md
2026-09-30 19:16:48 +03:00
Repinoid fd3ab32534 chore(dev-registry): физически удалены версии провайдера старше 2.0.21
В dev-реестре (s3://nubes-terraform-registry/.../nubes-dev/nubes/) удалены
версии 2.0.0–2.0.20 — 21 версия, 105 объектов (~800 MiB). Бакет un-versioned.

Осталось: 2.0.21, 2.0.22, 2.0.23, 2.0.24 (20 объектов).
Проверено: mc ls (20 объектов), API /versions (4), download 2.0.23/2.0.24 → HTTP 206
(ZIP), 2.0.0/2.0.20 → HTTP 404; nubes-test (3.0.0) и nubes (1.0.0) не тронуты.

Резервные копии zip не делались (прямое указание «стереть физически»);
восстановление — только пересборкой из git-истории.
Документация: HISTORY/2026-09-30_dev_registry_prune_versions.md, VERSIONS.md.
2026-09-30 10:50:45 +03:00
Repinoid 46dc548af4 docs(history): UUID-регистр — процедура релиза и карта точек нормализации
Перенесено из служебной памяти VS Code в файл репозитория:
- пошаговая процедура релиза dev (VERSION → 03 → curl-проверка → VERSIONS.md →
  dev-materialize), включая, что доки в реестр не публиковались;
- карта: нормализация нужна в двух местах (сравнение и отправка BuildJSON),
  перечень функций и правила (lower() — костыль; план целиком не нормализуем).
2026-09-30 10:32:22 +03:00
Repinoid 89bfb46b1c docs(history): этап 4 — перепроверка после перегенерации + подводные камни
Перенесено в файл репозитория (а не только в служебную память VS Code):
- результаты полной перегенерации и перепроверки всех трёх стендов;
- подводные камни: случайные default от API (детектор дрейфа по побайтовому
  сравнению не работает); случайный default вшивается в Go-код → drift 15 файлов
  сразу после перегенерации; generated/<стенд>/go|docs стареют после шага 01;
  403 без браузерного User-Agent (DDoS-Guard);
- актуальная карта пайплайна, токены, что удалено и что оставлено осознанно.
2026-09-30 10:30:41 +03:00
Repinoid 5d29010352 docs(history): этап 3 — сверка списков стендов с облачным каталогом
Зафиксирована методика: истина = GET /services?isProductionReady=true
(без фильтра API отдаёт все сервисы платформы, включая DEPRECATED).
Результаты по dev/test/prod и исправление prod (Vault).
2026-09-30 10:13:35 +03:00
Repinoid a68a36a0d2 fix(config): prod — включить Vault (151 k8sOpenbao) по сверке с облачным каталогом
Сверка TOOLS/config/prod/services_list.txt с облачным каталогом
(GET /api/v1/svc/services?isProductionReady=true → 36 сервисов):
- активных в файле было 35, лишних нет, но не хватало 151 k8sOpenbao (Vault);
- комментарий «нет в PROD UI» устарел: сервис отдаётся каталогом prod
  (isProductionReady=true, resourceRealmTypeId=3).

После правки: 36 активных = 36 в облаке, перегенерация prod дала 36 YAML,
включая 151_k8s_openbao.yaml. dev (40/40) и test (36/36) расхождений не имели.
2026-09-30 10:13:13 +03:00
Repinoid 5e1a6f06bc docs(history): этап 2 — удаление мёртвого легаси (что удалено, что оставлено)
- раздел «Этап 2» с таблицей удалённых файлов и обоснованием;
- зафиксировано, что НЕ удалено и почему (index.cfm-совместимость,
  справочная копия DOCS_PIPELINE/publish-docs.sh, исторические документы);
- результаты проверок после удаления (bash -n, smoke-прогон 01 dev).
2026-09-30 09:53:57 +03:00
Repinoid c822ae2f2a docs: актуализировать ссылки после удаления общего services_list.txt
- README.md, HOW_TO/README.md, HOW_TO/DEVOPS_BUILD_PIPELINE.md,
  HOW_TO/HOWTO_ADD_NEW_SERVICE.md, DOCS_PIPELINE/README.md:
  TOOLS/config/services_list.txt → TOOLS/config/<стенд>/services_list.txt;
- HOW_TO/HOWTO_ADD_NEW_SERVICE.md: блок «Быстрый старт» переписан с
  устаревших devops/-путей на канонические (./TOOLS/scripts/*, generated/<стенд>/);
- scripts/publish-doc-page.sh: примеры devops/profiles/<стенд> → TOOLS/config/<стенд>;
- .gitignore: убрана мёртвая строка devops/profiles/*/generated/.

Проверено: bash -n для всех TOOLS/scripts/*.sh и scripts/publish-doc-page.sh — OK.
2026-09-30 09:50:37 +03:00
Repinoid 1e796c8eb1 chore(tools): удалить мёртвые легаси-скрипты и общий services_list.txt
Удалено (100% мёртвое, ничего не вызывает):
- TOOLS/scripts/10_yaml_stability_run.sh
- TOOLS/scripts/11_yaml_stability_run_latest.sh
- TOOLS/scripts/12_generate_yamls_latest.sh
- TOOLS/scripts/13_generate_yamls_clean.sh
- TOOLS/scripts/02_generate_resources_and_docs_template_v2.sh
- TOOLS/config/services_list.txt (общий список: код его не читает, а как
  «объединение» он устарел — в нём активен id 27, который в test/prod
  закомментирован как «нет в UI», и отсутствуют 87/88/97/153 из dev)

Все ссылки в документации указывали на профильные списки либо будут
исправлены отдельным коммитом.
2026-09-30 09:50:28 +03:00