Переносимая граница CAP
Канонический Machine IR, чистые decide/verify и границы доверия.
Переносимая граница CAP
Tyapkin задаёт протокол Machine, Principal, Capability, State, Input, Guard,
Transition, Output, Commitment и Trace. protocol-core предоставляет чистые
Rust-операции CapIrV1::from_contract, decide и verify_trace: они не открывают
БД, не вызывают адаптеры и не знают coffee/printing. Хост может встроить эту
библиотеку в процесс или обернуть её сервисом/worker. Wire DTO описаны в
proto/cap/v1/decision.proto; transport в этом срезе не реализован.
Capkin source -> MachineContract -> CapIrV1 + digest
-> decide(checkpoint, claims) -> commitments + new checkpoint
-> verify_trace(checkpoint, commitments) -> verified checkpointCapIrV1 фиксирует структуру Machine, а не опубликованный package: manifest,
схемы Input, adapter bindings и QA cases должны получать отдельный digest пакета.
Host приложения в Allium закрепляет свой package digest и вызывает
decide/verify_trace через версионированную границу. Форматы старого
aggregation evidence и их совместимый reader принадлежат Allium.
Канонические байты
IR v1: CAP-IR-v1\0, затем machine_id, initial_state; затем массивы
principals, capabilities, states, guards, transitions, outputs в этом
порядке. Строка — UTF-8 с длиной u32 big endian; массив — число элементов
u32 big endian. Массивы сортируются по полному кортежу полей; дубли и
неоднозначные переходы отклоняются. CapabilityOperation: Commit=1,
Evaluate=2. Для Transition кортеж: (from_state, input_type, guard_id, to_state);
для Output: (principal_id, output_type, allowed_state). Digest — SHA-256
ровно этих байтов. Нормализация Unicode и пробелов не выполняется.
Commitment v2: CAP-COMMITMENT-v2\0, затем length-prefixed trace_id,
machine_id, principal_id, один байт типа (Capability=1, Input=2, Guard=3,
Transition=4, Output=5), sequence как u64 big endian, затем optional
state_before, state_after, input_type, guard_id, output_type. Optional
кодируется байтом 0 или байтом 1 и обычной строкой. Далее идут 32 сырых байта
payload_hash и optional previous_commitment_hash как строка. SHA-256 этих
байтов записывается строчными hex; ID имеет префикс cap:v2. Время,
payload_ref, подписи, refs и protobuf wire bytes в этот hash не входят.
Старое строковое кодирование cap:v1 не меняется. Для новых решений v2
отличает, например, поля a|b/c от a/b|c, которые давали одинаковый
v1 hash input. Общие векторы лежат в fixtures/protocol/portable-v1-v2.txt;
Rust и Node вычисляют их независимо через
pnpm test:protocol:conformance.
Decide и Verify
decide принимает digest IR, доверенный checkpoint с тем же IR digest, ожидаемую голову и
утверждения Input, Guard, Transition и Output. Он проверяет Capability,
совпадение Input/Guard, допустимый Transition, State и Output. Положительное
утверждение Guard приводит к записям Input -> Guard -> Transition -> Output*;
отрицательное или ошибка не выдаёт частичный результат. Output — намерение,
не доказательство исполнения. expected_head сравнивается с переданным
checkpoint; хост обязан загрузить его из своего авторитетного хранилища и
проверить актуальность в той же транзакции, где сохраняет commitments,
новый checkpoint и доменные данные.
verify_trace переигрывает эту последовательность от доверенного checkpoint,
проверяет поля, Capability, State, sequence, v2 ID и hash chain. Он может
проверить сегмент из нескольких завершённых решений. Сам checkpoint должен
быть получен из доверенного хранилища либо проверенного предшествующего
Trace: verify_trace не доказывает происхождение подставленной головы.
Внешний host устанавливает личность Principal, вычисляет предметный Guard,
подписывает/удостоверяет evidence, исполняет Output и фиксирует Observation.
Хеш Guard.evidence_hash лишь связывает переданное утверждение с Trace.
Структурно верный Trace не доказывает истинность Guard, подлинность
Principal, доставку сообщения или существование внешнего исполнителя. Локальная
запись NotifyRequester остаётся локальным Observation.
Текущие пределы
DecisionRequestпринимает один булев Guard verdict; отрицательное утверждение отклоняет шаг, не формируя отдельный outcome Transition. Составные Guards и graph evidence ports описаны в следующем этапе kernel.- Core допускает массив Output claims, но локальный Capkin action/host пока создаёт не более одного Output intent. Внешнего ExecutionReceipt protocol и durable outbox нет.
- Публичный интерфейс реализован как Rust-библиотека; сервис, Node binding и worker будут адаптерами над теми же типами и conformance vectors.
- Proto задаёт DTO, но генерация клиентов и сетевой endpoint пока не включены.
- v2 decision не порождает отдельный
CapabilityCommitted: Capability проверяется и выводится из Machine. Старые v1 записи этого типа продолжают проверяться старым путём; v2 verifier принимает только форму решения выше. - Нет протокольной подписи, trust registry, распределённой финальности и аутентификации. Это отдельные интерфейсы и будущие решения.