Глава 6. Ошибки и Наблюдаемость

Модель ошибок и наблюдаемость — две сквозные «провода» через три слоя Fayger. Они позволяют внешним вызывающим сторонам понимать, локализовать сбои и наблюдать исполнение в одной семантике.

6.1 Единая модель ошибок

struct FaygerError {
  code: ErrorCode
  source_layer: Layer       // loader | runtime | adapter | host
  message: String
  context: Map<String, Value>
  cause: Option<Box<FaygerError>>
}

Семантика полей:

  • code. Стабильный документируемый идентификатор. Для ветвлений на стороне вызывающего; семантика не меняется между версиями.
  • source_layer. Помечает слой, который изначально породил ошибку. Помогает маршрутизировать в нужный диагностический мануал.
  • message. Человеко-читаемое описание. Кратко; не дублирует информацию code.
  • context. Структурированные ключ-значение для инструментов. Минимум — поля, спровоцировавшие ошибку (offset, missing_fields, current_state, expected_range и т. д.).
  • cause. Сквозная цепочка причин. При оборачивании ошибки нижняя помещается в cause, чтобы не терять информацию.

6.2 Правила производства и распространения

  1. Создавать ближе к источнику. Каждый слой создаёт FaygerError в своих границах и помечает source_layer.
  2. Оборачивать слой за слоем. Если верхний слой добавляет семантику, он сохраняет нижнюю ошибку в cause и не переписывает source_layer.
  3. Не терять контекст. context несёт ключевые поля, спровоцировавшие ошибку.
  4. Сохранять сбой. BuF_Instance, попавший в Failed, обязан зафиксировать в failure_info последнюю Universal_Instruction и соответствующую ошибку до явного уничтожения.

6.3 Пример цепочки

Типовое распространение через три слоя:

[top]  RT_INSTANCE_FAILED      (source_layer = runtime)
         └── cause:
[mid]    ADP_HOST_CALL_FAILED  (source_layer = adapter)
           └── cause:
[low]      <нативная ошибка хоста> (source_layer = host)

Обход cause даёт [runtime, adapter, host], что соответствует фактическому порядку «изнутри наружу». Свойство непрерывно проверяется PBT.

6.4 Обзор ключевых кодов ошибок

ИсточникКодТриггер
LoaderLDR_PARSE_FAILНевалидный поток BuF
LoaderLDR_DIGEST_MISMATCHНесовпадение дайджеста Section (Eager)
LoaderLDR_LAZY_DIGEST_MISMATCHНесовпадение при первом доступе в Lazy
LoaderLDR_SIGNATURE_FAILПодпись отсутствует в режиме обязательной / невалидна
LoaderLDR_SCHEMA_UNSUPPORTEDВерсия schema вне поддерживаемого диапазона
LoaderLDR_RUNTIME_VERSION_TOO_HIGHМинимум Runtime_Interface выше предоставленного
LoaderLDR_MISSING_REQUIRED_FIELDОбязательные поля Manifest отсутствуют при сериализации
LoaderLDR_PROFILE_REQUIRED_SECTION_MISSINGRequired Section не подгружается под текущим профилем
LoaderLDR_LAZY_SOURCE_UNAVAILABLEBuF_Source недоступен при последующем доступе в Lazy
LoaderLDR_SOURCE_READ_FAILEDОшибка чтения BuF_Source (Eager или Lazy)
RuntimeRT_ILLEGAL_TRANSITIONНелегальный переход жизненного цикла
RuntimeRT_IMPL_NOT_FOUNDМаршрутизация не нашла подходящую реализацию
RuntimeRT_IMPL_MISSING_METHODSУ зарегистрированной реализации нет обязательных методов
RuntimeRT_QUOTA_EXCEEDEDПревышение квоты ресурсов
RuntimeRT_INSTANCE_FAILEDИнстанс перешёл в Failed
AdapterADP_NO_MATCHING_PLATFORMНи один адаптер не подходит хосту
AdapterADP_UNSUPPORTED_INSTRUCTIONАдаптер не поддерживает инструкцию
AdapterADP_CAPABILITY_DENIEDCapabilities недостаточны после усечения
AdapterADP_HOST_CALL_FAILEDХост сбойнул после перевода в системный вызов

Ошибки loader помечают context.phase как eager или lazy, что позволяет вызывающей стороне маршрутизировать по фазе: сбой при старте может вызвать переход к другому источнику / профилю или ретрай; сбой в Lazy в рантайме обычно затрагивает только доступ к этой Section, и вызывающая сторона решает, деградировать ли.

6.5 Шина событий наблюдаемости

interface EventBus {
  publish(event: FaygerEvent)
  subscribe(filter: EventFilter, handler: EventHandler) -> SubscriptionId
  set_debug_enabled(enabled: bool)
}

Категории событий:

  • Lifecycle Event. Переход состояния BuF_Instance; несёт from, to, timestamp, instance_id.
  • Quota Event. Выборка ресурсов, превышение, приостановка.
  • Loader Event. Вход / завершение / сбой фазы; несёт имя фазы.
  • Adapter Event. Диспетчинг инструкций, результат усечения, запись «не поддерживается».
  • Debug Event. Только при set_debug_enabled(true). Для глубокой диагностики.

Согласованность последовательности lifecycle-событий

Для любой легальной последовательности [(s₀, s₁), (s₁, s₂), …] шина должна:

  • иметь ту же длину;
  • для каждого eᵢ: eᵢ.from == sᵢ₋₁, eᵢ.to == sᵢ;
  • eᵢ.timestamp монотонно неубывающий.

6.6 Интеграция с лог-/трейс-каналами хоста

Если хост предоставляет лог- или трейс-каналы (systemd-journal, OS Logger, console браузера, канал In-App SDK и т. д.), слой адаптации мапит внутренние события туда:

  • Маппинг описывается самим Platform_Adapter; слой исполнения не знает о различиях каналов.
  • Уровни (debug / info / warn / error) сопоставляются уровням хоста.
  • Lifecycle Event и Loader Event — info; Quota / Adapter ошибки — warn / error.

Если канала нет, события остаются в EventBus для подписчиков.

6.7 Переключатель отладочных событий

Вывод отладочных событий по умолчанию выключен. Включение:

event_bus.set_debug_enabled(true)

Включает:

  • детали диспетчинга для каждой инструкции;
  • входы/выходы каждого усечения capabilities;
  • значения каждой выборки монитора ресурсов.

Из-за объёма подписчики отладки обязаны фильтровать, ограничивать скорость или сохранять активно.

6.8 Интерфейсы запроса состояния

Fayger обязан предоставлять для эксплуатации и диагностики:

ЗапросВозвращает
state(instance_id)Текущий Lifecycle_State
failure_info(instance_id)Последняя Universal_Instruction и объект ошибки, вызвавшие Failed
list_implementations()Дескрипторы зарегистрированных Runtime_Implementations
current_adapter()Дескриптор выбранного на текущий момент Platform_Adapter
granted_capabilities(instance_id)Capabilities инстанса после усечения

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

6.9 Поза безопасности по умолчанию

  • Режим обязательной подписи выключен по умолчанию (удобство разработки), но в release-сборках рекомендуется включать на уровне конфигурации.
  • Отладочные события выключены по умолчанию; включаются явно.
  • Не объявленные capabilities запрещены для BuF по умолчанию.
  • Неопознанные категории Universal_Instruction запрещены по умолчанию; «тихий проход» не разрешён.