docs(research): Agent Mesh × A2A interoperability study - #88
Open
hartsock wants to merge 3 commits into
Open
Conversation
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'.
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.
Summary
Research only — no code changes, no protocol commitment. Adds
docs/research/a2a_interop.md(~1470 lines), the study of how agent-mesh shouldrelate to the A2A protocol (spec v1.0.1, Linux
Foundation).
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:
(
authority.rsadmit()L3 BOUND → agent-bridle) — every surveyed system stopsat "the token says you may";
agent-mesh-bus/src/reply.rs:41) — everyone elseauthenticates 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
a2a-rs), spike design, upstream contributions, next steps by dependencyFindings that bear on this repo's backlog
Partoneof(text / raw bytes / url / structured data, each with
media_type). Recommendadopting rather than designing format negotiation.
contextId/taskId, eventordering guarantees and multi-subscriber broadcast per task (§3.5.2). Recommend
open_sessionbecomes the carrier for A2AStreamResponse, not a new turn model.RecordKindvocabulary reinventsMessage/Part/Artifactplus MCP. Recommend payloads become CIDs over canonicalA2A objects, keeping only
Attestation/Checkpoint/Decision/Retraction/Supersession.SignedEnvelopecarries noGrantId,so the authority DAG is not bound to messages; and
Derivation::Elevationalwaysfail-closes (
DenyAllElevations) because assertion signatures are deferred. Bothblock every provenance claim regardless of A2A.
Also notes an upstream security issue
A2A spec §8.4.3 lets an Agent Card's signer nominate its own trust root via the
jkuprotected-header field (upstream a2aproject/A2A#2096, open).a2a-rshas nocard 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).specification/a2a.proto, thespec markdown, governance docs,
a2a-rsat9d70cfdby file:line, and agent-meshby file:line.
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