Federation, imports и Flow
Проектная граница Capkin types, contract imports, федеративных полей, CEL и причинного Flow.
Federation, imports и Flow
Кандидат multi-transition Machine
Новый opt-in tyapkin-port-bindings-v2 связывает protobuf descriptor с
полным strict kernel Machine, включая несколько Input, Guard, Transition
и Output. binding-build сверяет CapIrV1 digest и покрытие всех портов.
ContractStore принимает machine-kernel-v1 и flow-v2 в отдельном
tyapkin-contract-package-v6-multimachine; graph release v5 требует v5
binding/runtime schema. Локальный fixture port-binding-multi-v1 проверяет
двухшаговую Machine, публикацию двух owner-пакетов, Flow и отказы при
изменённом Transition, пропущенном Input, чужом digest и старом ABI.
Веточный срез пока не является опубликованным API или принятым Allium release.
Локальный Flow переносит committed Output в запрос Input; target Guard,
tenant scope и внешний receipt остаются отдельными проверками host.
Наглядная локальная сборка
Для приёмки двух независимых Machine есть локальный runbook
docs/runbooks/capkin-federation-demo.md.
Команда pnpm demo:capkin:federation записывает отдельное
acceptance.webm: React Flow показывает Asset, ServiceCase, их четыре
protobuf TypeRef и пакет AssetToCase. Inspector раскрывает точный
Capkin .feature, package/import digest и правило переноса
asset_id/case_id. Проверка сборки запускает реальный compiler и
publication checker; успешный runtime затем показывает два Trace и
производную federated read projection. demo.webm сохраняет техническую
регрессию 15 сценариев. Схема читает pinned fixture и не редактирует
Allium ApplicationRelease.
Вторая вкладка того же React Flow показывает отдельный pinned graph release
ServiceCase → CaseToScheduleCelV2 → Scheduling. Человек видит строгий
Capkin .feature, выражение CEL v2, исходное case_id: string, целевые
case_id: string и reason: string, а после проверки и запуска —
reason = maintenance и target State Scheduled. Проверка использует
binding checker, CEL golden и Rust graph checker. CEL исполняется в Rust
reference host, не в браузере; этот release не входит в три packages
первой вкладки.
Над сборкой расположен общий проводник сущностей. Он собирает read-only
индекс из строгих source declarations и уже проверенных Machine, Kernel,
Type IR, Flow graph и read entity contexts. Сейчас это 339 сущностей 22 видов
и 484 связи. В одном поиске доступны Machine, Principal, Capability, State,
Input, Guard, Transition, Output, GuardSet, EvidenceComponent, bindings,
SemanticPort, TypeRef, Field, Flow, Projection, Package, Release и поля read
entity. Выбор узла показывает его прямые связи, точный контекст, статус
свидетельства и переход к подробной студии. Одноимённые узлы из разных
release не объединяются. Это проекция локального corpus: ExecutionReceipt и
Trace появляются только после отдельного запуска, а пунктирные source-symbol
совпадения не считаются release binding. Во время локального запуска
KernelHost::verified_trace отдаёт именно те Commitment records, которые
прошли Rust replay и проверку checkpoint. Node не перечитывает SQLite под
меткой verified Trace. Проводник связывает OutputIntent и его Commitment с
локальной Flow delivery, затем с точным Input Commitment целевой Machine.
Теперь FlowRuntime::verify_local_delivery также повторно проверяет source
Output и command целевого Input, pinned predecessor и сохранённый command
head. Отдельный targetInputCommitmentHash позволяет показать правильный
Input, даже если Machine позже выполнила ещё одну команду. Браузер отклоняет
witness, который не совпадает с проверенной Trace; он не выбирает первый
Input по имени Machine. Локальный формат
tyapkin-verified-local-flow-delivery-v1 не является внешним proof API.
Fanout показывает две отдельные delivery и три независимые Trace. Typed
effect и composite GuardSet также возвращают проверенные Rust Trace своих
Machine, включая отдельные PASS, DENY и INDETERMINATE instances.
Runtime facts живут в текущей вкладке; локальная delivery/receipt не
подтверждает внешнего эффекта.
Проводник также может прочитать любой явно выбранный локальный
ContractStore. Команда Rust capkin contract-inspect --db <registry.sqlite>
открывает существующую базу только для чтения, повторно проверяет digest и
структуру каждого опубликованного package и выдаёт versioned inspection:
imports, exports, source bytes, compiler IR, artifacts и typed effect sources.
Если при старте reference server задан DEMO_CONTRACT_DB, граф дополняется
этими packages и их Machine/Flow/TypeRef declarations, SemanticPort,
Principal, Capability, State, Input, Guard, Output и exact import связями.
Для опубликованного protobuf index инспекция теперь показывает каждый
TypeRef, его field numbers, origin и descriptor digest. Для typedEffects
Rust повторно компилирует strict Feature и выдаёт отдельный kernel профиль
Machine с GuardSet, evidence components, OutcomeRoute и typed binding. Узлы
kernel профиля связаны с исходником и Machine declaration, но имеют собственную
identity: совпадение имени само по себе не склеивает контракты. TypeRef и
binding показывают проверенные связи внутри опубликованного package, а не
совершившийся эффект.
Новый package появляется без правки demo loaders. Отдельный статус
PUBLISHED_CONTRACT означает проверенную публикацию в выбранной базе;
inspection не утверждает release binding, исполнение или внешнюю доставку.
Отсутствующий либо повреждённый package вызывает ошибку вместо догадки.
Путь к базе задаётся оператором сервера, браузер не выбирает произвольный
файл. Порядок запуска описан в runbook.
Следом расположен атлас строгих деклараций. Он обходит локальные
fixtures/ и tests/bdd/features/protocol/ и сейчас показывает 23
compiler-checked source variants: 11 Machine, 8 Flow, один native TypeSpec
и три type extension. Можно выбрать любой вариант по имени, профилю или
пути; inspector раскрывает исходный Feature, результат Rust compiler,
State/routes, Flow projection/CEL либо поля и base TypeRef. React Flow
показывает связи Flow с каждым Machine-вариантом, чей скомпилированный
Input/Output symbol совпал с SemanticPort. Эти пунктирные связи имеют
статус SOURCE_SYMBOL_CANDIDATE: они помогают исследовать mesh, но не
подтверждают совместимость package, TypeRef, release или доставку.
Для трёх определений, чьи exact source bytes встроены в локальные
digest-checked packages, атлас отдельно показывает package/release digest и
ссылку на проверку и запуск. Это связь исходника с release, а не утверждение
об исполнении выбранной декларации.
Для extension с base TypeRef вне локального source corpus атлас показывает
внешнюю ссылку, не приписывая ей ложного владельца. Навигация вверху
страницы ведёт от атласа к pinned assembly, отдельным Machine, kernel,
типам, graph release, read entity и исполнению.
Machine Studio под mesh раскрывает каждый из четырёх release-scoped Machine
contracts: State, Principal, Capability, Input, Guard, Transition, Output,
proof, SemanticPort, protobuf TypeRef и два вида исходника там, где runtime
Feature отличается от binding Feature. Два ServiceCase не объединяются
по имени: у них разные release pins. После запуска Studio показывает
упорядоченные Commitment, State и Trace head из проверенной Rust истории.
Карточка cel-map-v2 показывает исходный Flow Feature, выражение, engine и
expression digest, а после запуска — фактически вычисленный Input.
Это Flow projection; Guard целевой Machine остаётся отдельной проверкой.
Для bounded graph cycle есть ещё закрытый tyapkin-condition-v1 profile;
ни один из этих профилей не делает CEL универсальным CAP Guard.
Каталог Machine дополняет эти закреплённые сборки всем локальным protocol
corpus: сейчас 11 строгих Machine Feature в пяти именах. Сервер обходит
fixtures/ и tests/bdd/features/protocol/, компилирует каждый найденный
Machine-кандидат через Rust capkin compile или kernel-inspect-json и
показывает отдельный вариант для каждого source path/profile/digest.
На React Flow и в карточках видны все State, Input, Guard, Transition,
Output, Principal и Capability; composite профиль дополнительно показывает
все три исхода, evidence components и execution bindings. Повреждённый
Machine-кандидат вызывает явную ошибку каталога. Статус
COMPILED_LOCAL_SOURCE означает только проверенный исходник: package
publication, TypeRef/Port из binding и Trace доказываются отдельно в
release-scoped Studio. Так каталог не выдаёт 11 исходников за 11
опубликованных или исполняемых Machine.
Kernel Machine Studio читает структурированный JSON непосредственно из Rust
kernel compiler. Для EvidenceMachine он показывает оба компонента
GuardSet и три маршрута PASS/DENY/INDETERMINATE на одном графе. После
локального запуска можно увидеть отдельные State и Trace head каждого
исхода, сохранённые evidence, два OutputIntent, две Observation и два
ExecutionReceipt. Для типизированной ServiceCase показаны
TypedEffectBinding, protobuf TypeRef и typed receipt. Typed effect сейчас
не записывает отдельную generic Observation; это явно указано в UI.
Оба исполнения локальные, а источником деталей служат compiler и Rust host.
Type Registry Studio показывает другой разрез тех же contract primitives:
точные import refs, package owners, общий tyapkin-type-ir-v1, protobuf
TypeRef, native TypeSpec и extension. Два локальных контекста собираются
из фиксированных fixtures: Rust компилирует Type Feature, ContractStore
публикует packages, затем Rust type-ir-check проверяет import closure.
React Flow показывает связь package → TypeRef → field и extension → base;
inspector различает владельца типа и владельца каждого унаследованного
поля. Временный SQLite registry удаляется после построения read model.
Этот экран не публикует произвольный пользовательский package.
Flow Graph Studio показывает release-level маршрут между независимыми
Machine. Сервер вызывает Rust capkin flow-graph-check для четырёх
закреплённых release: fanout, CEL v2 projection, bounded cycle и scoped
cycle. Он сверяет SHA-256 каждого binding IR и runtime schema, затем
повторно компилирует исходный строгий Flow Feature. На графе видны
source Output Port, Flow, target Input Port и обе направленные стороны
цикла. Inspector раскрывает точное CEL выражение, engine, поля, scope,
source Feature и digest. Для cycle отдельно показаны maxIterations = 3
и два typed CEL exit condition. После запуска интерфейс связывает
delivery keys, Trace heads, terminal evidence и transport receipt с
digest этого же release. Accepted transport receipt не выдаётся за
target Transition. Это проверенная read-only визуализация локальных
fixtures; браузер не интерпретирует CEL и не создаёт новый Flow.
Entity Studio показывает, что одно имя AssetCase.View@1 ещё не определяет
одну и ту же read entity. Вариант v4 получает asset_id из committed Asset
Output и case_id из committed ServiceCase Input после причинной Flow
delivery. Вариант v5 берёт оба поля из committed Output двух Machine.
Сервер публикует exact packages во временный ContractStore и проверяет
оба manifest командой Rust federation-check --db; UI допускает только
совпавшие с pinned resolution bytes. React Flow связывает Machine,
SemanticPort, field owner package, зависимость requires и read entity.
Inspector показывает исходную декларацию и checked resolution. Кнопки
запускают локальный Rust host: для v4 видны fresh/stale/unknown, для v5 —
срезы с одним и двумя Output, expiry и чужим tenant. Значение, причина,
возраст, source commitment и Trace head берутся из FederatedReadStore;
read projection не меняет State и Trace исходных Machine.
Статус: проверенный локальный publication/runtime срез, 8 октября
2026. Rust capkin flow-compile компилирует field-copy-v1,
flow-v2 и opt-in flow-cel-v1. Для federated read entity есть локальный
preflight и ограниченная materialization из проверенной causal доставки;
v2 исполняется как отдельный scoped Flow и как маршрут mixed strict graph
release-v3 с независимым CEL Flow в локальном reference host.
CEL profile допускает закрытое map expression, не весь язык CEL.
Поэлементный аудит находится в
openspec/changes/archive/2026-10-08-capkin-federation-imports-flow/acceptance-audit.md.
Локальные publication, bounded Flow/CEL, federation read и Playwright demo
проверены в текущем профиле. Hosted CI и branch protection выведены из
scope локальной приёмки; внешние adapters и доверенные executor keys
ещё не приняты. Промежуточные снимки ниже
сохраняют историю срезов; актуальная матрица приёмки находится в OpenSpec.
Узкий capkin imports-check проверяет offline sidecar graph:
точные package ID/version/digest, alias, visibility, отсутствие циклов и
diamond с одним исходным символом. Он сверяет SHA-256 bytes локальных
tyapkin-package-exports-v1 artifacts, но пока не загружает полные
published packages из registry в старом v1 профиле. Opt-in
imports-check --db разрешает v2 graph из точных bytes в локальном
ContractStore. Локальная команда
pnpm check:capkin:bindings уже проверяет два Machine, protobuf binding и
три варианта узкого Flow; правила PortBinding, TypeRef provenance и projection теперь
проверяет Rust capkin binding-compile. Команда не вызывает RPC. Полный
порядок и проверяемые требования зафиксированы в
openspec/changes/archive/2026-10-08-capkin-federation-imports-flow/ и
docs/architecture/capkin-federation-flow.md.
Источники фактов
.proto / registry commit → pinned descriptors → внешний TypeRef index
Capkin package → Machine, SemanticPort, Flow, Guard, Trace
Binding → semantic ID ↔ protobuf message / RPC
Allium host → endpoint, outbox, RPC adapter, Observation.proto определяет поля, сообщения и сервисы; Tyapkin не переписывает их и
не генерирует .proto в первом schema-adapter profile. Capkin определяет
поведение и устойчивый порт ServiceCase.OpenCase@1. Привязка может быть
помечена protobuf custom options represents_type/implements_port или
задана sidecar для чужой схемы. Компилятор отклоняет конфликт этих двух
источников привязки. Allium выбирает версии слоёв и исполняет проверенную
семантику Tyapkin, не создавая второй язык Flow.
Текущий пример: proto/tyapkin/options/v1/binding.proto,
proto/tyapkin/fixture/port_binding/v1/service.proto,
fixtures/port-binding-v1/contract.json и
fixtures/port-binding-v1/compiled.json, а также
tests/bdd/features/protocol/port-binding-flow.feature. Digest descriptor
закреплён в fixture manifest. Замена имени RPC при прежнем alias проходит
проверку, а несовместимый request type — нет. Компилированный binding IR
сравнивается с сохранённым fixture при каждом запуске checker. В IR есть
types[] с semantic ID, именем protobuf message и digest descriptor. Это
индекс происхождения, а не второе определение полей и ещё не полный Type IR.
binding-build дополнительно выдаёт отдельный
tyapkin-protobuf-type-index-v1: для каждого привязанного semantic типа —
owner: protobuf, digest descriptor, исходный .proto файл и message FQN,
а также номера и формы полей, прочитанные из descriptor. Эти поля не
объявляются вторично в Capkin. Индекс и его SHA-256 закреплены в
fixtures/port-binding-v1/type-index.json и
fixtures/port-binding-cel-v1/type-index.json. Rust отклоняет повторные
или нулевые номера полей. Индекс пока охватывает только типы данного
binding manifest и не является общим registry всех типов.
При локальной сборке отдельный checker декодирует бинарный
FileDescriptorSet и независимо сверяет index/IR с origin, каждым
полем, represents_type, RPC method/input и implements_port.
Отрицательные тесты меняют поле, oneof, alias, method и message. Такой
же preflight запускается до сборки двух store composition fixtures;
публикация старого формата v2 через ContractStore не выполняет эту
бинарную проверку.
Для нового opt-in формата tyapkin-contract-package-v3-protobuf это
ограничение снято в части TypeRef: Machine package должен содержать
types/protobuf-index.json, binary schema/descriptor.binpb и
bindings/ports.json.
ContractStore::publish через Rust prost-reflect сверяет digest,
file/message, поля, presence/oneof, represents_type, port direction,
payload TypeRef, RPC Input и implements_port до записи. Пересчитанный
SHA-256 подменённого index/binding не обходит проверку.
При публикации следующей v3 версии того же ID поле compatibilityBaseline
указывает exact version/digest последней сохранённой версии. Store сверяет
добавочную совместимость прежних exports, TypeRef field IDs/forms,
binary field/oneof/method declarations и PortBinding. Новое поле допустимо;
изменение прежнего поля или метода
отклоняется даже при согласованно пересчитанном descriptor и index.
Legacy → v3 и breaking переход без migration policy пока закрыты.
Flow declaration в новом v3/v4 package при прямом publish сверяется с
точными импортированными checked Machine packages: source должен быть Output,
target — Input, payload TypeRef и root binding IR обязаны совпасть с
владельцами. Field-copy покрывает все target scalar fields с совместимым
типом; CEL map проверяется по полям обоих protobuf типов, включая отказ
неизвестного source field и несовпавшего expression. Это publication
preflight; он не исполняет Flow v2 и не включает внешний transport.
Для нескольких Flow один checked package указывает отдельный binding
artifact в каждой Flow declaration. Публикация отвергает неявный или общий
binding, повторную пару source/target и несовпадение CEL engine pin.
Следующая additive версия того же Flow export обязана сохранить его compiled
IR и binding bytes; изменение expression требует отдельной version/migration
policy. Для opt-in Flow@N прямой v5 parallel publish проверяет
Flow@1 → Flow@2, exact baseline, полный replacement map и совпадение
compiled Flow с binding IR. Прежний unversioned Flow не получает скрытого
переименования: @1 публикуется и активируется явно. Несколько опубликованных Flow не
активируются автоматически: DAG/cycle gate выполняется для graph release.
При v3 публикации checked import closure проверяется по exact сохранённым
пакетам: один semantic TypeRef не может получить второго package owner.
Межпакетная binding compatibility и полный CEL gate остаются открытыми;
v1/v2 bytes/readers не изменены.
Для exact опубликованных пакетов локальный types-check --db строит
read-only tyapkin-type-registry-v1 по всему v2 import graph. В
fixtures/composition-store-v3/types-resolved.json видны четыре semantic
TypeRef, package owner, descriptor origin и номера полей. Конфликт двух
package owners или повтор номера/имени поля отвергается. Это индекс
опубликованных artifacts: он пока не сверяет поля заново с бинарным
descriptor, не охватывает Tyapkin-native types и не является полным Type IR.
Composition-v3 открывает Flow только после такой проверки всего import graph.
Checked package v2 с вложенным protobuf индексом также проходит проверку
его формы, provenance и уникальных field identities до публикации.
Новый opt-in tyapkin-contract-package-v4-types публикует собственный тип
Tyapkin из строгого Gherkin-compatible профиля type-native-v1.
capkin type-compile --file fixtures/native-type-v1/case-note.feature
выдаёт tyapkin-native-type-ir-v1 с module owner, source digest и
стабильными номерами полей. ContractStore::publish повторно компилирует
source и сравнивает IR до записи, а затем проверяет одного владельца TypeRef
во всём exact import closure. Следующая версия v4 требует
compatibilityBaseline последней версии и сохраняет прежние поля; новые
поля допустимы. Прежние v1/v2/v3 package bytes не меняются.
Для явного breaking перехода добавлен opt-in
tyapkin-contract-package-v5-parallel. Его migrationPolicy с форматом
tyapkin-parallel-cutover-v1 проверяется при прямом publish: новая major
version N.0.0, exact compatibilityBaseline, полное отображение прежних
публичных TypeRef/port identities на новые ID с тем же stem и большим
@version, без повторного использования старых ID. Обязательные значения
existingInstances: retain-baseline и
consumerCutover: explicit-release описывают параллельное сосуществование.
Проверенный fixture публикует native CaseNote@1 → CaseNote@2 с новым
типом поля и затем additive 2.0.1; старый import graph после публикации
выдаёт прежний Type IR. Store не переключает live instances и не выполняет
State/payload conversion. Выбор release и проверка фактического cutover
остаётся отдельной runtime задачей. Второй публичный fixture публикует
параллельную v5 protobuf ServiceCase schema/ports с новыми @2 IDs и
дополнительным bool field: binary descriptor и TypeRef index проверяются
независимо, incomplete replacement map, stale baseline и пересчитанный
index drift отклоняются. Старый protobuf Type IR после этого по-прежнему
разрешается из прежних exact bytes.
capkin type-ir-check --file <import-graph-v2.json> --db <store.sqlite>
строит read-only tyapkin-type-ir-v1 из опубликованных native TypeSpec и
protobuf TypeRef indexes. У каждого поля видны number, type, presence и
origin package. Это общий производный read model, а не новый source of
truth: native fields принадлежат TypeSpec, protobuf fields — descriptor.
Строгий type-extension-v1 Feature объявляет только новые scalar fields,
base TypeRef и alias точного импортированного protobuf, native или extension owner. Такой
v4-types package публикуется после проверки base index/TypeSpec из checked
v3/v4 owner и его bounded base chain: номер или имя inherited field нельзя
повторить. Общий
type-ir-check показывает inherited fields, added fields и их владельцев.
Следующая версия package пинит exact baseline и сохраняет ранее добавленные
поля. Этот срез поддерживает прямой protobuf/native/extension base с
ограничением глубины цепочки. При additive публикации новый native или
extension @N требует опубликованный @N-1 того же owner/kind и сохраняет
прежние поля; extension также сохраняет exact pinned base. Первая версия
типа — @1; пропуск версии и изменение field identity отвергаются через
contract-publish. Старый read-only Type IR остаётся читаемым после restart.
Межпакетная binding compatibility, breaking migration и полный Flow/CEL
runtime gate ещё не приняты.
Локальный ContractStore также закрепляет native/extension TypeSpec за
одним package ID на уровне всей SQLite registry. Второй независимый package
с тем же редактируемым ID типа не публикуется; при открытии старого store
индекс восстанавливается из проверенных immutable package bytes. Protobuf
payload TypeRef из общего descriptor может встречаться в независимых
Machine packages; его origin и imports проверяются отдельно. Native/extension
TypeSpec не может занять уже опубликованный protobuf ID типа.
Историческая коллизия в старой SQLite базе не удаляет package: backfill
сохраняет чтение обоих, отмечает конфликт и блокирует новую публикацию
на этот ID.
Второй store-backed release fixtures/asset-store-composition-v4/
собирает Asset, ServiceCase и field-copy Flow из трёх checked packages.
Он использует тот же import/type preflight и локально исполняет причинный
Asset Output → ServiceCase Input; отдельный release digest сохраняет
delivery identity при restart. CEL composition-v3 остаётся прежним.
В release-v5.json host закрепляет один документ: его digest, пути и
SHA-256 composition/runtime schema, root package. Локальный
FlowRuntime::open_release_with_store проверяет этот документ и открывает
тот же Flow из данных ContractStore. V5 delivery key закреплён exact bytes
release, поэтому повтор после restart распознаётся, а v4 key остаётся прежним.
Старый release-v4 продолжает работать.
Исторический CapkinTypeIrV1 остаётся форматом старого Allium aggregation
package и его reader; новый external TypeRef берёт поля из protobuf
descriptor. Это согласовано с ProCoffee schema-first правилом: protobuf
владеет wire shape, а Capkin — поведением и смысловыми портами. Старые
package bytes не перекомпилируются.
Rust отклоняет двойную привязку message/method, несовместимый RPC Input,
неполную projection и oneof/explicit presence, которые field-copy-v1 пока
не моделирует.
buf breaking сравнивает схему с отдельным v1 descriptor baseline, а fixture
digest закрепляет точные байты текущего descriptor. Это два разных gate:
совместимость и неизменность выбранной версии.
flow-v2 добавляет явную policy: committed Output trigger,
tenant scope из source Trace, object scope по строковому полю Output,
authority source Output principal, tenant/object correlation,
idempotency по source commitment и target port, удержание неизвестного
исхода, остановку при DENY, максимум пять попыток и удержание после их
исчерпания. Пример находится в
tests/bdd/features/protocol/port-binding-flow-v2.feature; manifest
fixtures/port-binding-v2/contract.json явно выбирает flow-v2 и
сравнивает IR с compiled.json. Компилятор отклоняет несовпадение профиля,
отсутствующее scope поле и небезграничный retry. Runtime требует отдельный
schema marker v3 и scoped instances.
Локальное исполнение v1
cap-cli::FlowRuntime принимает сохранённый compiled.json v1 и отдельно
прикреплённый runtime-schema.json с digest из host release. Schema artifact
строится Rust binding compiler из того же protobuf descriptor и содержит
digest binding IR и source/target field shapes. Runtime проверяет оба digest,
точные поля и поддерживаемые scalar types локального canonical JSON profile;
неверный тип или лишнее поле отвергается до target apply. Runtime проверяет
commitment исходной Machine вместе с intent_id, SHA-256 точных байтов Output
и историю её Trace. Затем копирует объявленные поля в локальный JSON Input,
сохраняет причинную доставку в SQLite и через KernelFlowTarget вызывает
apply целевой Machine. У цели отдельные Guard, State и Trace. Повторная
подача после рестарта возвращает прежний результат. Потерянный ответ
помечается unknown; lookup того же command ID может подтвердить уже
записанный целевой переход. Этот путь проверен Rust fixture с двумя Machine,
чьи контракты читаются из отдельных строгих Capkin files
port-binding-service-case-kernel.feature и
port-binding-scheduling-kernel.feature, включая ошибочные байты и
подменённый outbox commitment.
Для host со своим хранилищем добавлен opt-in Rust FlowHostPortV1 и
FlowRuntime::enqueue_with_ports_v1. Порт даёт read-only Machine contract,
IR digest, replay-проверенный source Output, replay-проверенный target
checkpoint и scope. Прежний enqueue(&KernelHost, &KernelHost, …) вызывает
тот же путь через реализацию порта для KernelHost. Conformance fixture
сравнивает delivery bytes/key, повтор после restart и отказы при искажённом
IR, Output hash и tenant scope. Реализация порта должна быть доверенной:
произвольный клиентский JSON не становится проверенным Trace. Это Rust API
в локальном исходнике, а не опубликованный process/RPC ABI, Allium State
service или доказанная внешняя доставка.
При DENY delivery завершается без целевого Transition; при
INDETERMINATE удерживается unknown без целевого Transition.
После рестарта незавершённая отправка сначала становится unknown и
проверяется по прежнему command ID; она не отправляется повторно вслепую.
Перед enqueue runtime сравнивает semantic shape обеих запущенных Machine с
binding IR: principals, capabilities, states, guards и Input/Output. Кроме
того, schema artifact пинит точные CapIrV1 digests обеих Machine;
совпадения Machine ID недостаточно. Отдельный Rust test сверяет digest
legacy Machine Feature и строгого kernel Feature для каждого слоя.
Runtime v1 доверяет выбранному host и его pinned schema digest; локальный транспорт использует canonical JSON и поддерживает string, bool и 32-битные целые scalar fields. Это reference adapter, не protobuf wire codec, не gRPC endpoint и не публикация package. Tenant scope, объектная область и retry policy из v2 исполняются только для нового opt-in локального профиля; v1 путь остаётся без scope.
Второй fixture fixtures/asset-case-v1/ исполняет независимые Machine
Asset и ServiceCase. Asset.AssetContextChanged@1 несёт asset_id и
case_id; Flow field-copy переносит оба поля в
ServiceCase.OpenCase@2. Каждая Machine имеет собственные Guard, State и
Trace, а protobuf descriptor пинит четыре semantic ports и номера полей.
pnpm check:capkin:asset-case проверяет Buf lint/breaking, официальный
Gherkin AST, exact binding IR, TypeRef index и runtime schema; Rust tests
проверяют causal enqueue, целевой commit, restart/replay и отказ при
изменённых source bytes, DENY или INDETERMINATE. Это локальное исполнение
через JSON/SQLite host без живого RPC и без v2 tenant policy.
Отдельный flow-cel-v1 исполняется в том же локальном JSON/SQLite host.
tests/bdd/features/protocol/port-binding-flow-cel.feature содержит
Gherkin DocString с типом cel:
And project target Input with CEL
"""cel
{"case_id": output.case_id, "reason": "maintenance"}
"""Source Output ServiceCase.CaseOpened@1 содержит case_id, а target Input
Scheduling.ScheduleVisit@2 содержит case_id и reason. Target port и
protobuf payload получили отдельную версию. Rust проверяет полное покрытие
target полей, типы, форму выражения и лимиты до выпуска IR v3. Выражение и
версия движка cel-rust/0.14.5/tyapkin-projection-v1 закреплены digest.
Runtime повторно проверяет CEL при открытии host и вычисляет target Input
после verified Output intent, сохраняя причинный outbox. Fixture отдельно
пинит descriptor, binding IR и runtime schema. Текущий subset ограничен
map с не более чем 64 полями и 4096 байтами expression; вызовы функций и
comprehensions отклоняются. Это локальный reference adapter без внешнего RPC.
Compiler использует CelProjectionPort, а runtime при открытии Flow
сверяет engine_id port с pinned IR до вызова checker. Замена backend
означает новый versioned engine ID и отдельную проверку; текущие IR bytes
не меняются. Семь общих golden vectors в
fixtures/cel-projection-v1/golden.json проверяются Rust CEL engine и
независимым Node reference evaluator через pnpm check:capkin:cel-golden.
Vectors фиксируют canonical JSON результата, ошибки типов, отсутствие
полей и отказ вызова функции. Полный CEL type system и произвольные protobuf
shapes этим subset не объявляются.
Отдельный # @profile:flow-cel-v2 сохраняет прежний v1 reader и создаёт
новые IR v4 / runtime schema v4 с engine
cel-rust/0.14.5/tyapkin-projection-v2. Он разрешает проверенные по
protobuf scalar полям conditional, equality/order, boolean operators и
строковое сложение. Checker отказывает вызовам функций, collections,
неизвестным полям и несовместимым типам ветвей. Предельные значения:
4096 байт expression, 64 поля, 256 AST nodes, глубина 16, по 65 536 байт
source и target payload. Проверка повторяется при ContractStore::publish
и FlowRuntime::open; локальный E2E создал target Transition и повтор после
restart без второй доставки. Девять общих golden vectors исполняются Rust
и независимым Node parser/evaluator. Этот профиль остаётся scalar-map;
protobuf nested/repeated shapes и общий CEL type system открыты.
Feature: CaseToSchedule
# @registry:FLOW-CASE-SCHEDULE-002
# @profile:flow-v2
Background:
Given flow CaseToSchedule
Scenario: FLOW-CASE-SCHEDULE-002
When output ServiceCase.CaseOpened@1 is committed
Then submit input Scheduling.ScheduleVisit@1
And project field case_id to case_id
And causation references the source commitment
And tenant scope is inherited from the source trace
And target authority uses the source Output principal
And correlation uses tenant and object scope
And object scope is source field case_id
And idempotency key uses source commitment and target port
And unknown outcome is held
And denied outcome stops
And transient failure allows at most 3 attempts
And exhausted attempts are heldЭтот v2 профиль теперь исполняется локально через отдельный
tyapkin-flow-runtime-schema-v3. Host создаёт экземпляры через
create_scoped_instance(instance_id, tenant_id, object_id); исходный Output и целевой Input
должны относиться к тем же tenant/object, а adapter проверяет principal
исходного Output и target capability до apply. Transient разрешает
ограниченный повтор, Unknown удерживается до lookup того же command ID,
Denied останавливает маршрут. Scope и authority хранятся рядом с
причинной доставкой в SQLite. Для held и denied новый локальный
FlowTerminalEvidence записывается атомарно с terminal outbox status.
verify_terminal_evidence(source, target, key) сверяет digest документа,
source Output commitment, обе Machine Trace, первоначальный target head,
scope, authority и число попыток; изменённые bytes и чужой Trace отвергаются.
Это локальная reference реализация: документ не является подписанным
external receipt и не доказывает доставку внешнему transport.
Отдельный schema-first DeliveryRequestV1 и DeliveryReceiptV1 из
tyapkin.flow.transport.v1 пинят Flow/binding, source commitment, exact
target Input bytes и их hash, scope, authority и попытку. Descriptor gate
сверяет wire поля с Rust codec; независимые Rust/Node encoders дают
одинаковые request/receipt bytes и request digest на общем golden vector.
FlowTransportPort разделяет submit и
lookup; lost response остаётся unknown, а найденный signed receipt
атомарно сохраняется со статусом transport-accepted, transport-denied
или transport-failed. Verifier проверяет точные protobuf bytes, adapter ID
и attestation через доверенный host authenticator после restart. Adapter ID
пинится до submit; маршрут с unknown нельзя переключить на локальный
FlowTarget без signed receipt. Даже
transport-accepted не меняет target CAP State и не притворяется target
Transition. Локальный conformance test покрывает три исхода, потерянный
ответ, replay, чужой adapter, подмену подписи/попытки/bytes; production
gRPC adapter и конфигурация доверенных ключей остаются открытыми.
fixtures/flow-graph-v1/release-scoped-v3.json показывает этот v2 Flow
вместе с прежним CEL маршрутом под одним strict graph release. Оба
получают отдельные causal deliveries и проходят собственные target Guard;
после restart ключи не меняются. Scope v2 не приписывается CEL маршруту.
Какие отношения надо различать
| Отношение | Что получает слой |
|---|---|
Contract import | Имена и типы экспортированного пакета по ID/version/digest |
Runtime depends on | Требование наличия способности другого слоя |
Type extends | Новый тип с собственными полями; исходный тип неизменен |
Federated contributes | Поле общей read entity с собственным field owner и provenance |
Flow Output → Input | Новую причинную команду для другой Machine |
Текущий import fixture — fixtures/import-graph-v1/diamond.json.
capkin imports-check --file fixtures/import-graph-v1/diamond.json возвращает
importedSymbols с исходным package для каждого имени; две ветви diamond
ссылаются на один example.shared.Event. pnpm check:capkin:imports
сверяет результат с resolved.json и входит в локальный pnpm quality.
Это проверка графа зависимостей; она ещё не подключена к generic
Machine/Flow compiler. Отдельный
fixtures/import-graph-store-v2/graph.json проверяет те же alias,
visibility и diamond через четыре immutable package в ContractStore.
pnpm check:capkin:store-imports отвергает changed digest и import
declaration; v1 fixture не меняется.
Для прикладной сборки есть следующий локальный gate:
capkin composition-check --file fixtures/composition-v1/manifest.json.
Он связывает четыре SemanticPort двух независимых packages с pinned binding
IR v1, сверяет digests и выводит resolved.json с исходным package каждого
порта. CaseOpened → ScheduleVisit проходит только если оба Flow endpoints
импортированы. Ошибочный import alias, неверный экспорт или изменённый byte
binding IR отклоняется. pnpm check:capkin:composition входит в pnpm quality.
FlowRuntime::open_composed может открыть проверенную композицию в локальном
v1 JSON/SQLite host. Его outbox keys привязаны к digest композиции, так что
два release с одинаковым binding IR не совпадают по delivery identity.
Локальный release.json хранит отдельно проверяемые pins manifest и
runtime schema.
Код слоя из composition не генерируется; внешний transport и scoped v2
release через эту v1 композицию не приняты.
fixtures/composition-v2/ — отдельный pinned release для CEL Flow. Он
импортирует ServiceCase и Scheduling версии 2.0.0, требует экспорт
Scheduling.ScheduleVisit@2, привязывает все четыре SemanticPort к их
исходным package artifacts и включает неизменённый compiled CEL IR v3.
FlowRuntime::open_composed принимает exact manifest digest из release,
повторно проверяет binding/schema и строит Input с reason через CEL.
Delivery key отличается от прямого открытия того же IR. Старый
composition-v1 и field-copy release сохраняют прежние байты.
fixtures/composition-store-v3/ связывает ту же CEL семантику с полными
опубликованными tyapkin-contract-package-v2 bytes. Каждый такой пакет
содержит исходный .feature, точный compiler IR и declaration exports;
contract-publish повторно компилирует исходник и проверяет, что Machine
публикует только свои Input/Output, а Flow использует импортированные порты.
Checked package принимается после публикации каждой импортируемой версии
с тем же digest; отсутствие зависимости или изменённый digest отвергаются.
Команда
capkin composition-check --file fixtures/composition-store-v3/manifest.json --db <registry.sqlite> требует v2 import graph, проверяет pinned digests
пакетов, exports и declarations, а затем полный набор портов и оба конца
Flow. FlowRuntime::open_composed_with_store повторяет эти проверки при
открытии release; отдельный digest manifest формирует delivery identity.
Корневой package закрепляет тот же binding IR как собственный artifact:
проверка сравнивает его точные bytes с выбранным IR, затем сопоставляет
скомпилированный из Flow source ID, scenario, endpoints и CEL expression с
binding. Подмена связи между source Flow и binding отклоняется.
Каждый Machine contract из binding также сравнивается с точным compiled IR
его импортированного checked package; порты одной Machine должны иметь
одного package owner. В каждом Machine package лежит собственный subset
protobuf TypeRef index; loader сверяет payload TypeRef каждого порта,
descriptor digest и message origin с binding IR. Совпадения имён портов
недостаточно.
Локальный тест проверяет восстановление после повторного открытия и отказ
при отсутствующем пакете. pnpm check:capkin:store-composition сверяет
resolution byte-for-byte и проверяет отрицательный digest drift. Это
локальная сборка из опубликованных данных контракта: package source не
загружается как исполняемый код. Этот узкий Rust compiler gate не заменяет
полный publish gate с независимой проверкой protobuf compatibility, CEL
cost/type environment и всех runtime policies.
При federation нужны entity key, owner каждого поля и список внешних полей, необходимых для вычисления. При Flow нужны trigger, pinned source/target types, projection, tenant/object scope, authority, causation, unknown/failure route, идемпотентность и ограничение повторов. Никакой слой не меняет State соседа.
Первый локальный preflight есть в fixtures/composition-v2/entity.json:
capkin federation-check проверяет Dispatch.WorkItem@1 с ключом case_id.
Поле case_id принадлежит пакету ServiceCase, а reason — Scheduling;
reason явно требует внешний case_id. Владелец выводится из проверенного
import origin, тип — из pinned protobuf runtime schema. Результат
entity-resolved.json хранит owner ID/version/digest, source port/field,
type и dependencies. Валидатор отклоняет два владельца одного поля,
неизвестный source field, отсутствующую или циклическую зависимость,
неверный ключ и изменённые pins. pnpm check:capkin:federation сравнивает
результат с fixture в локальном quality gate. Этот v1 профиль проверяет
только декларацию read entity; значения появляются в отдельном v4 профиле.
Отдельный fixtures/composition-v2/entity-typed.json выбирает v2 preflight.
Он дополнительно пинит type-index.json, сверяет его descriptor/message и
форму полей с binding IR и runtime schema и сохраняет protobuf field number
в entity-typed-resolved.json. Изменённый digest или type shape отклоняется.
Предыдущий v1 manifest и resolution остались без изменений. V2 также пока
только проверяет контракт read entity, не материализует данные.
fixtures/asset-store-composition-v4/entity.json выбирает typed v3
preflight: capkin federation-check --db берёт TypeRef владельцев и
номера полей из опубликованного import closure, сверяет их с binding и
runtime schema. Отдельный type-index.json в entity manifest больше не
нужен. AssetCase.View@1 показывает поле Asset и поле ServiceCase с
явной внешней зависимостью; результат закреплён в entity-resolved.json.
V3 пока не хранит значения, не отслеживает freshness и не открывает query API.
fixtures/asset-store-composition-v4/entity-values.json вводит opt-in v4
read entity с pinned freshness.maxAgeSeconds. Локальный
FederatedReadStore::materialize_flow принимает завершённую causal доставку,
повторно проверяет исходный Output и целевой Input по их независимым Trace,
проверяет точные payload hashes, tenant/object scope, field types и key.
Он сохраняет read snapshot отдельно от Machine State; каждое поле содержит
owner package и точный source commitment. query показывает fresh,
stale или unknown и возраст. Запрос с другим tenant/object получает
только unknown поля. Пропавшая зависимость делает зависимое поле unknown;
просроченное значение не возвращается как актуальное. Локальный тест
проверяет положительный путь, чужой tenant, expiry, подменённый payload,
restart и неизменность обеих Trace. Это read projection одного
Asset Output → ServiceCase Input. Новый профиль
entity-outputs.json берёт два независимых committed Outputs:
Asset.AssetContextChanged@1 и ServiceCase.CaseOpened@1. Их TypeRef,
номера полей и owners разрешаются из published import closure.
materialize_outputs повторно проверяет каждую Trace и exact payload,
принимает только одинаковый tenant/object, сохраняет отдельный
observedAt каждого поля. Отсутствие второго Output даёт unknown,
а просроченный required field делает зависимое поле unknown даже если
его собственный источник ещё свежий. Внешние observations и hosted query
endpoint остаются отдельной интеграцией.
Отдельный capkin type-extension-check с manifest
fixtures/type-extension-v1/manifest.json проверяет additive extension
protobuf TypeRef. Новый ServiceCase.CaseOpenedWithSource@1 получает owner
example.dispatch@1, наследует case_id с номером 1 и добавляет source
с номером 2. База загружается по SHA-256 из производного индекса и остаётся
владением .proto. Компилятор отклоняет повтор имени/номера, неизвестный
base type, изменённый pin и неподдержанный scalar shape; resolved.json
сравнивается byte-for-byte в pnpm quality. manifest-v2.json создаёт
@2 поверх pinned resolved.json версии @1: checker требует соседнюю
версию и сохранение каждого прежнего field number/name/type/owner; удаление,
изменение типа и подмена pin отклоняются. Это локальный sidecar profile:
новый тип ещё не связан с портом, runtime или общим registry.
Локальное хранение контрактных байтов
ContractStore в cap-cli сохраняет exact bytes версионированного
tyapkin-contract-package-v1/v2/v3-protobuf по ID/version в SQLite. Самодостаточный
пакет перечисляет exports/import refs и содержит артефакты с SHA-256 и
вложенными bytes. Команда capkin contract-publish с --file и --db
возвращает ID/version/digest. Повтор тех же байтов
идемпотентен; изменённые байты под той же версией и повреждённый artifact
отклоняются. Fixture fixtures/contract-store-v1/package.json содержит
Machine source и производный protobuf TypeRef index;
pnpm check:capkin:contract-store проверяет сборку fixture и CLI publication.
Чтение после restart повторно проверяет package integrity.
V1 пакет проверяет структурную целостность. V2 пакет дополнительно требует
source, скомпилированный Rust IR и проверенные semantic exports до записи.
V3 protobuf сохраняет эти требования и для Machine независимо проверяет
embedded binary descriptor против TypeRef index и package PortBinding при
самой публикации. При следующей версии того же ID compatibilityBaseline
пинит последний package, а additive check сохраняет поля и semantic ports.
V2 import resolver читает exact bytes, но не активирует Machine/Flow и не
выполняет полный publish gate. Allium по-прежнему
владеет собственным каталогом LayerPackage и ApplicationRelease.
capkin flow-graph-check --file fixtures/flow-graph-v1/manifest.json
проверяет несколько pinned binding IR перед сборкой. Текущий профиль
разрешает только DAG, проверяет направление портов, уникальность Flow и
маршрутов, одинаковый compiled contract общего Machine ID и выдаёт
детерминированный порядок Machine. Два Flow
ServiceCase → Scheduling проходят; добавление скомпилированного обратного
Scheduling → ServiceCase отклоняется с путём цикла. Изменение digest или
повтор маршрута также отклоняются. pnpm check:capkin:flow-graph сравнивает
resolution с fixture и проверяет отрицательный граф. Этот gate не активирует
Flows и не исполняет ограниченные циклы. Политика выбора между двумя
маршрутами от одного Output задаётся в opt-in
fixtures/flow-graph-v1/release-v2.json: fanout: all означает постановку
каждого подходящего маршрута в собственный локальный outbox.
LocalFlowGraphRuntime::open сверяет SHA-256 самого release, каждого binding
IR и runtime schema, проверяет общий Machine contract и DAG, затем открывает
два прежних FlowRuntime. enqueue_all выбирает маршруты по проверенному
committed Output, возвращает отдельный результат каждого Flow и узнаёт
повтор после restart. Ключи доставки зависят от exact release bytes и
соответствующего binding IR, поэтому отделены от прямого Flow reader.
Частичный успех возможен и виден вызывающему host;
автоматический dispatch, общий атомарный commit и внешние эффекты здесь
не реализованы. Отдельный opt-in release-v4 исполняет bounded cycle;
старый graph-v1 resolution не меняется.
Локальный SQLite pin закрепляет verified source Output за одним graph release
digest. Host может вызвать pin_source_output при создании Output;
enqueue_all повторно проверяет pin перед постановкой. При попытке провести
этот же Output через изменённый release runtime отказывает до новой доставки.
Pin распространяется и на Output, для которого прежний release не имел
маршрута: новый граф не должен подхватывать его задним числом.
Если host не сделал pin до переключения, ещё не обработанный старый Output
может попасть в новый release. Атомарную активацию и rollback новых
ApplicationRelease должен реализовать Allium host.
Для этой границы добавлен opt-in tyapkin-local-flow-graph-release-v3.
Host открывает KernelHost с exact graph digest через
with_graph_release до apply; новый OutputIntent и его release pin
записываются в одной SQLite transaction. V3 graph проверяет этот pin до
enqueue и не принимает Output, созданный без pin либо под другим release,
включая Output без текущего маршрута. Повтор команды после смены выбранного
release сохраняет старый pin. release-v2 и его delivery key bytes не
изменены; v3 имеет отдельный domain separator. Выбор активного
ApplicationRelease и атомарный rollback всё ещё принадлежат Allium.
Роль Gherkin и CEL
Gherkin предоставляет обычные
Feature, Background, Rule, Scenario, tags, DataTable и DocString.
Готового import в нём нет. Технический schema import и lock digest живут
в manifest. Строгие шаги .feature описывают Machine и Flow через
смысловые порты, без имён RPC. Checker отклоняет неизвестный шаг.
CEL, прикреплённый как """cel DocString, в текущем профиле вычисляет
типизированное содержимое target Input. Он не выбирает trigger и не
исполняет следующий слой. Causation и права проверяются независимо от
результата CEL. Текущий Machine profile сохраняет своё значение Feature;
flow-v2 выбирается отдельным marker в .feature и в package manifest.
Официальный @cucumber/gherkin AST уже подключён как отдельный syntax gate
для пятнадцати compiler fixtures с явным profile selection. Он отвергает
неподдержанные Rule, tags и DataTable; DocString допускается только для
закрытого шага flow-cel-v1 с media type cel. Rust semantic compiler
по-прежнему читает узкие строки и проверяет смысл шагов. Русские Gherkin
keywords для этих исполняемых профилей ещё не включены.
При сборке binding manifest Machine и Flow подаются в Rust как закрытый
normalized AST через compile-ast и flow-compile-ast. Шесть Flow и пять
Machine fixtures дают тот же IR byte-for-byte; два kernel fixtures сохраняют
те же digests. Прямые старые команды сохраняют прежний source input.
Публикация
Локальный binding checker входит в pnpm quality и имеет positive/negative
tests. Node собирает descriptor через Buf и вызывает Rust compiler; digest
descriptor проверяется до компиляции binding, затем бинарный descriptor
сверяется с результатом компиляции. Перед публикацией в Forgejo локально
запускается pnpm quality; hosted CI и обязательный status check пока не настроены.
pnpm check:capkin:federation теперь является единым локальным gate для
действующих Type/Flow IR, CEL scalar-map, graph, publication, runtime
replay и отрицательных fixtures. Он вызывается из pnpm quality.
check:capkin:cross-language внутри него сверяет native Type, field-copy
Flow v1, scoped Flow v2 и CEL Flow v1/v2 IR независимым Node reader
официального Gherkin AST с Rust CLI. Неверные retry bound и CEL DocString
type отвергаются обеими сторонами. Node также декодирует binary descriptor
и сверяет TypeRef/PortBinding.
Полный контракт CEL typing/cost и внешний gRPC transport conformance ещё
остаются открытыми в OpenSpec change. Локальный protobuf receipt gate
входит в check:capkin:federation.
pnpm quality также выполняет strict OpenSpec validation текущего change.
Браузерное reference demo
Для bounded graph cycles Rust предоставляет
compile_cel_condition_v1: закрытое CEL выражение над pinned scalar
полями обязано возвращать bool, имеет отдельный engine ID и проверяемый
digest, лимиты AST/depth/payload. Compile-only cycle preflight сверяет
оба pinned Flow, exit для каждого source port и конечный budget; его
нельзя открыть в LocalFlowGraphRuntime. Исполняемый opt-in
tyapkin-local-flow-graph-release-v4 закрепляет оба binding IR/runtime
schema, boolean exit для каждого source Output и конечный budget 1..16.
enqueue_cycle допускает следующий переход только после committed target
Input и нового Output/Trace, связанного с предыдущей delivery. При exit или
budget новые delivery не создаются; SQLite terminal document и digest
проверяются через verify_cycle_terminal. Повтор после restart узнаёт
прежний delivery key и terminal digest. Это локальный однописательный host:
Flow outbox и graph lineage пока не входят в одну SQLite transaction;
распределённое исполнение требует отдельного admission/recovery контракта.
Семь общих golden vectors для CelCondition независимо исполняются Rust и
Node checker: true/false, ошибка non-bool, неизвестное поле, impure call и
несовпадение типа source payload. Для scalar projection добавлены отказные
vectors по пропущенному/неизвестному target полю и неверному типу результата.
Проверка входит в общий federation gate.
Инспекция произвольного graph release
capkin flow-graph-inspect --file <release.json> --sha256 <digest> проверяет
точные bytes release и каждый закреплённый binding IR/runtime schema,
используя тот же Rust graph resolver, что и локальный runtime. Его versioned
read model содержит Machine contracts, SemanticPort, Flow и projection.
Это read-only инспекция деклараций: она не открывает Machine instance, не
ставит Flow в outbox и не создаёт Trace.
При DEMO_GRAPH_RELEASE=<путь> общий Entity Explorer загружает выбранный
release без fixture-specific loader. Кнопка «Показать маршруты release»
открывает понятные переходы Machine → Output port → Flow → Input port →
Machine. «Весь mesh» дополнительно показывает TypeRef, Projection и все
отношения. Выбор узла сохраняет выбранный вид и показывает точный binding digest,
origin и связи. Машины с одинаковым именем в разных release не склеиваются.
Одно имя TypeRef может иметь разные protobuf descriptor origins в разных
Flow; такие определения также остаются раздельными. Поля protobuf появляются
только из отдельно проверенного Type index опубликованного package: binding
IR сам по себе подтверждает origin, но не содержит структуру полей.
Процедура и Playwright evidence описаны в
docs/runbooks/capkin-federation-demo.md.
CARGO_HOME=/tmp/tyapkin-cargo pnpm demo:capkin:federation собирает
локальный Rust runner и через Playwright показывает Asset Output →
ServiceCase Input из закреплённого release-v5. Он записывает video,
trace.zip, кадры, SQLite и manifest в новый каталог
runs/demo/capkin-federation/<timestamp>/. Сквозной путь показывает два
независимых Trace и federated read. Отдельная кнопка открывает strict
graph release-v3: два Flow от ServiceCase Output дают независимые delivery
keys, target Trace и replay после restart.
Отдельный CEL v2 route строит Input.reason = maintenance из
Output.case_id = case-1 по условному выражению Feature и проводит
отдельный target Trace с pinned release и replay. Кнопка bounded cycle
исполняет ServiceCase → Scheduling → ServiceCase → Scheduling: три отдельные delivery и четыре Trace, затем остановку по
budget до четвёртой delivery; независимый root Output демонстрирует typed
exit до первой delivery. Video/trace и SQLite counts проверяют оба terminal
documents и replay после restart. Отдельный scoped вариант собирает два
flow-v2 binding в один release-v4: оба направления проверяют tenant/object
correlation и authority перед target Input, сохраняя те же три причинные
delivery, четыре Trace и конечную остановку. Foreign tenant и другой object
отвергаются до первой delivery. Отдельный checked protobuf package
публикует оба flow-v2 Feature с собственными binding artifacts;
publication сверяет authority, scope, retry и outcome policy с Gherkin и
отвергает подмену. Package publication и graph runtime используют exact
binding bytes. Типизированный эффект проверяется отдельным opt-in контрактом.
Graph DENY показывает локальное terminal
evidence без target Transition. Graph transport показывает
lost response, lookup и локально проверенный receipt без target Transition;
demo verifier тестовый и не доказывает подлинность внешнего адаптера.
Остальные кнопки отказа
вызывают forged Output, DENY, чужой tenant, stale read и неверный release
pin. Подробная процедура —
docs/runbooks/capkin-federation-demo.md.
Демо использует только fixture packages и локальный reference host. Его Output intention не является доказательством внешнего эффекта, а read snapshot не меняет CAP State.
Типизированный эффект v2
Строгий machine-kernel-v1 Feature может добавить строку
And typed binding CaseOpened port ServiceCase.CaseOpened@1 payload ServiceCase.CaseOpenedPayload@1 result Scheduling.VisitScheduledPayload@1 descriptor_sha256 <digest>.
Она наследует binding id/version/executor от уже объявленного Output и
выдаёт отдельный digest TypedEffectBindingV2. Прежний binding digest,
Machine IR и Trace остаются прежними. TypedEffectSchemaV2::open повторно
проверяет exact binding IR pin, binary FileDescriptorSet, TypeRef index,
направление и symbol Output port, payload/result messages. Текущий opt-in
профиль принимает канонические protobuf bytes с заполненными ненулевыми
scalar полями. prepare_from_host сначала требует verified OutputIntent,
затем связывает его hash с payload bytes и номером попытки.
Checked protobuf package может включить typedEffects с exact Gherkin
source artifact. ContractStore::publish повторно компилирует его, сверяет
CAP IR с Machine declaration и TypeRef/port с package descriptor.
typed_effect_schema открывает схему только по опубликованному
ID/version/digest и Output port. Additive версия обязана сохранить source
bytes прежнего typed effect. Локальный KernelHost::with_typed_effects
закрепляет его digest при создании экземпляра; типизированный dispatch
пишет outbox status и receipt v2, восстанавливает прерванный вызов как
UNKNOWN и проверяет сохранённые receipts после restart. Некорректный
успешный результат переводится в UNKNOWN, а не в ложный успех.
cap.v2.TypedEffectRequest и TypedEffectReceipt описаны в
proto/cap/v2/typed_effect.proto. Core вычисляет domain-separated digests;
receipt v2 связывает exact request, binding, executor, result TypeRef и hash
результата. Для успешного результата schema adapter проверяет protobuf
форму; внешний origin требует валидную attestation от настроенного
authenticator. Локальный mock test не доказывает внешнее исполнение.
Adapter активирует host после выбора точного package release и executor;
автоматический вызов внешнего provider не заявлен.
pnpm check:capkin:typed-effect и
pnpm check:capkin:typed-effect-publication сверяют descriptor, package,
независимые Node/Rust golden digests, replay и отрицательные случаи.
В локальном Playwright demo сценарий typed-effect публикует этот
checked package, отклоняет поддельный payload и подтверждает один receipt
после restart. Изолированная SQLite содержит четыре commitments, один
binding pin и один typed receipt; video/trace и точные SHA-256 описаны в
docs/runbooks/capkin-federation-demo.md. Это проверка локального executor,
а не свидетельство вызова внешнего сервиса.