Files
autotest/polygon-docs/sonnet-compare-testing-prompt.md
T

9.7 KiB
Raw Blame History

Соннет: анализ сравнительного тестирования Polygon ↔ реальный Nubes API

Адресат: Claude Sonnet 4.6 (новый чат) Режим: диалог. Задавай встречные вопросы если нужно уточнение. НЕ редактировать файлы. Только анализ и советы в чат.


Контекст

Polygon (v0.5.4) — эмулятор REST API облачной платформы Nubes. 3 стенда: dev (37 сервисов), test (37), prod (35). YAML-конфиги генерируются из терраформ-репы (~/tf_provider/generated/{dev,test,prod}/resources_yaml/).

Реальное API:

  • https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc
  • https://lk-api-gateway-test.ngcloud.ru/api/v1/svc
  • https://lk-api-gateway.ngcloud.ru/api/v1/svc

Токены в secrets/{dev,test,prod}.token.

Что сделано

Написан скрипт compare_test.py который сравнивает read-only эндпоинты полигона и реального API:

  • GET /services — список сервисов
  • GET /services/{id} — операции (svcOperationId, operation, kind, action)
  • GET /instanceOperations/default/{id} — cfsParams (id, код, dataType, isRequired)

Первый прогон показал:

  • dev: операции совпадают, но у 2 параметров dataType: None вместо "string"
  • test: аналогично
  • prod: чисто, расхождений нет

Также обнаружено что реальный API возвращает HTML-entities в dataType (integer >= 0), а полигон — чистый текст (integer >= 0). Полигон здесь правильнее реального API.

Ключевой нюанс: идеология стендов

Стенды НЕ идентичны. Dev опережает test, test опережает prod. Новые сервисы и параметры появляются сначала в dev, потом через какое-то время попадают в test, и только затем в prod. Поэтому:

  • Если в dev-полигоне и dev-реальном API есть расхождения — это может быть нормально (реальный API уже обновился, а YAML в полигоне — ещё нет)
  • Если в prod есть расхождения — скорее всего баг в генерации YAML
  • Нужно различать «допустимое отставание» и «реальный баг»

Что нужно от тебя

1. Стратегия сравнительного тестирования

Как правильно сравнивать полигон с реальным API учитывая что:

  • Стенды могут и должны отличаться
  • YAML генерируется не в реальном времени, а батчами из терраформа
  • Некоторые сервисы есть в реальном API но НЕ в терраформе (их не тестируем)

Что должно считаться PASS, а что FAIL? Какие допуски?

2. Какие ещё эндпоинты сравнивать?

Сейчас сравниваются 3 read-only эндпоинта. Какие ещё можно безопасно сравнять? Что ещё есть в реальном API такого что полигон должен повторять один-в-один?

3. Периодичность и автоматизация

Как часто запускать сравнение? При каких событиях (изменение терраформа, деплой полигона)? Должно ли это быть частью CI?

4. dataType: None

В from_stands.py для некоторых параметров dataType падает в None (хотя дефолт "string"). Где конкретно искать причину?

5. Общие советы

Что ещё мы упускаем в тестировании полигона? Какие сценарии, краевые случаи, проверки контрактов?


Формат диалога

Ты можешь:

  • Сразу дать развёрнутый ответ по всем пунктам
  • Или задать уточняющие вопросы — и тогда я отвечу, а ты продолжишь

Я хочу чтобы в итоге получился конкретный план действий: что тестировать, как часто, что считать ошибкой, что — допустимым расхождением.


Ответ Соннета (2026-08-02)

4. dataType: None — первопричина найдена

dict.get(key, default) возвращает default только если ключ отсутствует. Если в YAML написано data_type: null — ключ есть, значение — None, дефолт "string" не срабатывает.

Мои ответы

Q4.1 — data_type: null в YAML? Проверил — в терраформ-YAML нет data_type: null. Реальный API возвращает dataType: null для параметра nestedRefExample (param 396). Полигон возвращает "string" — он ПРАВИЛЬНО применяет дефолт там, где реальный API отдаёт null. Это не баг полигона, а улучшение.

Q4.2 — _convert_sub_params? Та же уязвимость потенциально есть, но не проявляется — sub_params всегда имеют data_type.

Q1.1 — частота регенерации YAML? ВРУЧНУЮ. from_stands.py запускается человеком когда он вспомнит. Никакого cron/webhook.

Q1.2 — лаг от реального API до YAML? Непредсказуемо. От часов до недель. Зависит от того когда кто-то запустит from_stands.py.

Q1.3 — потребитель результатов? Разработчик. Ему нужно знать «полигон устарел, перегенери YAML», а не «полигон сломан».

Q2.1 — дополнительные эндпоинты в реальном API? Не проверял. Надо сравнить полный список эндпоинтов.

Q2.2 — lifecycle поля? Не сравниваются в текущем compare_test.py. Надо добавить.


Ответ Соннета — раунд 2

Три категории расхождений — 👍 принимаю

Категория Значение Реакция
🔴 REAL BUG полигон ≠ реальный API, полигон неправ FAIL
🟡 LAG новый параметр в реальном API, нет в полигоне WARN
🟢 POLYGON BETTER реальный API отдаёт null/entities, полигон — правильно INFO

Для prod 🟡 LAG тоже должен быть заметен.

Мои ответы — раунд 2

Q5.1 — сервис есть в полигоне, пропал из реального API? Теоретически да — если сервис удалили из реального API, а terraform ещё не обновили. Это 🔴 REAL BUG и должно быть FAIL. Полигон не должен эмулировать несуществующие сервисы.

Q5.2 — HTML-entities? Нормализовать при сравнении: html.unescape() для real API перед сравнением. Считать 🟢 POLYGON BETTER, не ошибка.

Q5.3 — lifecycle поля? Проверил — ни реальный API, ни полигон НЕ возвращают lifecycle в GET /services/{id}. Сравнивать нечего, вопрос снят.


Ответ Соннета — раунд 3 (финальный)

Q6.1 — defaultValue, valueList и др.

Реальный API возвращает 29 полей на каждый cfsParam: defaultValue, valueList, isModifiable, isRequired, isHidden, descr, man, regex, maxlength, minvalue и т.д. Полигон возвращает подмножество из ~6-8 полей.

Сравнивать нужно только те поля, которые from_stands.py реально генерирует: defaultValue, valueList, isModifiable, isRequired. Остальные либо отсутствуют в терраформ-YAML, либо не имеют смысла для мока.

Q6.2 — cfsParamsByOp

Это внутренний индекс полигона, не API-эндпоинт. Связь «какие параметры к какой операции» уже проверяется через GET /instanceOperations/default/{id} — если в ответе правильный набор параметров, значит cfsParamsByOp правильный. Отдельно сравнивать не нужно.

Q6.3 — формат вывода

stdout + exit code — достаточно. Разработчик запускает вручную, смотрит глазами. Файл отчёта переусложнит. Если понадобится история — можно потом.