feat(relay,protocol,mt-core): протокол v4 для multi-owner — membership по WS, підписаний transfer, push, directory#53
Merged
Conversation
…hip по WS, підписаний transfer, push, directory
Закриває чотири потреби owner-app (спека task/docs/specs/260714):
- relay: WS-кадри invite/accept/decline/transfer_ownership/bootstrap_owners
(ядро вміло, транспорту не було); transfer через WS — лише з
Ed25519-підписом canonical-акта (домен mt-transfer-v4, верифікація
node:crypto без залежностей); bootstrap_owners — ідемпотентний сідинг
task_members з owner:-розмітки (зареєстровані → учасники + MemberChanged,
решта → pending-запрошення без дублікатів)
- relay push: інтерфейс sink + dev-реалізація; тип 2 «вас запрошено»,
тип 3 «потребує уваги» (PlanReview/AuditPending/NodeState:unresolvable —
всім, крім автора; Escalation — адресно за to_account_id)
- agent-protocol: Event::Escalation {from, to, to_account_id?, reason_ref}
(handles як у git, PII не тече — account_id непрозорий);
transfers.rs — TransferPayload + sign/verify (байт-у-байт дзеркало
relay/lib/signing.mjs, закріплено тестом формату)
- mt-core: directory.rs — канонічний парсер .mt/directory.json
(git-ignored, handle → email/імʼя; PII-політика operations.md);
.gitignore-запис
- store: валідація hex-32 pubkey при реєстрації пристрою (формат, який
очікує pubkey-кеш agent-server)
Тести: relay 67/67 (vitest), agent-protocol 17/17, mt-core directory.
Відомі преіснуючі падіння поза скоупом: agent-server
failing_check_blocks_done_until_fixed і npm config.test (env-залежні,
падають і на чистому origin/main).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # .cspell.json
…лінтера Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vitaliytv
added a commit
that referenced
this pull request
Jul 17, 2026
…о фіксів) (#55) PR #53 змерджено на коміті 2893506 — до пуша фіксів eslint (module-scope regex, max-classes-per-file, Uint8Array-API), тому main лишився з чотирма порушеннями. Той самий фікс, реаплайнутий поверх поточного main: - DevPushSink винесено з push.mjs у push-sink.mjs (max-classes-per-file) - signing.mjs: Buffer.from(…, 'base64') → Uint8Array.fromBase64() - тести: Buffer …toString('base64') → …toBase64(), [...map.values()] → map.values().toArray(), regex-літерали в toThrow/toMatch — module-scope константи Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Що
Закриває чотири потреби owner-app зі спеки
task/docs/specs/260714-cognitive-delegation.md(доріжка M4/v4). Gap-аналіз проти access.md показав: підписані approvals вже готові; membership було в ядрі relay без транспорту; directory/bootstrap/push — greenfield.Relay (
relay/lib)invite/accept/decline/transfer_ownership/bootstrap_owners— ядро вміло це давно, мережевого шляху не було (server.mjsвайрив лише hello/subscribe/envelope/pubkeys).mt-transfer-v4); верифікація уsigning.mjsчерез node:crypto (без нових залежностей), fail-closed без підпису. Прямий виклик ядра без підпису лишається локальним/адміністративним шляхом.bootstrap_owners: ідемпотентний сідингtask_membersзowner:-розмітки лісу — зареєстровані email-и стають учасниками (+MemberChanged), незареєстровані отримують pending-запрошення без дублікатів; наявні ролі не понижуються.push.mjs): інтерфейс sink + dev-реалізація (черга в памʼяті, FCM — за тим самим інтерфейсом окремо). Тип 2 «вас запрошено» на invite/bootstrap; тип 3 «потребує уваги» —PlanReview/AuditPending/NodeState:unresolvableвсім учасникам, крім автора,Escalation— адресно лишеto_account_id.agent-protocol (Rust)
Event::Escalation { from, to, to_account_id?, reason_ref }— записка «вгору» owner-app: handles як у git-файлах, PII у стрічку не тече (to_account_id— непрозорий uuid, резолвиться емітером через directory).transfers.rs—TransferPayload+sign_transfer/verify_transfer; формат повідомлення закріплено тестом як байт-у-байт дзеркалоrelay/lib/signing.mjs; підпис approval-домену не проходить як transfer.mt-core (Rust)
directory.rs— канонічний парсер.mt/directory.json(git-ignored; handle → email/імʼя за PII-політикою operations.md):parse_directory/resolve_email, толерантний до відсутнього/битого файлу; запис у.gitignore.Верифікація
@7n/rules lint— чисто; doc-files згенеровано; change-файли npm+relay (minor)message_matches_relay_canonical_formatВідомі преіснуючі падіння (поза скоупом)
agent-server::graph::tests::failing_check_blocks_done_until_fixedіnpm config.test(model_map з env) — падають і на чистомуorigin/mainлокально (env-залежні), цим PR не зачеплені.Наступні кроки (не в цьому PR)
Escalation-події з owner-app приescalate(repo task) + резолвto_account_idчерез directory🤖 Generated with Claude Code