docs(opus): дописать ответы №2 (inverse/schema/current/idempotency/skip)
This commit is contained in:
@@ -113,3 +113,81 @@ No-op Delete = скрытый drift (класс D). Пока обратный pa
|
||||
(а не хардкодом в коде reconcile)?
|
||||
5. **Что если желаемое == текущее, но была «частичная» ошибка ранее** — пропускать run
|
||||
безопасно всегда, или есть исключения?
|
||||
|
||||
---
|
||||
|
||||
# Ответы Opus №2 (уточнения по 5 вопросам)
|
||||
|
||||
## 1. inverse-Delete — только декларативно в YAML, хардкод запрещён
|
||||
|
||||
Обратный payload зависит от параметров: `needEnableAVI:false` валиден, а
|
||||
`virtualServicesCount` (`integer > 0`) обнулить нечем → `0` невозможен.
|
||||
Значит inverse-значения задаются **явным блоком в YAML**. Если хоть один параметр
|
||||
не имеет валидного inverse — стратегия `inverse` недопустима (fail-fast в загрузчике).
|
||||
Для `ip_space` inverse нет вообще → только `noop_warn`.
|
||||
|
||||
## 2. Точная схема YAML новых полей
|
||||
|
||||
```yaml
|
||||
operations:
|
||||
- kind: modifier
|
||||
modifier: network
|
||||
action: modify
|
||||
delete_strategy: noop_warn # enum: noop_warn | inverse | error
|
||||
idempotency: check_before_run # enum: none | check_before_run
|
||||
delete_params: # обязателен ТОЛЬКО при delete_strategy: inverse
|
||||
- code: needEnableAVI
|
||||
value: "false"
|
||||
params: [...]
|
||||
```
|
||||
|
||||
Go-контракт (`OperationSpec`):
|
||||
```go
|
||||
DeleteStrategy string `yaml:"delete_strategy,omitempty"` // "" → noop_warn
|
||||
Idempotency string `yaml:"idempotency,omitempty"` // "" → none
|
||||
DeleteParams []ParamSpec `yaml:"delete_params,omitempty"`
|
||||
```
|
||||
|
||||
Дефолты: `delete_strategy` → `noop_warn`; `idempotency` → `none`.
|
||||
Fail-fast в `ValidateSpec`: значение вне enum → ошибка; `inverse` с пустым
|
||||
`delete_params` → ошибка; `delete_params.code` нет в `params` → ошибка; inverse-значение
|
||||
нарушает constraint параметра → ошибка на этапе генерации.
|
||||
`GenModifier` получает `DeleteStrategy`, `Idempotency`, `DeleteParams`.
|
||||
|
||||
## 3. Откуда читать current + как сравнивать
|
||||
|
||||
**Читать из `state_params`, отдельный GET не делать** (это уже источник истины для Read;
|
||||
второй источник = риск рассогласования).
|
||||
|
||||
Сравнение по типу:
|
||||
| Тип | Как сравнивать |
|
||||
|---|---|
|
||||
| bool/int/string | равенство после `normalizeUniversalValueV6` |
|
||||
| map-fixed | `JSONStringsEquivalent` (игнор порядка ключей) |
|
||||
| array-map-fixed | deep-equal с сохранением **порядка элементов** (порядок значим) |
|
||||
|
||||
Порядок ключей map-fixed — нормализовать (не значим). Порядок элементов
|
||||
array-map-fixed — НЕ нормализовать (значим).
|
||||
|
||||
## 4. idempotency декларативно
|
||||
|
||||
Поле `idempotency` на modify-операции в YAML → `ValidateSpec` → `GenModifier.Idempotency`
|
||||
→ шаблон `modifier.go` в `reconcile()` эмитит pre-check `{{- if eq .Idempotency "check_before_run" }}`.
|
||||
Для `ip_space` — в YAML; для остальных — дефолт `none`.
|
||||
|
||||
## 5. Когда безопасно skip run при desired == current (НЕ всегда)
|
||||
|
||||
Три условия безопасного skip:
|
||||
1. **Инстанс idle** — если pending/in-progress, сначала `waitForInstanceIdle`, потом
|
||||
перечитать `state_params` (иначе mid-flight аллокация даст ложное «уже равно»).
|
||||
2. **current из живого state_params, НЕ из TF-state** — после частичной ошибки TF-state
|
||||
может врать, а state_params отражает реальную платформу.
|
||||
3. **Сравнение по всем полям, не по одному** — skip только при совпадении ВСЕХ полей.
|
||||
|
||||
Итог:
|
||||
```
|
||||
idle? нет → wait, re-read
|
||||
всё-live == всё-desired? да → skip run
|
||||
иначе → reconcile (полный payload)
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user