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 ## Core Principles
1) YAML per service is generated ONLY from API data. 1) YAML per service is generated ONLY from API data.
2) The provider core is universal and must not contain service-specific logic. 2) The provider core (`provider/internal/core`) is universal and must not contain
3) Service-specific Go code is fully generated from YAML. No manual edits. 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. 4) Documentation is generated from the same YAML.
5) Build artifacts for 3 OS targets are published to the registry, and docs are 5) Build artifacts for 3 OS targets are published to the registry, and docs are
published to the website. published to the website.
@@ -107,15 +109,23 @@ Each operation has a kind:
## Provider Model ## Provider Model
- Core is universal: no service-specific logic inside the core. - Core (`provider/internal/core`) is universal: no service-specific logic inside it.
- Generated service resources contain only schema/params and references. - 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 ### API Resilience
- Core MUST retry transient 401 errors from Gateway (3 attempts, exponential backoff). - Core MUST retry transient 401 errors from Gateway (3 attempts, exponential backoff).
Gateway may temporarily reject valid JWT tokens. Gateway may temporarily reject valid JWT tokens.
- GET operations (GetInstanceState, GetInstanceStateRaw) retry 401 with 2s/4s/8s backoff. - **CURRENTLY NOT IMPLEMENTED** — `isRetryable` (`core/http.go`) retries only
- `doRequest` treats 401 as retryable for GET requests (alongside 429, 502, 503, 504). {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 ### Generated Code Resilience
@@ -208,28 +218,49 @@ From the unified YAML, generate:
5) Upload provider artifacts to registry. 5) Upload provider artifacts to registry.
6) Build and publish docs to site. 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 ## Non-Negotiable Rules
- No manual edits to generated YAML or generated Go code. - 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. - The generator must enforce these rules and fail fast on drift.
## Exception Registry (service-specific DATA, never logic) ## Exception Registry (service-specific DATA, never logic)
Principle: provider core and generator logic are universal for all stands and 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 services. Service-specific deviations are of two kinds:
exactly two named registries:
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 | | 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 | | `serviceSpecificDocExamples` | `TOOLS/docs-generator/internal/writers/writers.go` | per-service doc examples, gated on service name + required state/vault keys |
Rules: Rules:
- Key by stable service NAME (slug), never by raw numeric ID. - Key by stable service NAME (slug), never by raw numeric ID.
- Each entry answers WHAT / WHAT IT DOES / WHY / WHERE (see code comments). - 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. - Never annotate API-YAML: it is machine-regenerated and edits would be lost.
Enforced by scripts (run before build/commit): Enforced by scripts (run before build/commit):