doc: полная хронология реализации polygon v0.2.0 (4 этапа)

This commit is contained in:
2026-07-31 20:40:58 +04:00
parent 6978d13d0e
commit de6217e07b
2 changed files with 161 additions and 1 deletions
+160
View File
@@ -551,3 +551,163 @@ polygon/
- YAML не руками — через `from_stands.py` из STANDS (37 сервисов) - YAML не руками — через `from_stands.py` из STANDS (37 сервисов)
- `site/__init__.py` ⛔ нельзя - `site/__init__.py` ⛔ нельзя
- Импорты без префикса `site.` - Импорты без префикса `site.`
---
## Полигон — реализация (2026-07-31, DeepSeek Pro 4)
### Архитектура утверждена (Sonnet 4.6)
Промпт Соннету в `polygon-docs/sonnet-polygon-prompt.md`, ответ в `polygon-docs/sonnet-response.md`.
Ссылки на генератор YAML: `polygon-docs/tf-provider-refs.md`.
Ключевые решения Соннета (отличия от Опуса):
- subresources: `kind == "subresource"` из STANDS YAML
- dtFinish: синхронный в `/run` (sleep → apply → dtFinish)
- Лишние операции (restart, recovery): включать все, no-op
- stateOut: авто-генерация из subresource-операций
- map с sub_params → dataDescriptor для всех типов
- 11 тестов (против 5 у Опуса)
- UUID: `uuid.uuid4()`
- Mock-эндпоинты: +`/_mock/state`, `/_mock/services`, `/_mock/delay`
Уточнения:
- Синхронный dtFinish (блокирует воркер, но MOCK_OP_DELAY ≤ 0.5s)
- Вариант Б: сгенерированные YAML коммитятся в репу (НЕ генерить на лету)
- `from_stands.py <STANDS_DIR>` — без хардкода, читает все .yaml из директории
### Сервис запущен на Nubes
- URL: `https://polygon.pythonk8s.dev.nubes.ru/`
- Репа: `https://gitea.services.ngcloud.ru/forcloud/polygon.git`
- InstanceUid: `db9d7835-1ef8-4fee-b42f-c91e1c0783cb`
- Мониторинг: Grafana (namespace db9d7835...)
### Этап 1 — from_stands.py (`77f12d2`)
Создан универсальный конвертер STANDS YAML → polygon config:
- `html.unescape()` для всех строк (`&gt;``>`, `&quot;``"`)
- Рекурсивный `dataDescriptor` из `sub_params` (для map, map-fixed, array-map-fixed)
- Авто-генерация `state_out_template` из subresource-операций
- `stateParams` из create-операции с JSON-генерацией для map-fixed
- `cfsParamsByOp` — связка opId → список paramId
- 210 строк, 37 YAML сгенерировано, 0 ошибок
- Все YAML валидны, HTML entities раскодированы
### Этап 2 — config_loader + mock_state + state_machine (`1956fb7`)
**config_loader.py** (50 строк):
- Загружает все YAML из `services/`, строит `{svcId: def}` + `{opId: def}`
- 37 сервисов, 245 операций в индексе
**mock_state.py** (150 строк):
- `MockState` синглтон: instances, operations, op_params
- `create_instance()` → UUID v4, статус "creating"
- `create_operation()` → UUID v4, dtFinish=None
- `list_instances()` с пагинацией (pageSize≤200, стоп по len<pageSize)
- `set_param()`, `get_params()`, `reset()`
**state_machine.py** (140 строк):
- `apply_effect()` — мутирует MockState по kind/action:
- instance+create → статус running, stateParams из шаблона, stateOut из шаблона
- instance+modify → мерж params через cfsParamsByOp
- instance+delete → удалить инстанс
- instance+suspend/resume/redeploy → статус
- subresource+create → state.out[plural][name] = {}
- subresource+delete → del state.out[plural][name]
- `_extract_subresource_name()` — ищет имя в op_params, fallback на subresource_name
### Этап 3 — app.py: 17 эндпоинтов (`d4c2a26`)
| # | Метод | Путь | Детали |
|---|-------|------|--------|
| 1 | GET | `/health` | "OK" |
| 2 | GET | `/` | HTML: версия, счётчики, delay |
| 3 | GET | `/api/v1/svc/services` | список всех сервисов |
| 4 | GET | `/api/v1/svc/services/<id>` | операции сервиса |
| 5 | GET | `/api/v1/svc/instances` | пагинация (pageSize, page) |
| 6 | GET | `/api/v1/svc/instances/<uid>` | полный instance+state |
| 7 | POST | `/api/v1/svc/instances` | 201 + Location: ./{uid} |
| 8 | GET | `/api/v1/svc/instanceOperations/default/<id>` | cfsParams с dataDescriptor |
| 9 | POST | `/api/v1/svc/instanceOperations` | 201 + Location, auto-find create opId |
| 10 | GET | `/api/v1/svc/instanceOperations/<uid>` | +cfsParams если ?fields=... |
| 11 | POST | `/api/v1/svc/instanceOperationCfsParams` | paramId → value |
| 12 | GET | `/api/v1/svc/instanceOperations/<uid>/validate-cfs` | **пустое тело**, 200 |
| 13 | POST | `/api/v1/svc/instanceOperations/<uid>/run` | sleep(delay) → apply_effect → dtFinish |
| 14 | POST | `/api/v1/svc/_mock/reset` | сброс состояния |
| 15 | GET | `/api/v1/svc/_mock/state` | отладка: instances + operations |
| 16 | GET | `/api/v1/svc/_mock/services` | отладка: все сервисы |
| 17 | POST | `/api/v1/svc/_mock/delay/<s>` | изменить MOCK_OP_DELAY |
Критические детали:
- `default/<int:op_id>` строго ДО `<uid>` в маршрутах Flask
- `validate-cfs`: `return "", 200` (НЕ jsonify)
- `_now()`: ISO-формат с 'Z'
### v0.1.0 → v0.2.0 (`4e136cd`)
Bump версии после трёх этапов изменений.
### Этап 4 — тесты (`760d16e`)
**test_converter.py** (10 тестов):
- basic_fields, lifecycle, operations_count
- html_unescape, value_list, state_params_from_create
- data_descriptor_from_sub_params, state_out_subresources
- cfs_params_by_op, roundtrip (запись/чтение YAML)
**test_state_machine.py** (9 тестов):
- create → running + params + state.out
- delete → инстанс удалён
- suspend → suspended
- resume → running
- modify → params мержатся
- create_user → state.out.users[name]
- delete_user → users[name] удалён
- reset → всё пусто
**Все 19 тестов PASS.**
### Проверка в кубере
```bash
ssh naeel@5.172.178.213 kubectl -n db9d7835... logs deploy/pythonk8s --tail=20
```
- Под: `1/1 Running`, перезапущен
- Логи: все curl-запросы (201, 200), ни одной ошибки
### Проверка curl (deployed)
```bash
curl https://polygon.pythonk8s.dev.nubes.ru/health → OK
37 services, create flow: 201+Location → run → status=running, params=12
```
### Файлы polygon-docs/ (в корне autotest)
- `sonnet-polygon-prompt.md` — промпт для Claude Sonnet 4.6
- `sonnet-response.md` — полный ответ Соннета (архитектура + план)
- `tf-provider-refs.md` — ссылки на генератор YAML в `~/tf_provider`
### Итоговая структура polygon
```
polygon/
├── requirements.txt
├── README.md
├── .gitignore
├── tests/
│ ├── test_converter.py # 10 тестов
│ └── test_state_machine.py # 9 тестов
└── site/
├── app.py # 17 эндпоинтов
├── mock_state.py # MockState (in-memory)
├── state_machine.py # apply_effect()
├── config_loader.py # загрузка YAML
├── from_stands.py # конвертер STANDS → polygon
└── services/ # 37 сгенерированных YAML
```
~900 строк Python, 37 YAML-конфигов, 19 тестов PASS.
Задеплоено, проверено через curl и kubectl.
Готово к интеграции с app-autotest.
+1 -1
View File
@@ -16,7 +16,7 @@
| `2026-07-24-session-6.md` | 24.07.2026 | Сессия 6 | | `2026-07-24-session-6.md` | 24.07.2026 | Сессия 6 |
| `2026-07-29-session.md` | 29.07.2026 | Сессия: CMDB delete, переписка с Георгием | | `2026-07-29-session.md` | 29.07.2026 | Сессия: CMDB delete, переписка с Георгием |
| `2026-07-30-session.md` | 30.07.2026 | Сессия | | `2026-07-30-session.md` | 30.07.2026 | Сессия |
| `2026-07-31-session.md` | 31.07.2026 | **Текущая.** Аудит Codex (3 раунда), полигон (план + отдельная репа), v1.2.16→v1.2.23 | | `2026-07-31-session.md` | 31.07.2026 | **Текущая.** Основная сессия: унификация executor (v1.2.0-v1.2.16), аудит Codex (3 раунда, v1.2.19-v1.2.23), архитектура полигона (Опус + Соннет), **реализация polygon v0.2.0** (4 этапа, 17 эндпоинтов, 19 тестов PASS) |
## Формат ## Формат