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' -> один реестр + ручные ресурсы.
This commit is contained in:
Repinoid
2026-09-30 20:32:29 +03:00
parent 2c51b0392d
commit 047d53a67b
+42 -11
View File
@@ -9,8 +9,10 @@ reflected here FIRST, then implemented in `gen_v2` and other tools.
## Core Principles
1) YAML per service is generated ONLY from API data.
2) The provider core is universal and must not contain service-specific logic.
3) Service-specific Go code is fully generated from YAML. No manual edits.
2) The provider core (`provider/internal/core`) is universal and must not contain
service-specific logic.
3) Service-specific Go code (`provider/internal/resources_gen`) is fully generated
from YAML. No manual edits to generated code.
4) Documentation is generated from the same YAML.
5) Build artifacts for 3 OS targets are published to the registry, and docs are
published to the website.
@@ -107,15 +109,23 @@ Each operation has a kind:
## Provider Model
- Core is universal: no service-specific logic inside the core.
- Generated service resources contain only schema/params and references.
- Core (`provider/internal/core`) is universal: no service-specific logic inside it.
- Generated service resources (`provider/internal/resources_gen`) contain only
schema/params and references.
- Hand-written service resources live in `provider/internal/resources_core` and are
registered in `provider/internal/provider/provider.go` `Resources()`. They are
NOT generated; they must not contain arbitrary service logic, only:
- a schema, and
- wiring between schema fields and the universal core API
(`RunInstanceOperationUniversalByCode`, `ResolveRefSvcParamValue`, etc.).
### API Resilience
- Core MUST retry transient 401 errors from Gateway (3 attempts, exponential backoff).
Gateway may temporarily reject valid JWT tokens.
- GET operations (GetInstanceState, GetInstanceStateRaw) retry 401 with 2s/4s/8s backoff.
- `doRequest` treats 401 as retryable for GET requests (alongside 429, 502, 503, 504).
- **CURRENTLY NOT IMPLEMENTED** — `isRetryable` (`core/http.go`) retries only
{429, 502, 503, 504}, NOT 401, and only for GET. This is a known gap versus the
intent above; fix in `core/http.go` `isRetryable`.
### Generated Code Resilience
@@ -208,28 +218,49 @@ From the unified YAML, generate:
5) Upload provider artifacts to registry.
6) Build and publish docs to site.
## Lifecycle Vocabulary (single contract)
⚠️ The destroy-behaviour vocabulary is currently INCONSISTENT across resource kinds:
1. generated instance resources: runtime flags `suspend_on_destroy` / `keep_on_destroy`;
2. generated modifiers: compile-time `delete_strategy` (no runtime flag);
3. hand-written modifiers: runtime `keep_on_destroy` only.
All three express the same intent ("what happens to the platform effect on destroy").
Canonical direction: one unified vocabulary/contract for all resource kinds.
## Non-Negotiable Rules
- No manual edits to generated YAML or generated Go code.
- Any change must come from API or generator logic updates.
- Any change to generated code must come from API or generator logic updates.
- The generator must enforce these rules and fail fast on drift.
## Exception Registry (service-specific DATA, never logic)
Principle: provider core and generator logic are universal for all stands and
services. The ONLY allowed deviations are DATA entries, and they MUST live in
exactly two named registries:
services. Service-specific deviations are of two kinds:
1. **Generated modifiers** — a `modify` op that should become a dedicated modifier
resource. The generator (`TOOLS/resource-generator/internal/loader/loader.go`)
supports `kind: modifier` with `delete_strategy` (`noop_warn`/`inverse`/`error`)
and `idempotency` (`none`/`check_before_run`). The overlay data file
`modifiers.yaml` that would drive this is **documented but NOT yet created**;
until then, modifiers are hand-written in `provider/internal/resources_core/`.
(The legacy registry `serviceSpecificModifiers` in `TOOLS/yaml-generator/main.go`
was REMOVED during the 2026-09-23 refactoring.)
2. **Doc examples** — named registry:
| Registry | File | Declares |
|---|---|---|
| `serviceSpecificModifiers` | `TOOLS/yaml-generator/main.go` | which service `modify` op becomes a modifier resource and its name (key = normalized service name) |
| `serviceSpecificDocExamples` | `TOOLS/docs-generator/internal/writers/writers.go` | per-service doc examples, gated on service name + required state/vault keys |
Rules:
- Key by stable service NAME (slug), never by raw numeric ID.
- Each entry answers WHAT / WHAT IT DOES / WHY / WHERE (see code comments).
- Adding an exception = editing one of these two registries → visible in diff.
- Doc-example exception = editing the named registry above → visible in diff.
- Modifier exception (until `modifiers.yaml` exists) = hand-written resource in
`provider/internal/resources_core/` + registration in `provider.go`.
- Never annotate API-YAML: it is machine-regenerated and edits would be lost.
Enforced by scripts (run before build/commit):