Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Контракты в AngaraBase

Goal

Объяснить, что в AngaraBase понимается под словом «контракт», какие уровни контрактов существуют и какими механизмами они соблюдаются. Эта страница — для пользователей, DBA и новых контрибьюторов: чтобы при чтении документации, кода или сообщений об ошибках было понятно, на какие гарантии можно полагаться, а какие — явно вне контракта.

Что мы понимаем под контрактом

Контракт в AngaraBase — это явное обещание о наблюдаемом поведении компонента: что он принимает на вход, что возвращает, какие гарантии даёт и как ведёт себя при нарушении границ. Контракт не «лучшие намерения» и не «как обычно работает» — это формализованная договорённость, которую обязаны соблюдать обе стороны: реализация и вызывающий код (или клиент).

У контракта три ключевых свойства:

  1. Явность. Контракт зафиксирован в одном каноническом источнике — не в чате, не в коде комментария, не в «общем понимании команды».
  2. Проверяемость. Соблюдение контракта подтверждается автоматически: тестами, типами, метриками, lint-проверками.
  3. Fail-closed. При нарушении границы контракта система возвращает явную ошибку (с известным кодом), а не «как-нибудь продолжает работать».

Если что-то в системе не покрыто контрактом, это явно помечается как roadmap, experimental или known limitation. Поведение вне контракта может измениться без deprecation-цикла.

Уровни контрактов

В AngaraBase есть несколько уровней контрактов, каждый со своим источником истины и способом проверки.

1. SQL-контракт (внешний, для пользователя)

Что поддержано — поддержано полностью. Что не поддержано — возвращает явный SQLSTATE (0A000 feature_not_supported и др.), а не молчаливый bypass или искажённый результат.

  • Источник: SQL — обзор совместимости, Известные ограничения и SQLSTATE.
  • Проверка: pinned compat suite, регрессионные тесты на каждый зафиксированный SQLSTATE.
  • Что это значит на практике: клиент может ловить psycopg.errors.FeatureNotSupported и точно знать, что попал в задокументированное ограничение, а не в баг.

2. Конфигурационный контракт

Каждый ключ конфига имеет тип, значение по умолчанию, диапазон допустимых значений и поведение при отсутствии или некорректном значении.

  • Источник: Configuration, Configuration schema reference.
  • Проверка: парсер отвергает неизвестные/некорректные ключи на старте (fail-closed), а не молча игнорирует.
  • Изменение семантики ключа — через deprecation-цикл (см. WRITING_RULES.md §9a).

3. Operational контракт

Метрики, USDT-зонды, имена sys.* view, формат backup/restore, формат логов и runbook-вывода — всё это публичные имена, на которые завязан мониторинг и автоматизация оператора.

  • Источник: System tables, Observability metrics checklist, Backup and restore, USDT/eBPF probes.
  • Принцип: каждая ресурсная граница (RAM-бюджет буфер-пула, лимит write-set транзакции, snapshot age и т.д.) обязана иметь Prometheus-метрику и явное fail-closed поведение при нарушении. Граница без наблюдаемости — это не контракт.

4. Внутренние API-контракты (для контрибьютора)

Каждая подсистема ядра имеет публичный Rust-trait, который определяет её семантику: TableEngine, PageProvider, TransactionLogSink, StorageIo и др. Без реализации контракта код не соберётся — это «honest checked promise», а не «честное слово разработчика».

  • Источник: doc-comments на trait-ах, Architecture overview, API Boundaries.
  • Проверка: компилятор Rust + property-tests на инварианты + layering lint (Core не зависит от Adapters/Tooling).

5. Документационный контракт (anti-drift)

Документация — часть кода. Любое изменение публичного контракта (SQL surface, конфиг-ключи, метрики, SQLSTATE, имена сабсистем, защитные дефолты, порядок init/upgrade) обязательно сопровождается изменением AngaraBook в том же PR.

  • Источник: WRITING_RULES.md §8 — Anti-drift contract.
  • Проверка: pre-commit / CI прогоняют tools/docs/lint_angarabook_public.py, tools/docs/check_public_build_security.py и помечают расхождение как блокирующее.

