Skip to content

feat(relay,protocol,mt-core): протокол v4 для multi-owner — membership по WS, підписаний transfer, push, directory#53

Merged
vitaliytv merged 3 commits into
mainfrom
claude/v4-owner-needs
Jul 17, 2026

Conversation

@vitaliytv

Copy link
Copy Markdown
Member

Що

Закриває чотири потреби owner-app зі спеки task/docs/specs/260714-cognitive-delegation.md (доріжка M4/v4). Gap-аналіз проти access.md показав: підписані approvals вже готові; membership було в ядрі relay без транспорту; directory/bootstrap/push — greenfield.

Relay (relay/lib)

  • WS-кадри membership: invite / accept / decline / transfer_ownership / bootstrap_owners — ядро вміло це давно, мережевого шляху не було (server.mjs вайрив лише hello/subscribe/envelope/pubkeys).
  • Підписаний transfer: мережевий transfer — лише з Ed25519-підписом canonical-акта (домен mt-transfer-v4); верифікація у signing.mjs через node:crypto (без нових залежностей), fail-closed без підпису. Прямий виклик ядра без підпису лишається локальним/адміністративним шляхом.
  • bootstrap_owners: ідемпотентний сідинг task_members з owner:-розмітки лісу — зареєстровані email-и стають учасниками (+ MemberChanged), незареєстровані отримують pending-запрошення без дублікатів; наявні ролі не понижуються.
  • Push (push.mjs): інтерфейс sink + dev-реалізація (черга в памʼяті, FCM — за тим самим інтерфейсом окремо). Тип 2 «вас запрошено» на invite/bootstrap; тип 3 «потребує уваги» — PlanReview/AuditPending/NodeState:unresolvable всім учасникам, крім автора, Escalationадресно лише to_account_id.
  • Валідація pubkey пристрою (hex-32) при реєстрації — формат, який очікує pubkey-кеш agent-server.

agent-protocol (Rust)

  • Event::Escalation { from, to, to_account_id?, reason_ref } — записка «вгору» owner-app: handles як у git-файлах, PII у стрічку не тече (to_account_id — непрозорий uuid, резолвиться емітером через directory).
  • transfers.rsTransferPayload + 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.

Верифікація

  • vitest relay: 67/67 (нові кейси: WS membership, підписаний transfer з реальними ключами, push тип 2/3, адресна Escalation, ідемпотентний bootstrap, валідація pubkey)
  • cargo: agent-protocol 17/17, mt-core directory — зелені; clippy/fmt через @7n/rules lint — чисто; doc-files згенеровано; change-файли npm+relay (minor)
  • Крос-мовна сумісність підпису: relay-тести підписують node:crypto-ключами і перевіряють тим самим форматом, який закріплено у Rust-тесті 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
  • FCM-доставка за інтерфейсом sink; PostgreSQL-store; expose invite/accept у клієнтських SDK

🤖 Generated with Claude Code

vitaliytv and others added 3 commits July 17, 2026 14:30
…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>
…лінтера

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vitaliytv
vitaliytv merged commit 05d4b3f into main Jul 17, 2026
3 of 4 checks passed
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant