API changelog и migration guides

Release notes для совместимых v1 изменений, deprecation notices и migration guide шаблоны держатся рядом с OpenAPI, reference и SDK, чтобы клиенты видели не только endpoint, но и историю контракта.

Release notes

Каждая совместимая public API поставка получает запись, где указаны affected operationIds, additive fields, docs examples и validation gates. Breaking removal требует новой major версии или завершенного deprecation path.

Классификация изменений

Каждая запись получает одну категорию совместимости, чтобы интеграторы отделяли обычные дополнения, миграции, новую major версию и действия по безопасности.

Additive
Совместимые optional fields или operations с синхронными OpenAPI, SDK, examples и tolerant-client evidence.
Deprecated
Старый flow сохраняется на период уведомления, пока опубликованы replacement, telemetry, migration guide и support guidance.
Breaking или new major
Несовместимое удаление или изменение смысла выпускается только в новой major версии либо после завершенного deprecation path.
Security
Security notes сообщают влияние и нужное действие клиента без опасных деталей. Небезопасная совместимость проходит emergency migration процесс.
Stable candidateAdditive

SLO, freshness и capacity budgets

Public API получил числовые product SLO, strong If-Match для mutable writes и admission budgets до provider signing.

  • Цели: availability ≥99.9%, latency p95 ≤2000 ms, catalog p95 ≤15 s, search index p95 ≤1800 s, RPO ≤24 h и RTO ≤4 h; warning/critical alerts срабатывают до breach.
  • Mod и ModVersion PATCH требуют strong If-Match и возвращают новый ETag. Missing validator даёт 428, malformed/weak/wildcard/list — 412 без mutation, а корректный stale — 412 с текущим ETag; старые SDK сохраняют Problem Details и status.
  • Multipart default изменён на 16 MiB × 4 после live R2 capacity probe. Primary и fallback download admission проверяют authoritative size, actor/client concurrency и byte buckets до дорогого signing; leases восстанавливаются после failure или expiry.
Stable candidateAdditive

Универсальные domain ID и lifecycle

Все 13 публичных сущностей получили единые opaque UUID, ownership/state rules, tombstone/410 non-reuse и immutable snapshot опубликованной версии без удаления legacy aliases.

  • Game, Mod, ModVersion, Artifact, Blob, UploadSession, DownloadGrant, User, Team, Dependency, Job, WebhookSubscription и WebhookDelivery имеют отдельные UUID и fail-closed state machines. Rename сохраняет ID; slug, filename, URL, storage key, ETag и hash не являются identity.
  • Archive можно восстановить, permanent delete оставляет retained tombstone и возвращает 410. UUID и source binding никогда не переиспользуются; неизвестный ID возвращает 404.
  • Первая публикация фиксирует canonical snapshot и SHA-256. Semantic fields immutable; restore требует точного snapshot и текущих upload-trust gates. lifecycle_version защищает concurrent updates. Старые uploaded/quarantined/approved/rejected values остаются compatibility aliases.
Stable candidateAdditive

Fail-closed compensation boundaries