Как мы соблюдаем контракты

Контракт без механизма соблюдения — декларация. В AngaraBase используется несколько слоёв принуждения, которые работают вместе.

Type system как первый рубеж

  • Result<T, Error> вместо panic. unwrap() / expect() в production-коде запрещены.
  • Bounded generics и trait-объекты вместо dynamic dispatch там, где инвариант можно зафиксировать на уровне типов.
  • No-panic policy: сервер не падает из-за пользовательского ввода — он возвращает SQLSTATE.

Restrictive by default + fail-closed

Каждый компонент с ресурсной границей обязан определить:

  • свою границу (например, buffer_pool_size_mb, txn_max_write_set_mb, max_concurrent_queries),
  • поведение при её нарушении (явная ошибка с известным SQLSTATE),
  • реакцию вызывающего кода (Reaction Propagation Contract).

Нет границы и нет fail-closed поведения — нет merge.

Pinned tests и golden datasets

Контракт SQL-совместимости и совместимости клиентов подтверждается pinned-тестами, а не «процентом совместимости». Если тест зафиксирован — изменение поведения требует либо обновления теста с обоснованием, либо отката изменения.

Подробнее: Testing and validation baseline, Golden dataset management, CI reproducibility contract.

Deprecation-цикл

Когда контракт выводится из обращения, он не исчезает молча. Применяется единый цикл: Active → Deprecated → Removed, минимум один major-релиз между объявлением Deprecated и Removed; до v1.0 — минимум две minor-точки. Каждое изменение фазы — атомарный PR (код + AngaraBook + Migration steps).

Полный регламент: WRITING_RULES.md §9a — Deprecation policy. Public-список всех deprecated/removed контрактов: Известные ограничения и SQLSTATE.

Security gate как fail-closed для документации

Что это даёт пользователю

  • Предсказуемость поведения. Если поведение задокументировано — оно стабильно в рамках мажора. Если задокументировано как ограничение со SQLSTATE — оно вернёт именно этот SQLSTATE, а не «иногда работает».
  • Безопасный код клиента. Можно ловить конкретные SQLSTATE и строить логику ретраев / обработки ошибок без эвристик и парсинга текстовых сообщений.
  • Понятный апгрейд. Изменение поведения публичного контракта проходит явный deprecation-цикл с migration-шагами; вы заранее видите, что и когда поменяется.
  • Наблюдаемость гарантий. Каждая ресурсная граница имеет метрику; вы видите утилизацию и реджекты до того, как они станут инцидентом.

Что это даёт разработчику и контрибьютору

  • Контракт компилятора, а не review-комментария. Если инвариант можно закодировать в trait или тип — он кодируется. Code review ловит то, что компилятор поймать не может.
  • Один источник истины на тип знания. Не нужно «искать актуальную правду по нескольким документам»: для каждого слоя контракта есть один canonical owner.
  • Предсказуемая работа с долгом. Deprecated-контракт фиксируется в reference/known-issues.md, а если он не закрывается одним PR — в registry технического долга со статусом scheduled <target-train>.
  • Anti-drift в одном PR. Меняешь поведение — обновляешь AngaraBook здесь же. Не «доработать docs позже».

Что не является контрактом

Чтобы избежать ложных ожиданий, явно: контрактом не считаются:

  • внутренние имена модулей, файлов и приватных функций ядра (могут меняться при рефакторинге без deprecation);
  • поведение фич с frontmatter status: experimental или CLI-флагами --experimental-* — они никогда не считались стабильными;
  • тексты сообщений об ошибках (контракт — SQLSTATE и его смысл, не текст);
  • не задокументированные побочные эффекты, замеченные эмпирически («у меня работает, если…»);
  • бенчмарки и численные значения латентности — это observability, а не обещание производительности (performance-claim требует pinned benchmark, см. tools/perf_pack/).

Если вы опираетесь на что-то из этого списка в продакшене — это технический долг на стороне клиента, и очередное обновление AngaraBase его раскроет.