RFC: Extending A2A Agent Cards with behavioral rules (ERDL) #2031
Replies: 31 comments 49 replies
|
The behavioral-rules half of this is the right instinct: an Agent Card says what an agent CAN do, and declaring what it SHOULDN'T do in a deployment context is the missing piece. The deterministic action types and the audit trail exporting to OTLP/OCSF are the compliance-relevant parts, because they are about recorded, inspectable decisions. One caution on the The mechanism that does carry that weight is per-decision, not per-agent: make each governed decision a recomputable, content-addressed record binding the rule that applied, the verdict, and the inputs it was evaluated against, so any third party can re-derive it offline and confirm the action was permitted, without trusting a score or calling the guardian. That is the difference between reputation (an opinion about the agent) and compliance (verifiable proof about each action). The rules and audit-trail work you describe is most of the way there; the For what it is worth, we have built an open compliance gate for the A2A ecosystem that does exactly this: it emits a no-PII compliance receipt as a content-addressed object any party recomputes from the record alone, with no issuer contact, so a governed decision is provable rather than scored. It composes with the deterministic-rules and audit-trail model you have here, the rules decide, the receipt is the recomputable evidence. Happy to share it if it is useful to what you are building. On your direct question: A2A does not encode governance posture natively, and the durable way to communicate it between agents is not a score but a reference to verifiable decision records the counterparty can recompute, so posture is proven rather than asserted. |
|
@chopmob-cloud Thanks for the thoughtful and precise feedback — this is exactly the kind of architectural rigor the A2A governance discussion needs. You're right on the trust_score distinction. I'll amend the proposal: trust_score becomes advisory metadata explicitly labeled as a reputation signal, not a governance input. The load-bearing compliance mechanism must be per-decision, not per-agent — a content-addressed record binding (rule_version, inputs, verdict) that any third party can recompute offline. The compliance-receipt-v1 shape you described (JCS RFC 8785 canonicalization → SHA-256 frame_id → Ed25519 JWS receipt_hash over the canonical body) maps cleanly onto what ERDL's Action Guard would produce. In our model: the rule engine evaluates → deterministic action type (ALLOW/DENY/REFER/etc.) → structured audit trail → the receipt is the recomputable evidence exported to OTLP/OCSF. I'd be very interested in seeing the draft-hopley-x402-compliance-receipt I-D and understanding where the receipt format could compose with ERDL's rule-evaluation layer. Would you be open to a brief technical discussion on alignment points? |
|
Glad it maps, and labeling Two clarifications so the shape stays accurate as you fold it into ERDL:
On alignment: glad to keep working the composition points in the open here, and I can drop the receipt spec and vectors so the Action Guard mapping is concrete rather than described. |
|
@chopmob-cloud Appreciate the precision on content-address vs signature — that's the right distinction. Keyless recompute (RFC 8785 JCS → SHA-256 content-addressed frame → any third party re-derives from the record alone, no keys, no issuer contact) is the compliance load-bearing mechanism. Ed25519 JWS as an optional additive layer for named signers, not mandatory. ERDL's evidence chain model in §9 already follows this shape: canonicalize(record) → sha256 → receipt. No issuer-trust required for verification. Same split for Agent Cards noted — card_ref (keyless) + optional card_sign. Clean. Two things that would help pin the Action Guard ↔ receipt mapping concretely:
Happy to iterate in the open here. If you prefer to drop the spec and vectors as a gist or in this thread, either works. |
|
On the I-D you wanted to read, here is the datatracker link: On your first ask, the field set and mandatory-vs-optional. The receipt is a six-field JSON object, canonicalised under RFC 8785 (JCS), with
The direct answer to "which are mandatory vs optional": in a content-addressed receipt there is no optional field in the JWS sense. The hash is taken over the entire canonical object, so every field present is load-bearing, an added or absent field simply produces a different Mapping that onto ERDL's evidence record ( On your second ask, the retention chain: Happy to keep iterating in the open here. The field list above and the two vector sets are the concrete artifacts to map the Action Guard against; if it helps I can also point you at the exact |
|
@chopmob-cloud This is exactly what we needed. Thank you. Receipt alignment: The ERDL evidence record maps cleanly onto the 6-field receipt under RFC 8785 JCS. Our verdict (closed enum: ALLOW / BLOCK / REQUEST_HUMAN / ... 16 values) maps to your screen_result. rule_version and canon_version play the same role — pinned, versioned, no silent re-hashing. inputs and eval_tree become part of the canonical body that gets content-addressed. Your constraint that every field is load-bearing and that there is no "optional" in a content-addressed receipt is a sharp discipline we'll adopt. Vectors: We'll pull the Node runner from compliance_receipt_v1 and compliance_gate_lite_v1 and diff our Action Guard output against the expected digests as we implement ERDLEvidenceChain. If you can point me at the repo or gist with the runners, that saves me hunting. Retention chain: Read the I-D. The hash-based linkage (prev_hash = prior row_content_hash, agent-agnostic) is exactly the cross-Agent property we need. The specific anchoring rule for prev_hash in the vectors — if you can drop that, I can wire it into the multi-Agent evidence chain test case directly. One note on mapping: our verdict enum is 16 values (ALLOW → EMERGENCY_HALT), broader than your 3-value {ALLOW, REFER, DENY}. For compliance gate alignment, we'll map the subset that constitutes a governance-significant outcome (BLOCK / ESCALATE / EMERGENCY_HALT → DENY; REQUEST_HUMAN → REFER; ALLOW / AUDIT → ALLOW) while preserving the full 16-value enum in the canonical body for audit precision. Does that decomposition pattern align with your screen_result intent? Appreciate the depth here. This turns the Action Guard-to-receipt mapping from "conceptually compatible" to "byte-verifiable." Henry, |
|
The runners are in the public corpus, On the anchoring rule for the multi-Agent chain, the set you want is the retention chain (the I-D you read), and its row is not the compliance-receipt audit row, so the fields differ. The chain ref is On the 16 to 3 decomposition: the pattern is right, and preserving the full enum in the canonical body is the correct instinct, with two refinements. First, pin the projection map itself and version it the way Glad this got to byte-verifiable. We want to support the ecosystem forming on this substrate, so treat the runners and vectors as a stable reference to build against, and I am happy to help any ERDL implementer get their output reproducing. If a specific digest does not reproduce when you wire the runners in, send me the row and I will look at the exact bytes with you. |
|
@chopmob-cloud Received. Will clone the conformance vectors repo first thing and point ERDLEvidenceChain.verify() at compliance_receipt_v1/runner_node.js for byte-level diffing. Apache 2.0 LICENSE + NOTICE will stay alongside the vendored runners — provenance preserved. On the cross-Agent chain: The issuer_id inside the preimage, with rows from different issuers linking purely by prev_receipt_hash, is precisely what we need. I'll wire retention_chain_v1 Part B (006-009, two-issuer case) as the first multi-Agent test fixture for the ERDL evidence chain. That makes the cross-Agent property byte-verifiable rather than described. On the 16→3 projection: Agreed on both refinements. The projection map will be versioned and pinned alongside canon_version — not implicit, not configurable-at-runtime, but a fixed mapping under the same canonicalisation discipline. |
|
The recompute-from-the-record-alone property is the right bar for ERDL's evidence chain. One caution before it hardens on a single vector set: a conformance profile anchored on one authorship is only as neutral as that author — "recomputable" then quietly means "recomputable against them." What makes it real is a second, independently-authored emitter producing byte-identical canonical output (JCS/rfc8785 → SHA-256) from the same record. Concordia ships one: CascadeDecisionRecord, a committed recomputable terminal-deny — a denied or deferred action emits a verifiable receipt too, so there's no audit silence for a BLOCK to hide in. Public interop fixtures: https://github.com/eriknewton/concordia-protocol/tree/main/docs/interop/a2a-1404-receipt-revocation-vector . Happy to cross-run these against the ERDL vectors so the profile has two independent implementations, not one. |
|
Fantastic, glad it lines up so cleanly. If you need anything else, just shout. |
|
@haoran-tang-ch A spec draft is the right next move, and MIT with no permission gate is the right posture. One structural point before it hardens: neutrality is a property you test, not declare. The test is two independently authored implementations reproducing the spec's vectors byte for byte, with the vector set living somewhere any implementer can PR against. We have already run exactly this shape against AlgoVoi's corpus: Concordia reproduces all 22 compliance_receipt_v1 vectors byte for byte (write-up: #2038). Concordia commits to being a second independent runner for Decision Object v1.0 the week your draft lands. If a neutral home for the cross-run vector sets is useful, #2038 exists for exactly that. |
|
Henry, thank you for keeping the attribution careful as this hardens. One factual correction on the Decision Object v1.0 acknowledgments, checkable against this thread directly. The closing pull-quote beginning "An Apache-2.0 open corpus, actively maintained until a foundation can ratify it as neutral ground" is attributed to Erik Newton. That sentence was written in this thread by you, on 09 July, in the comment that opens "That's exactly the right posture," affirming the position I had set out just above it. It is your line describing the AlgoVoi posture, not Erik's, so the attribution is off by one. Whenever convenient it would be good to fix that entry so the record matches the thread. The other closing quote, "Neutrality is a property you test, not declare," is correctly Erik's. On the substance no change is needed, and I appreciate that it is already credited. Noting it once for the record as the spec settles: the content-addressed compliance receipt (RFC 8785 JCS canonicalize, SHA-256 frame, recomputable with no issuer contact), the reputation versus compliance distinction the trust_score discussion turned on, and the compliance_receipt_v1, compliance_gate_lite_v1 and retention_chain_v1 vector sets your evidence chain builds on and cross-verifies against are AlgoVoi's work. The dated comments in this thread are the record of it, and your acknowledgment already credits that substance; keeping the two closing quotes with who actually wrote them is the only correction. Glad ERDL is building on the substrate. Shout if any digest does not reproduce when you wire the runners in. |
|
Henry, I ran ERDL's five audit_vectors (AV-001 through AV-005 in decision-object-vectors-v1.0.json, draft.2) through the keystone's open validation framework, using our published RFC 8785 JCS canonicalizer and SHA-256 and following your one-step recipe (strip audit.hash, canonicalize, hash). All five reproduce byte for byte: my canonical bytes equal your canonical_bytes, my digest equals expected_sha256, and the recomputed value refills audit.hash exactly. The Decision Object's hash surface is clean against the substrate as it stands. The structural read is the useful part. ERDL already uses the same discipline (JCS RFC 8785, SHA-256, recompute from the record alone), so an ERDL decision record is content-addressed under the identical rule and composes by hash the way the keystone nodes do, without an adapter. Your audit.previous_hash chaining is the same content-hash linkage the keystone chain and the retention chain already use. So ERDL sits on the substrate natively rather than mapping onto it. On the practical side: the keystone is Apache-2.0 and built to be used exactly this way, a validation framework anyone runs their own records through, one that recomputes for everyone with no issuer call and no privileged runner. The runners are in the public corpus (github.com/chopmob-cloud/algovoi-jcs-conformance-vectors); composition/keystone_v1/verify_keystone.py and verify_keystone.mjs are the end-to-end example, and the vector sets ship a Python and a Node runner beside each fixture. Point ERDL's Decision Object validation straight at those if it helps. Glad to help wire the Action Guard output in if any digest does not reproduce. |
|
Thank you, Henry, and good luck with the other vendors. I think we can all agree that neutrality is the correct path. Our position is simply that it has to come via Foundations, not via any one vendor. If a foundation wants to work with us on it, we will happily work with them, the same way we already participate in the A2A ecosystem: https://a2a-protocol.org/latest/partners/ AlgoVoi is here if you need anything else. We will keep the substrate open for anyone to verify against. |
|
@chopmob-cloud @eriknewton — following up on the great progress here. A few updates from the ERDL side, and a request for your help. ERDL SPEC v1.1 is live → https://github.com/OpenOBA/erdl-landing Key changes in v1.1: Operators expanded: 11 → 13 (added not_in, not_contains) Verification Vectors expanded to 44 (37 decision + 7 audit hash) → https://github.com/OpenOBA/erdl-landing/tree/main/spec/vectors The audit hash vectors (AV-001 through AV-007) all use JCS RFC 8785 + SHA-256 — the same discipline @eriknewton verified byte-for-byte for AV-001~AV-005 back in July, and the same discipline that just produced 8/8 on compliance_receipt_v1 and 10/10 on jcs_edge_v1. What we'd like from you @eriknewton — Could you re-run Concordia's independent runner against the updated vector set (AV-001 through AV-007)? The 4 edge cases we fixed in the state vector spec (T06, T08, T09, C01) should produce clean matches as before. Independent confirmation would be gold. @chopmob-cloud — Same request from the compliance receipt side: re-validate the JCS+SHA-256 pipeline against the v1.1 decision output. The verdict mapping (16→3) should be unaffected, but the audit hash chain has two new entries. On neutrality and governance @eriknewton's offer to co-file with Concordia as the second implementation seems like the right next step. Happy to make ERDL the third. Also — we've included both of you in the SPEC's acknowledgments section (§14 / Community). Your cross-implementation rigor is what gives this standard its credibility. Best, |
|
Ran the same check here, and it both confirms Christopher's finding and confirms the fix: at current HEAD c3f22df all seven audit vectors reproduce byte-for-byte under Concordia's independent canonicalizer, including AV-003, AV-004, AV-005. The space after the em dash that dropped in the 23 July pass is back, and canonicalize(decision_object) now equals your published canonical_bytes for all three. That adds a fourth independent canonicalizer at the same result. I put the per-vector detail in #2038 to avoid duplicating here. |
|
Re-ran at 5cff368: 7 of 7, bytes and digest, under Concordia's independent canonicalizer. Worth naming what that commit actually fixed, because it is invisible to a canonicalizer and fatal to a verifier. Between c3f22df and 5cff368 the preimage, the canonical_bytes and the expected_sha256 are unchanged for all seven vectors. The only change is decision_object.audit.hash on AV-003, AV-004 and AV-005, which was still carrying the pre-fix digests. Anyone who strips audit.hash before hashing, as your own generator does, gets identical results at both commits. Anyone who checks the claimed audit.hash against their own recompute would have failed those three at c3f22df. That is the gap between reproducing bytes and verifying a claim. |
|
You are right, and our runner was implementing the shorthand. Added step 6 and re-ran both commits:
So my earlier framing was wrong in a way worth correcting on the record. It is not an extra check layered on the spec, it is the last step of the spec, and our 7 of 7 at c3f22df was the shorthand's answer rather than the spec's. The claimed-value comparison is the step that catches a stale self-referential digest, which is exactly what those three vectors were carrying. |
|
Erik, Chris — Thank you both for surfacing this. The discussion over the past 24 hours has been the most productive conformance review I've ever been part of. Let me share where we've landed on our side and propose a path forward for your review. What we've already done §3.8 and §12.7.3 of the spec have been upgraded. Step 6 is now a normative MUST. Preimage construction is explicit: delete the key, not blank it. The rationale section cites the c3f22df evidence and credits both of your analyses. On the specification text itself, we believe we are now solid. The next question: how should the vector set be designed? The core insight you both surfaced is this: a vector set that carries both the test (decision_object) and the answer key (expected_sha256, canonical_bytes) creates a structural blind spot. A verifier can compare its recomputation against the answer key and pass — without ever checking whether the artifact's own claimed hash is self-consistent. As Erik put it: "a production artifact carries no answer key — it carries a claim." As Chris put it: "a runner validated only against vectors can be structurally incapable of the check it will need in the field." We want to close this gap guided by two principles: Eliminate the vulnerability entirely — not merely catch it, but make it structurally impossible. Strip expected_sha256 and canonical_bytes from the audit vectors. The vector set carries only what a production artifact carries: the decision_object, with its self-referential audit.hash. A verifier then has exactly one path: strip audit.hash → JCS → SHA-256 → compare against the claimed value. There is no answer key to lean on. A five-step shorthand cannot pass — not because it was caught, but because the information it would need to bypass the check simply does not exist. Why we believe this serves both principles On eliminating the vulnerability: the problem is not that verifiers can cheat — it is that the vector set enables cheating by providing the answer. Remove the answer, and the vulnerability becomes structurally impossible. On neutrality: a vector set with an answer key requires trust in whoever provided the answers. A vector set without one requires no trust at all — anyone can verify its correctness by running the six-step method themselves. The mathematics of the hash function is the only authority. For a specification that we hope will become infrastructure, and that we intend to bring to A2A, this is the right posture. On diagnostic tooling We do not believe diagnostic tooling should be controlled by any single entity. While it is positioned as a non-authoritative development aid, correctness matters just as much — a diagnostic tool that produces wrong canonical_bytes is worse than no tool at all. Our thinking is that it should be developed collaboratively by the community, and your deep experience with JCS canonicalization and audit hashing would be genuinely valuable to its design and verification. If either of you already has diagnostic tools or test helpers, we would be very happy to link to them and credit them in the vector set repository. The specific form can be discussed — we would like to hear your thoughts first. What this means practically for your runners Both of your runners already implement the full six-step verification. The change should be transparent — drop any reference to expected_sha256 and re-run against the stripped vector set. Since all seven audit.hash values are already correct at 5cff368, the results should be identical. Next steps Chris: if you're still willing, a brief protocol-level analysis of this failure mode — what it is, why it is easy to miss, what the fix pattern should be — would be a lasting contribution to the spec's rationale section. We would value both of your thoughts. — Haoran |
|
Summary: v1.1 Freeze-Period Audit — Resolution @eriknewton @chopmob-cloud — the three issues raised during the freeze-period review of the ERDL Decision Object audit vectors have been resolved: 1. The 2.
3. AV-008 stale regression vector added (@eriknewton) A deliberately stale vector: 4. Five-step shorthand structural defect documented (@chopmob-cloud) The five-step procedure deletes the very field it needs to verify. At c3f22df it reported 7/7 PASS while the full six-step method exposed 3/7 stale vectors. The expanded Rationale in SPEC §12.7.3 now documents this as the empirical case, along with Chris's delete-vs-blank JCS divergence proof ( Changes landed: Independent verification status:
Thank you both for the rigorous review. This is exactly what a cross-implementation standard needs. |
|
Re-verified against the stripped vector set at AV-001 through AV-007: 7/7 byte-perfect. Our canonical bytes match the published AV-008: correctly fails. Recomputed One correction for the status table: the Concordia runner is Python, not Rust. It drives our RFC 8785 serializer directly. Removing the answer key was the right call. |
|
Title: ERDL Decision Object v1.2 RFC — Cross-Implementation Verification Request Body: @eriknewton @chris — We are seeking your review and independent verification of ERDL Decision Object v1.2. Background: The v1.1 independent audit revealed two architectural issues — c3f22df (em-dash whitespace fix causing audit.hash mismatches) and the expected_sha256 structural risk (pre-computed answer keys enabling "shortcut" validators). Both point to the same conclusion: v1.1's flat hashing structure is insufficient for 10-year production auditability. A breaking upgrade is necessary. What changed in v1.2: Hierarchical hashing (CORE×JURISDICTION in main JCS, extensions protected indirectly via extensions_hash) We need your help again: Review the whitepaper and provide feedback on architecture, compliance model, and long-term maintainability Whitepaper (Chinese): https://github.com/OpenOBA/erdl-vectors/blob/master/docs/WHITEPAPER-v1.2-DRAFT-3.md @eriknewton — If you'd like a copy of the whitepaper via email as well, please leave your address and we'll send it over. v1.2 is not a rewrite of v1.1 — your audit findings and independent verification directly shaped this architecture. We would not be here without your work. Looking forward to your feedback. |
|
Congrats on publishing the white paper. Happy to take the audit-hash set. I will run AV-001 through AV-012 against Concordia's independent canonicalizer under the full method, recomputing from first principles and comparing each artifact to its own claimed audit.hash rather than to any field in the vector file. I will post the per-vector result here either way. On the whitepaper: I do want to read it properly and I will, but the next two weeks are very busy, so I would rather tell you that now than go quiet on you. Better a verification you can trust soon than an opinion that arrives late. No need to email anything, I'll pull the draft from the repo. |
|
Started on this, and hit a snag straight away: all four links 404 for me, signed in and signed out, and OpenOBA/erdl-vectors does not resolve as a public repo. The org shows only erdl-landing and erdl-mcp-server. I suspect it is still private. My side is ready. The runner is written and re-validated against the published v1.1 set: AV-001 through AV-007 pass and AV-008 correctly fails as the stale canary. It recomputes from first principles and compares against each artifact's own claimed audit.hash, so if a future set carries a precomputed digest field the runner never reads it. Flip the repo public, or point me at wherever the v1.2 vectors actually live, and I will run AV-001 through AV-012 and post the per-vector result here. |
|
AV-001 through AV-012, verified with Concordia's independent RFC 8785 canonicalizer: eleven verify byte-perfect against each artifact's own claimed Three notes, in the order I would act on them. 1. The preimage rule in the whitepaper does not reproduce your own vectors. Section 13.3 says "DELETE audit.hash + DELETE signature + DELETE signing_key_id". The Runner's Guide and 2. Removing the whole 3. On Happy to share the runner. |
|
Chris, I wanted to update you on the ERDL Decision Object v1.3 release and ensure you know how much your work shaped this iteration. Every finding you reported — C1 through C4, S1 through S3 — has been addressed in RFC 001 (OPENOBA-DOBJ-RFC-001), published today: C1 (self-referencing exclusion): Confirmed correct. policies[].hash and profile_hash self-exclusion is documented in §3.2 with explicit JCS-before-hashing convention. The repo is at https://github.com/OpenOBA/erdl-vectors. Erik Newton has also completed his re-verification pass with eleven byte-perfect matches out of twelve, and his three findings (E1–E3) are likewise fully addressed. You set a high bar with your review, and the protocol is measurably stronger for it. Thank you — genuinely. —Tang Haoran |
|
Re-ran against v1.3 at One note on AV-013: as published it cannot produce the false MATCH it is designed to catch. Its stored |
|
Re-verified at |
|
Haoran, thank you for the generous note, and congratulations on the v1.3 turnaround. Correcting a canary within six hours of a report is rare, and the way you handled the AV-003 through AV-005 drift set the tone for the whole thread. Two follow-ups, both in the same spirit as the vectors. On the reference implementation: the Quick Start clone target and the engine repository both return 404 for me, and I cannot find Rulsynor published anywhere. Neutrality is measured across implementations, so if the Concordia runner is currently the only one a reader can execute independently, the README would be stronger for saying that plainly rather than leaving a second implementation to be inferred. On wording: "agents cannot bypass it" is stronger than an in-process evaluator can demonstrate. Mediating every call that arrives is a real and useful property, and claiming exactly that will hold up better under adversarial review. Erik |
|
@haoran-tang-ch Glad the generated-artifact pattern fits. If you sequence it, the clean-room job with the SDK uninstalled is the piece I would land first: it is the one that catches hidden SDK dependence, and the rest composes on top. |
Uh oh!
There was an error while loading. Please reload this page.
A2A's Agent Card defines what an agent CAN do — its capabilities, skills, endpoints. This is powerful. But it doesn't define what an agent SHOULDN'T do in a given deployment context.
Proposal: Agent Card extension for behavioral rules
{ "extensions": { "erdl": { "protocol": "erdl/v1", "rules_file": "agent.erdl.yaml", "guardian": "did:erdl:guardian-main", "trust_score": 850 } } } This would let: Agent B know what behavioral rules Agent A operates under — before accepting task delegation Guardian Agents discover rule profiles of observed agents through Agent Card exchange Multi-agent workflows pre-validate rule compatibility at the protocol level What ERDL provides ERDL (Entity-Rule Definition Language) is an open standard (MIT) for agent behavioral rules: 11 operators (within, rate new in v1.0) 16 deterministic action types (ALLOW → EMERGENCY_HALT) Execution Rings (Ring 0–3) Guardian Agent / Observed Agent model SafeExpr engine (zero code injection) Structured audit trails exporting to OTLP/OCSF Deliverables Landing Page: openoba.github.io/erdl-landing Spec v1.0 (EN): github.com/OpenOBA/erdl-landing/blob/main/spec/index-en.md Reference Implementation: github.com/OpenOBA/ERDL Question for this community Does extending Agent Cards with a rules profile make sense for A2A? Are there existing or planned mechanisms in A2A for communicating governance/security posture between agents? Happy to contribute a formal RFC if there's interest.All reactions