PR-F2.6.6 и PR-F2.6.7 фиксируют replay и recovery для контрольных точек provider upload commit, ready binding, publish/outbox и trust enqueue без ослабления trust или publication preconditions.

  • Cross-provider transaction не заявляется. Once-only generation byte-budget checkpoint предшествует atomic session/file/upload.accepted reservation; replay между ними использует тот же budget result. Каждый single PUT возвращает signed If-None-Match: * и максимум 900-second URL lease, row-lock checkpointed после sign и до response; abort-winning checkpoint отклоняет URL. Conditional 412 ведёт в complete для authoritative HEAD/seal/SHA-256. Затем session-level claim условно копирует точный client-source ETag в write-once server-only seal до queued scan checkpoint.
  • Heartbeat-backed claim token ограждает каждую scan mutation. Ready, quarantine и rejection атомарно фиксируют session/file/job state, audit и canonical event; terminal replay точно перечитывает и проверяет этот envelope. Перед provider config и normal claim bounded DB-only sweep восстанавливает stale max-attempt claim без повторного scan/provider work: coherent state атомарно получает canonical manual review/quarantine, а incoherent state terminal-fail-ит только exact job для видимого manual intervention. Same-SHA final promotion использует durable SHA/bucket/key claim, canonical MIME и cf-copy-destination-if-none-match: *; fresh duplicate ждёт или принимает ready blob без расхода normal scan attempt. Polling экспоненциальный и ограничен 15 минутами на claim. Первые два durable token-fenced yield атомарно восстанавливают normal attempt и requeue-ят job с DB-owned jitter 30–60 секунд; третий атомарно создаёт manual review/quarantine с exact lost-response replay вместо бесконечного retry. Lost copy response требует exact HEAD и nonblank ETag. Content-addressed final copy становится ready только после accessible attested blob и atomic ready/audit/file.ready binding. Transactional publish и durable outbox тоже используют одну transaction. Quarantine scan.completed и последующее file.ready сохраняют разные идентификаторы. Account-inbox notification не является lifecycle acknowledgement.
  • После lost response same Idempotency-Key повторно получает только тот же generation claim и сходится без дублирования budget, audit, job, terminal-event или outbox effects. Для single cleanup durable stage 1 условно пишет zero-byte tombstone и проверяет provider ETag, LastModified, metadata token и size=0; fence удерживается до latest URL lease и минимум 16 минут. Stage 2 exact-delete/HEAD-проверяет staging и завершает DB; crash replay продолжает stage. Multipart cleanup abort-ит и relist-ит exact-key uploads, каждый seal claim key удаляется и проверяется, quarantine сохраняется. Desired CORS включает If-None-Match, object-level probe подтверждает conditional copy и late-PUT tombstone rejection, но live CORS/lifecycle/lock evidence остаётся BLOCKED до CLOUDFLARE_API_TOKEN, MODDINGFLOW_R2_FINAL_LOCK_MIN_SECONDS и MODDINGFLOW_R2_ALLOWED_BROWSER_ORIGINS; live deployment не заявляется. Unbound final copy remains non-ready и never publishable до PR-F3.13 reference-aware legal-hold-safe deletion. Numeric freshness остаётся PR-F2.6.3, deployed webhook enablement — PR-F8.14.
Stable candidateAdditive

Managed artifact expansion

Optional PublicModVersion.artifacts добавляет complete metadata для managed primary artifact, сохраняя artifact_ids как стабильную v1 связь.

  • Expansion доступен только при size_bytes > 0, точном sha256/hashes.sha256, current upload-session match по file_id и final_blob_id, actual AV scan_status=clean, lifecycle=ready, publication state=published и managed resolve eligibility.
  • Полный artifact содержит role/category, display и nullable platform hints, integrity fields, actual AV state и provider-opaque download_metadata с relative resolve_endpoint и truthful range_supported.
  • Для legacy artifact поле artifacts будет omitted, а artifact_ids сохранится; API не фабрикует metadata и не раскрывает provider URL.
  • PR-F2.6.4 фиксирует bounded freshness: version write — committed private/no-store, anonymous catalog/version GET — eventual shared cache; cached PublicModVersion artifact expansion требует scan_status=clean, lifecycle=ready и publication state=published и остаётся eventual; direct resolve/install plan — private point-in-time reads по eligible target, чьё established state может быть approved или published. Current inventory содержит 53 approved public legacy targets и 4 published targets, поэтому direct eligibility не является published-only или legacy-only. Upload status показывает current DB state at request, worker transitions eventual, progress.available=false означает unknown; install plan — deterministic private/no-store request-time snapshot; webhooks feature-gated, eventual, at-least-once, replayable и unordered, с no delivery promise while disabled. Numeric catalog convergence остаётся PR-F2.6.3, live webhook rollout — PR-F8.14.
Stable candidateAdditive

Граница целостности download

OpenAPI теперь машинно различает stored-object SHA-256 и transport representation validator, не выдавая ETag за content hash.

  • sha256 и hashes.sha256 покрывают полный immutable stored object; клиент сначала сверяет size_bytes, собирает все Range части и только затем проверяет SHA-256.
  • ETag является opaque non-cryptographic validator одной transport representation, не служит file identity и может измениться между primary, refreshed и fallback providers.
  • RFC 9530 Content-Digest и Repr-Digest текущим signed transport не гарантируются; fail-closed OpenAPI lint запрещает ложные header или transcoding claims.
Stable candidateAdditive

Принятие асинхронного завершения upload

