Глава 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 Правила производства и распространения
- Создавать ближе к источнику. Каждый слой создаёт
FaygerErrorв своих границах и помечаетsource_layer. - Оборачивать слой за слоем. Если верхний слой добавляет семантику, он сохраняет нижнюю ошибку в
causeи не переписываетsource_layer. - Не терять контекст.
contextнесёт ключевые поля, спровоцировавшие ошибку. - Сохранять сбой. 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 Обзор ключевых кодов ошибок
| Источник | Код | Триггер |
|---|---|---|
| Loader | LDR_PARSE_FAIL | Невалидный поток BuF |
| Loader | LDR_DIGEST_MISMATCH | Несовпадение дайджеста Section (Eager) |
| Loader | LDR_LAZY_DIGEST_MISMATCH | Несовпадение при первом доступе в Lazy |
| Loader | LDR_SIGNATURE_FAIL | Подпись отсутствует в режиме обязательной / невалидна |
| Loader | LDR_SCHEMA_UNSUPPORTED | Версия schema вне поддерживаемого диапазона |
| Loader | LDR_RUNTIME_VERSION_TOO_HIGH | Минимум Runtime_Interface выше предоставленного |
| Loader | LDR_MISSING_REQUIRED_FIELD | Обязательные поля Manifest отсутствуют при сериализации |
| Loader | LDR_PROFILE_REQUIRED_SECTION_MISSING | Required Section не подгружается под текущим профилем |
| Loader | LDR_LAZY_SOURCE_UNAVAILABLE | BuF_Source недоступен при последующем доступе в Lazy |
| Loader | LDR_SOURCE_READ_FAILED | Ошибка чтения BuF_Source (Eager или Lazy) |
| Runtime | RT_ILLEGAL_TRANSITION | Нелегальный переход жизненного цикла |
| Runtime | RT_IMPL_NOT_FOUND | Маршрутизация не нашла подходящую реализацию |
| Runtime | RT_IMPL_MISSING_METHODS | У зарегистрированной реализации нет обязательных методов |
| Runtime | RT_QUOTA_EXCEEDED | Превышение квоты ресурсов |
| Runtime | RT_INSTANCE_FAILED | Инстанс перешёл в Failed |
| Adapter | ADP_NO_MATCHING_PLATFORM | Ни один адаптер не подходит хосту |
| Adapter | ADP_UNSUPPORTED_INSTRUCTION | Адаптер не поддерживает инструкцию |
| Adapter | ADP_CAPABILITY_DENIED | Capabilities недостаточны после усечения |
| Adapter | ADP_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 запрещены по умолчанию; «тихий проход» не разрешён.
