Files
autotest/polygon-docs/opus-architecture-audit-prompt.md

7.9 KiB
Raw Permalink Blame History

Архитектурный аудит polygon v0.2.5

Адресат: Claude Opus (новый чат) Дата: 2026-07-31 ОТВЕТ — ТОЛЬКО В ЧАТ. Не редактировать файлы.


1. Что такое polygon

Polygon — отдельный managed-сервис (polygon.pythonk8s.dev.nubes.ru), эмулирующий REST API облачной платформы Nubes. Нужен для интеграционных тестов приложения app-autotest — чтобы тесты гонялись не на реальном облаке, а на эмуляторе.

  • Flask 3.0 + gunicorn (1 воркер), деплой на Nubes pythonk8s
  • Всё состояние в памяти (MockState), без БД
  • Data-driven: конфиги сервисов генерируются из 37 STANDS YAML через from_stands.py
  • 17 API-эндпоинтов с префиксом /api/v1/svc
  • 19 юнит-тестов (pytest) + 15 интеграционных (в app-autotest)
  • Версия: v0.2.5, задеплоена и протестирована curl'ом

2. Архитектура

polygon/
├── requirements.txt          # Flask>=3.0, gunicorn>=21.2, PyYAML>=6.0
├── tests/
│   ├── test_converter.py     # 10 юнит-тестов from_stands.py
│   └── test_state_machine.py # 9 юнит-тестов state_machine.py
└── site/
    ├── app.py                # 57 строк: Flask() + 6 blueprint'ов + app.run()
    ├── routes/
    │   ├── root.py           # /health, / (Jinja2)
    │   ├── services_routes.py# /api/v1/svc/services
    │   ├── instances_routes.py# /api/v1/svc/instances
    │   ├── operations_routes.py# /api/v1/svc/instanceOperations/*
    │   ├── run.py            # /api/v1/svc/instanceOperations/<uid>/run
    │   └── mock_routes.py    # /api/v1/svc/_mock/*
    ├── mock_state.py         # MockState: instances, operations, op_params
    ├── state_machine.py      # apply_effect() — мутация состояния
    ├── config/
    │   └── loader.py         # SERVICES, OPS_INDEX, DELAY, VERSION
    ├── utils/
    │   ├── now.py            # now() — UTC ISO с 'Z'
    │   └── pluralize.py      # pluralize()
    ├── from_stands.py        # конвертер STANDS YAML → polygon config
    ├── static/style.css      # тёмная тема
    ├── templates/index.html  # Jinja2-шаблон
    └── services/             # 37 сгенерированных YAML-конфигов

Ключевые архитектурные решения:

Решение Обоснование
Blueprint'ы по доменам По шаблону app-autotest. 6 файлов вместо монолитного app.py (было 418 строк → 57)
In-memory state, 1 воркер Без БД, без гонок. WEB_CONCURRENCY=1 принудительно
Синхронный dtFinish sleep(MOCK_OP_DELAY) прямо в /run — без потоков, просто
Data-driven из STANDS YAML 37 сервисов генерится конвертером, не хардкод
Модульные переменные в config/loader.py SERVICES/OPS_INDEX/DELAY/VERSION — единый источник
import config.loader as _cfg Модульные переменные меняются на лету (_cfg.DELAY = x)
CSS/HTML отделены от Python static/style.css + templates/index.html — не в f-строках

3. Поток данных

STANDS YAML (37 файлов)
  → from_stands.py (html.unescape, sub_params→dataDescriptor, stateOut auto-gen)
  → services/*.yaml (37 конфигов)
  → config/loader.py (_load_all при импорте)
  → SERVICES + OPS_INDEX (модульные переменные)
  → routes/*.py (читают SERVICES/OPS_INDEX/DELAY)
  → MockState (create_instance → create_operation → run → apply_effect)

4. Что сделано (хронология)

  • Этап 1: from_stands.py — конвертер STANDS → polygon, 37 YAML
  • Этап 2: mock_state.py + state_machine.py + config/loader.py
  • Этап 3: app.py — 17 эндпоинтов (потом разнесены на blueprint'ы)
  • Code Review #1 (Sonnet): 12 находок, 2 крит. исправлены (workers=1, KeyError в _merge_params)
  • Decouple: монолит → blueprint'ы + CSS/HTML разделение
  • Code Review #2 (Sonnet): 9 находок — _cfg.DELAY, VERSION в config/loader, мёртвые импорты
  • Интеграция с app-autotest: auth.py — STANDS-check, v1.2.24
  • 🟡 фиксы: json.dumps вместо ручного JSON, 409 при повторном run, MOCK_AUTH_TOKEN
  • Интеграционные тесты: 15 тестов в app-autotest, все PASS

5. Что проверять

Архитектура

  • Правильно ли выбран паттерн blueprint'ов? Не переусложнено ли?
  • Модульные переменные в config/loader.py — адекватный подход или есть лучше?
  • In-memory state с 1 воркером — масштабируемо ли для CI (параллельные тесты)?
  • Есть ли архитектурные дыры: что будет при 1000 инстансов? При рестарте сервера?

Поток данных

  • Не теряются ли данные между этапами: STANDS → YAML → loader → state?
  • Все ли поля маппятся корректно? (dataDescriptor, valueList, stateOut)
  • Правильно ли обрабатываются subresources (create_user, create_database)?

API-совместимость

  • Все ли форматы ответов совпадают с реальным Nubes API?
  • Location-заголовки, пустое тело validate-cfs, 201/404/409 коды?
  • Пагинация: стоп по len < pageSize, cap 200?

Безопасность

  • _mock/* защищены MOCK_AUTH_TOKEN — достаточно?
  • Нет ли утечек данных между тестами (autouse reset в conftest)?
  • Что будет при отправке невалидного JSON в POST /instances?

Что дальше

  • Готов ли polygon к CI/CD?
  • Что нужно для продакшен-использования (не только тесты)?
  • Какие мониторинг/логирование нужны?

6. Вопросы к Опусу

Q1. In-memory vs Redis

Сейчас всё в MockState.instances (dict). При рестарте сервера всё теряется. Для CI это ок (тесты стартуют заново). Нужен ли персистентный слой? Redis? Файлы?

Q2. Масштабирование

1 воркер, 1 процесс. Если запустить параллельные тесты (несколько pytest-сессий) — каждая поднимет свой polygon на своём порту? Или один общий сервер?

Q3. Генерация YAML

Сейчас from_stands.py запускается вручную, результат коммитится. Стоит ли генерить YAML при старте сервера (если STANDS_DIR задан)?

Q4. Мониторинг

Нужны ли метрики: количество инстансов, операций, latency? Prometheus-экспорт? Или только Grafana-логи как сейчас?

Q5. Общая оценка

Готов ли polygon к использованию в CI app-autotest? Что критично доделать?