Upload completion теперь отличает принятую фоновую работу от уже terminal результата, сохраняя тот же response DTO и идемпотентные side effects.

  • POST /v1/uploads/{upload_id}/complete возвращает 202 Accepted для queued или processing job и требует, чтобы Location в точности совпадал с data.job.statusEndpoint.
  • Terminal или synchronous результат возвращает 200 OK без Location; replay с исходным Idempotency-Key сохраняет committed status/header без повторения storage, audit или webhook effects.
  • Additive status покрыт generated OpenAPI, curated examples, lint failures и retained TypeScript, Python и C# client probes.
Beta toolingAdditive

Official CLI и SDK compile gate

Source distribution теперь включает official Node.js CLI для creator upload automation и отдельный compile gate для каждого языка generated SDK.

  • npm run api:cli дает credential check, archive validation, upload create/resume/complete/status и полный API-key-to-publish command, не принимая secrets через argv.
  • Production, local sandbox и выданные оператором protected staging base URLs выбираются через environment profiles; staging использует MODDINGFLOW_STAGING_API_BASE_URL и отдельный staging key.
  • npm run api:sdks:compile проверяет реальный TypeScript consumer, импортирует Python package без записи bytecode и собирает C# smoke consumer внутри npm run api:openapi:check.
Stable candidateAdditive

Stable v1 OpenAPI documentation gate

OpenAPI 3.1 остается источником правды для auth, scopes, errors, cursor pagination, upload sessions, download grants, webhooks, SDK source artifacts и public reference rendering.

  • Successful request/response examples cover install plan resolve, upload-session create/status/parts/complete/abort, download resolve/fallback and webhook subscription/delivery/redelivery flows.
  • Problem Details examples use application/problem+json with type, title, status, detail, instance, code, request_id and trace_id so clients do not parse prose.
  • Webhook verification guidance documents X-Moddingflow-Signature, X-Moddingflow-Timestamp, X-Moddingflow-Delivery-Id and HMAC-SHA256 over `${timestamp}.${raw_body}`.
Policy activeDeprecated

Compatibility, Deprecation and Sunset policy

Stable v1 old clients keep working during the support window while additive changes can ship through documented, tolerant OpenAPI/SDK/docs updates.

  • Deprecated OpenAPI operations must include x-deprecation-date, x-sunset-date, x-migration-url and x-changelog-url.
  • HTTP-visible deprecations use Deprecation, Sunset and Link rel="deprecation" headers.
  • Minimum notice is 90 days or two stable API releases, whichever gives the safer migration window.
  • Repository release gate требует committed migration evidence, готовый non-deprecated replacement, dated telemetry review и approved support plan с явными owner и approver до Sunset.

Migration guide templates

Каждый deprecation guide должен быть actionable: что заменить, как найти affected clients, как раскатить замену и куда отправить support evidence.

Deprecated operation template

Deadline
Не раньше x-sunset-date и минимум через 90 days или two stable API releases после x-deprecation-date.
Replacement
Указать replacement operationId/path, required scopes, request/response schema differences и expected Problem Details codes.
Detection
Искать deprecated operationId в SDK calls, OpenAPI client generation, logs, user-agent/client_id traffic и stored integration configs.
Rollout
Добавить replacement client path, включить dual-read или dual-write если нужно, проверить idempotency/cursor behavior, затем удалить old operation после sunset.
Support
Передавать X-Request-Id, request_id, trace_id, client_id, affected operationId и SDK version в support request.

First stable v1 limitations

Deadline
До stable launch ограничения должны быть описаны как release notes, а не hidden implementation details.
Replacement
Если capability еще beta/experimental, пометить x-moddingflow-stage=beta или x-moddingflow-stage=experimental и не делать ее prerequisite для stable flows.
Detection
Сравнить public OpenAPI paths, SDK generated clients, localized docs, FAQ и runtime route parity перед публикацией.
Rollout
Публиковать только после npm run api:openapi:check, npm run locales:validate и focused docs/reference rendering tests.
Support
Known limitations должны ссылаться на changelog entry, migration guide или support contact вместо устной договоренности.

Release validation evidence

  • npm run api:openapi:generate -- --check confirms committed JSON matches the Rust generator.
  • npm run api:openapi:lint checks examples, auth, scopes, Problem Details, pagination, uploads, downloads, webhooks and deprecation metadata.
  • npm run api:sdks:check confirms generated TypeScript, Python and C# source artifacts match OpenAPI operationIds and schemas.
  • npm run locales:validate keeps API docs, reference, SDK, FAQ and changelog copy synchronized across ru, en and de.