Skip to content

docs(research): Agent Mesh × A2A interoperability study - #88

Open
hartsock wants to merge 3 commits into
mainfrom
research/a2a-interop
Open

docs(research): Agent Mesh × A2A interoperability study#88
hartsock wants to merge 3 commits into
mainfrom
research/a2a-interop

Conversation

@hartsock

Copy link
Copy Markdown
Member

Summary

Research only — no code changes, no protocol commitment. Adds
docs/research/a2a_interop.md (~1470 lines), the study of how agent-mesh should
relate to the A2A protocol (spec v1.0.1, Linux
Foundation).

⚠️ Stacked on #87. This branch is based on fix/ssh-test-etxtbsy-race
because the pre-existing ETXTBSY test race (#86) blocked any push from gnuc,
including this docs-only one. Merge #87 first, then this rebases onto plain
main cleanly. The first commit here is #87's.

Headline

agent-mesh does not substantially duplicate A2A. A2A specifies an entire
application layer we never built (task lifecycle, artifacts, skills, agent cards,
three bindings) and explicitly defers everything we did build — spec §7: "Identity
information is handled at the protocol layer, not within A2A semantics"
, and
§7.6.4 disclaims authorization evidence outright.

After surveying prior art (UCAN 1.0.0, Biscuit 3.x, AIP, AGNTCY Identity, IETF
WIMSE, SPIFFE, OAuth Transaction Tokens, RFC 9421, in-toto/DSSE), exactly two
properties remain distinctively ours:

  1. an attenuation lattice checked against an OS enforcement witness
    (authority.rs admit() L3 BOUND → agent-bridle) — every surveyed system stops
    at "the token says you may";
  2. expected-responder binding (agent-mesh-bus/src/reply.rs:41) — everyone else
    authenticates the caller and leaves the response direction unauthenticated.

Cryptographic agent identity is explicitly not our differentiator: A2A #1672 has
657 comments, #1786 has 236, #1829 has 143, and none has graduated.

Contents

§
1–5 Executive summary, A2A ecosystem status, agent-mesh as implemented (status-tagged per concept, with file:line), A2A normative semantics (normative / optional / extension / unspecified), overlap-gap matrix
6–8 Security & provenance gap analysis, identity analysis, delegation-provenance trace examples
9–11 Five integration architectures evaluated, recommendation, what agent-mesh can delete, the differentiation sentence
12–15 Rust integration seam (a2a-rs), spike design, upstream contributions, next steps by dependency
16–17 Prior-art survey (18 candidates, adopt/adapt/align/reject), seven concrete integration proposals P1–P7
18 A2A standardization trajectory — adversarially verified, 11 confirmed / 14 refuted

Findings that bear on this repo's backlog

Also notes an upstream security issue

A2A spec §8.4.3 lets an Agent Card's signer nominate its own trust root via the
jku protected-header field (upstream a2aproject/A2A#2096, open). a2a-rs has no
card signature verification at all, so the Rust SDK is unprotected either way.

Test plan

Documentation only — no code, no tests affected. Verified:

  • cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings,
    full test + coverage all clean via .githooks/pre-push ([pre-push] OK).
  • Claims are cited to primary sources — the normative specification/a2a.proto, the
    spec markdown, governance docs, a2a-rs at 9d70cfd by file:line, and agent-mesh
    by file:line.
  • §18's claims went through a 3-vote adversarial refutation panel; the 14 refuted
    claims are recorded alongside the 11 confirmed, including one I had asserted in an
    earlier pass and which the evidence does not support.

A driving summary for other agents lives at
knowledge/board/2026-08-18_a2a-agent-mesh-interop-AGENT-BRIEF.md.

🤖 Generated with Claude Code

The unix_process tests failed intermittently with ExecutableFileBusy at the
spawn sites — 12/20 parallel runs on gnuc (ext4 /tmp), 0/4 serial. Different
tests failed on different runs, so this blocked the pre-push gate on any branch,
including docs-only ones.

WHAT: fake_ssh no longer writes the file it later execs. The script bytes go to
a staging path that is never executed, and a child process (/bin/cp) creates the
exec target.

WHY: Linux tracks write access as i_writecount per open-file-description, not
per descriptor. libtest runs the four #[tokio::test]s as threads sharing one
descriptor table, and glibc's posix_spawn issues clone3 WITHOUT CLONE_FILES, so
a sibling test thread's spawn duplicates the whole table. That duplicate keeps
this thread's write-side struct file alive past its own close() — f_count 2->1,
so __fput() never runs, so put_write_access() never runs, so i_writecount stays
1 — and the subsequent execve of that same inode is refused by
deny_write_access(). O_CLOEXEC does not help: it fires at the forked child's
exec, not at fork.

Delegating the write removes the precondition instead of retrying around it, and
the ordering is a kernel guarantee rather than a probability: status() returns
only once the copier has exited, and do_exit() runs exit_files() then
exit_task_work() — which flushes the deferred __fput — before exit_notify()
releases our wait. No descriptor for the executable ever exists in this process
to be inherited.

Production is untouched and was never exposed: the only production path is
SshTransport::bind -> OpenSshClient::system() -> /usr/bin/ssh, and set_mode(0o7xx)
appears exactly once in the workspace, in this test module.

Rejected alternatives: a retry at the production spawn site (masks a true alarm —
ETXTBSY there means someone holds a write fd on that inode right now — only
reduces rather than eliminates, and stalls the transport-wide outbound_connect
mutex); sync_all() before spawn (measured 54-176x WIDER window, since it holds
the descriptor open across the fsync); rename() into place (no effect — the
leaked duplicate is on the inode); a static Mutex or --test-threads=1 (hides it).

Measured: BEFORE 12/20 parallel runs failed; AFTER 0/30. Full crate 42 passed,
5/5 runs.

Refs #86
…survey, integration proposals

Research-only. Establishes what agent-mesh implements today vs what A2A v1.0.1
specifies, an overlap/gap matrix, an identity and delegation-provenance
analysis, evaluation of five integration architectures, a survey of
pre-existing standards (UCAN, Biscuit, AIP, AGNTCY Identity, WIMSE, SPIFFE,
Transaction Tokens, RFC 9421, in-toto/DSSE), and seven concrete integration
proposals.

Headline: agent-mesh does not substantially duplicate A2A — A2A defers identity
explicitly (spec §7) and disclaims authorization evidence (§7.6.4). What remains
distinctively ours after surveying prior art is (a) an attenuation lattice
checked against an OS enforcement witness and (b) expected-responder binding.

No code changes.
Adversarially verified pass: 25 candidate claims, 3-vote refutation panel,
11 confirmed / 14 refuted.

Findings that change the plan: the a2aproject extension pipeline has produced
ZERO graduations (both experimental repos seeded same-day 2026-05-14, no bare
ext-*/cpb-* exists); the structural gate is a named-maintainer sponsor, not
merit; insider comments on every identity proposal checked total zero (#1672 has
657 comments / 0 insider); the TSC is 8 vendor-appointed seats with steady-state
deferred to ~2026-12-23 and the graduation vote has never run.

Consequence: do not target an a2aproject extension repo near-term. Publish under
our own URI namespace (explicitly permitted by the same governance doc), and
treat the upstream a2a-rs SDK PRs as the relationship path.

Records the 14 refuted claims too, including the convenient-but-false 'A2A
deliberately defers identity to external SDOs'.
@hartsock hartsock added the risk:low Low-risk change: scoped, tested, no CI/build/hook edits label Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:low Low-risk change: scoped, tested, no CI/build/hook edits

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant