Skip to content

feat(delegation): add parent_record_hash, verify_delegation_link, and verify_delegation_chain - #588

Open
drk-ram wants to merge 3 commits into
agentrust-io:mainfrom
drk-ram:drk-ram-feat-python-a2a-delegation-verifier
Open

drk-ram wants to merge 3 commits into
agentrust-io:mainfrom
drk-ram:drk-ram-feat-python-a2a-delegation-verifier

Conversation

@drk-ram

@drk-ram drk-ram commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

What this changes

Adds src/agentrust_trace/delegation.py (exposed as agentrust_trace.delegation), bringing the Python SDK to parity with trust-record-verify/src/delegation.ts and the 26 A2A delegation-link conformance vectors in examples/delegation-link/:

  • parent_record_hash(record, algorithm="sha256"): computes the spec/trace-v0.2.md section 3.1.3 chain digest ("<alg>:<hex>") over the complete RFC 8785 (JCS) canonical form of record, signature included, for sha256 and sha384.
  • verify_delegation_link(child, parent, *, supported_digest_algorithms=DELEGATION_DIGEST_ALGORITHMS): verifies the single-hop section 3.1.3 delegation commitment (parent_record_hash and credential_id) against a candidate parent record and returns a frozen DelegationLink.
  • verify_delegation_chain(records, leaf, context, *, rules=RULES): executes the 11-rule A2A delegation-chain walk from leaf (accepting either a digest string or the leaf record dict) over an unordered record set and returns a frozen ChainResult. Validates each record against the TRACE v0.2 JSON Schema via validate_json, decides iat by value via sign._integer_value, decodes cnf.jwk.x and signature via sign._b64url_decode, and reports an unlisted data_class on either side of a hop as unverifiable (data_class_unknown, covered by vectors 25-data-class-unknown-at-leaf.json and 26-data-class-unknown-at-parent.json).
  • Points tests/test_delegation_vectors.py and tests/test_delegation_completeness.py at agentrust_trace.delegation so there is a single walk implementation across the repository, and updates docs/rfcs/a2a-delegation-profile.md and examples/delegation-link/README.md with D-11 (data_class_unknown) and the 11-rule / 26-vector counts.
  • DelegationError(ValueError): documented exception raised across all malformed inputs, registered in tests/test_public_functions_raise_what_they_document.py.

Contributor: Raghuvar Durga (@drk-ram)
Closes #581

Type of change

  • Editorial (typo, link fix, clarification: no normative effect)
  • Non-breaking spec change (new optional field, new platform profile, informative addition)
  • Breaking spec change (requires 14-day comment period and Project Lead sign-off)
  • Schema change
  • Example addition

Spec section

spec/trace-v0.2.md section 3.1.3 (single-hop delegation block digest and link verification) and docs/rfcs/a2a-delegation-profile.md (11-rule A2A delegation-chain walk).

Tests for a fix

New module (src/agentrust_trace/delegation.py). Removing the data_class_unknown entry from RULES with every name in place fails 12 tests: vectors 25 and 26 in test_delegation_vectors.py and test_delegation_module.py, the five lattice cases of test_unlisted_data_class_reports_unverifiable_and_never_verified, and three completeness guards in test_delegation_completeness.py.

Validation run:

  • pytest tests/test_delegation_module.py tests/test_delegation_vectors.py tests/test_delegation_completeness.py tests/test_delegation_parent_hash_canonicalization.py tests/test_adequacy_all_sets.py tests/test_generators_reproduce_fixtures.py tests/test_public_functions_raise_what_they_document.py tests/test_requirement_keywords_are_attributable.py tests/test_revocation_bundle.py: passed (498 passed)
  • python tools/sweep_public_surface.py --strict: passed (98 parameters swept, 0 unfiled leaks)
  • python tools/check_dashes.py: passed (no dashes outside exempt paths)
  • ruff check: passed
  • mypy --strict src/agentrust_trace/delegation.py tests/test_delegation_module.py: passed

Checklist

  • DCO sign-off on all commits (git commit -s)
  • CHANGELOG.md updated (for any normative change)
  • Breaking changes marked with <!-- CHANGED: #NNN: description --> in spec text
  • Backward compatibility statement included (for breaking changes)

Changelog entry

@drk-ram
drk-ram requested review from a team, lywinged and rajnisht7 as code owners October 19, 2026 19:23

Copy link
Copy Markdown
Contributor

A concrete DCO-signed author-adoption companion is available: a089d8b292ea06232043faf3f1505952df5a12a7, branch fix/588-delegation-audit, based on reviewed head 33286a34ef1fbb90e28ae456ce082eae1c46cff0.

Refuses unknown delegation classes and stops traversal at the depth bound.

Earlier exact-commit validation: 248 focused tests pass; five new controls fail against the original implementation; Ruff and module mypy pass. These results come from the recorded correction run; I verified the published commit/sign-off/files today, not a new runtime rerun.

Initial input indexing still requires caller-provided record/byte bounds. This does not settle broader delegation policy semantics.

For adoption, fetch https://github.com/dinakarjs/trace-spec.git branch fix/588-delegation-audit and apply the missing correction against the current head. Please run final-head checks and obtain independent review after incorporation. Original PR ownership is retained; this handoff is not approval of my own correction.

Reference: src/agentrust_trace/delegation.py and tests/test_delegation_module.py define the local classification/depth contract. Prepared with Codex.

@imran-siddique imran-siddique left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked at 33286a3: 404 passed, the sweep reports 0 unfiled leaks, and all 24 vectors agree in three record orders.

One fail-open first. _data_class_widened returns False when either class is missing from the lattice, so vector 18 goes from authorization-invalid to verified with data_class_lattice=["public"]. The test walk has the same gap, but it never shipped. Please report an unknown class as unverifiable, add a vector, and point test_delegation_vectors.py at this module so there is one walk. Plus a CHANGELOG Added line for the new API.

@drk-ram
drk-ram force-pushed the drk-ram-feat-python-a2a-delegation-verifier branch from 33286a3 to bca6951 Compare October 20, 2026 15:41

@lywinged lywinged left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REVIEW on #588, head bca6951: Request changes

The second commit does what the earlier review asked, and the shape of the fix is the right one: a class outside the lattice is reported as unverifiable under its own code, not as a failure and not as a pass. Measured on bca6951 with the hash-pinned requirements, on 3.11 and on 3.12: 4666 passed, 48 skipped on both; ruff, mypy, the dash check and sweep_public_surface.py --strict clean; all 26 vectors reach their declared outcome in every record order the tests try, and deleting any one of the eleven rules moves exactly two vectors. The nearest wrong fix, reporting an unknown class as a failure, moves vectors 25 and 26 on their declared classification and fails the five unverifiable cases of test_unlisted_data_class_reports_unverifiable_and_never_verified, so those are the lines that hold the choice. Two places where the module is behind the package it now sits in, both reproduced on this head.

  1. iat is decided by spelling. _validate_record_shape (delegation.py lines 385 to 394) refuses a record whose iat is 1785000000.0. Section 3.2.2 as merged in #404 (spec/trace-v0.2.md line 530) says that number is the integer 1785000000 and that a verifier MUST decide on the value, and sign.verify_record does, through _integer_value (sign.py line 391). Take vector 01 and rewrite the leaf's iat as that float: the JCS bytes are unchanged, the signature verifies, the schema accepts it, sign.verify_record returns a VerificationResult, and verify_delegation_chain raises DelegationError: record must carry an integer iat, whether the leaf is passed by digest or as the dict. One package, one record, two answers, on the exact distinction #404 took out of verify_record. _integer_value is one import away, beside the _canonical_bytes the module already takes from sign. The credential bounds are context rather than record members, so what they accept is your call.

  2. D-1 accepts what the package refuses. _decode_b64u (delegation.py lines 180 to 186) pads and calls urlsafe_b64decode, which ignores the unused bits of the last character. Spec/trace-v0.2.md line 512 says a verifier MUST reject a record whose signature is not canonically encoded; sign._b64url_decode (sign.py line 509) does, and the schema pattern does. Respell the last character of the same leaf's signature so that it decodes to the same 64 bytes and pass the leaf as the dict: validate.iter_errors reports the pattern, sign.verify_record refuses it as not canonical, _signature_invalid returns False, and the chain comes back verified with no codes. The walk also returns verified for a correctly signed leaf carrying a top-level member the schema forbids, because nothing in the module runs the schema, where verify_record runs validate_json (sign.py line 932) before it verifies the signature. The reference walk in the test file decoded the final character the same way, so this is inherited rather than introduced, and the earlier review's point about the lattice gap applies here too: the test walk never shipped, and this change ships it beside verify_record. The RFC keeps schema defects outside the profile (a defect the schema already rejects is not a profile defect), so a record's validity is a precondition of the walk rather than one of its rules, and _validate_record_shape is where this change already checks part of that precondition. Running validate_json there refuses both records above as input (the corpus is unaffected, every vector already validates), and decoding with sign._b64url_decode in D-1 keeps the walk's own check in step with verify_record for whatever the schema pattern does not reach. What the function must not do is report either verified.

  3. The eleventh rule is in the code and in the CHANGELOG entry, and in none of the documents that describe the profile. RULES has eleven entries and the corpus has 26 vectors. docs/rfcs/a2a-delegation-profile.md still says ten rules, ten defects and 24 vectors (lines 3, 8, 91, 191, 195 and 225) and its section 3 table has no row for data_class_unknown; examples/delegation-link/README.md line 64 says ten rules; the module docstring (delegation.py lines 13 to 15) says ten-rule and 24 test vectors; and tests/test_delegation_vectors.py lines 11 to 13 still say nothing here is exported and the package gains no public API for rules that are not yet normative, which this change makes false. Someone scoring a second implementation from the RFC table cannot know the rule exists. Please add the row (code, class unverifiable, vectors 25 and 26, and that a class absent from the lattice at either end of a hop is unknown, the same string at both ends included), fix the counts, and the two docstrings.

  4. The review-bar line in the description is produced by the test files, not by the code. On this head review_bar.py prints "175 fail on behaviour, 0 fail on a missing name or file", the figure the description reports, and it comes from the except ImportError guards this change adds to four test files; none exist on main. Three of the files raise pytest.fail("unimplemented") at import and the fourth defers the same call to five tests, so on the merge base the three fail at collection with "Failed: unimplemented", which the tool charges to each of their tests and cannot sort as a missing name, and the remaining failures are the fourth file's guards raising the same string. The tool says its sorting can be wrong both ways; here the guards push it the wrong way, and with them replaced by plain imports the same run sorts every failure as a missing name, which is what a new module should report. "Before a pull request is reviewed" does not owe a switched-off test for a new module, but the fix in the second commit is the case it was written for, and the test exists on this head: removing the data_class_unknown entry from RULES with every name in place fails 12 tests, vectors 25 and 26 in both vector files, the five lattice cases of test_unlisted_data_class_reports_unverifiable_and_never_verified, and three completeness guards. That sentence is worth putting in the description in place of the tool's line, and the guards can go; they are dead code once merged.

  5. Not a change request, a note for whoever picks up the companion branch (a089d8b on the dinakarjs fork). The walk does not stop at max_depth in its control flow, and the test file carried the comments saying why: the depth bound is not repeated, the walk breaks for one reason only, and there is no cycle rule. The reasoning is still in the completeness file's docstring; the walk itself no longer carries it. Applying the companion's stop, with its failures.append("depth_exceeded"), after the resolve rules and before the parent lookup, as the companion places it, fails four tests in test_delegation_completeness.py: emission outside the registry, the margin and the independence of depth_exceeded, and the ratchet. A bare break at the same place fails the independence test alone, because vectors 20 and 21 then move together under the off-by-one defect, which is the case the comment described. Worth carrying the comments over beside the code.

With 1 and 2 fixed and 3 and 4 done, I would approve.

@drk-ram

drk-ram commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Thank you @lywinged and @imran-siddique for the thorough reviews! All five items are addressed in 547a4ef:

  1. iat decided by value via sign._integer_value: _validate_record_shape and _credential_window now use sign._integer_value(record.get("iat"), "iat") (wrapped in DelegationError), matching sign.verify_record. Added test_verify_delegation_chain_decides_iat_by_value in tests/test_delegation_module.py proving a record with iat: 1785000000.0 verifies whether leaf is passed by digest or as a dict.
  2. Schema validation in _validate_record_shape and sign._b64url_decode in D-1: _validate_record_shape now validates each record with validate_json (wrapping ValidationError in DelegationError), and _signature_invalid decodes cnf.jwk.x and signature via sign._b64url_decode (enforcing canonical unpadded base64url with zero unused low bits). Added test_verify_delegation_chain_refuses_non_canonical_signature_and_unknown_members in tests/test_delegation_module.py.
  3. Profile documentation and docstrings updated for D-11 (data_class_unknown) and 26 vectors: Added the D-11 (data_class_unknown, unverifiable, vectors 25 and 26) row to the section 3 table in docs/rfcs/a2a-delegation-profile.md, updated the rule/defect/vector counts in docs/rfcs/a2a-delegation-profile.md and examples/delegation-link/README.md, and updated the module docstrings in src/agentrust_trace/delegation.py and tests/test_delegation_vectors.py.
  4. Plain imports in the four test files and PR description: Removed the except ImportError guards from tests/test_delegation_module.py, tests/test_delegation_vectors.py, tests/test_delegation_completeness.py, and tests/test_public_functions_raise_what_they_document.py, and updated ## Tests for a fix in the PR description with the switched-off data_class_unknown check.
  5. Walk comments carried over: Restored the control-flow and no-cycle comments inside verify_delegation_chain in src/agentrust_trace/delegation.py.

@dinakarjs dinakarjs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked 547a4ef. The focused delegation module/vector/completeness selection passes (156 tests, Linux/Python 3.12.14 with the hash-locked dev dependencies). The current code uses schema validation, value-based integer handling and canonical base64url decoding, updates D-11 documentation, and removes the import guards that distorted review-bar classification. Current technical CI is green; the approval gate remains separate.

I withdraw the adoption recommendation for my earlier companion a089d8b. Its depth stop conflicts with the existing completeness/independence contract; it must not be cherry-picked unchanged. The current walk's restored comments explain why depth is a rule rather than a second control-flow stop. This supersedes my earlier handoff for that companion. I am not dismissing another reviewer's outstanding review or claiming independent approval of my own proposed correction.

@dinakarjs dinakarjs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completing the current implementation review at unchanged 547a4ef. Re-ran delegation module/vector/completeness selection on Linux/Python 3.12.14 with the hash-locked dependencies: 156 pass. The current code's schema input precondition, shared value-based integer helper and canonical base64url decoder address the reported consistency gaps. The D-11 documentation and plain imports now match the eleven-rule/26-vector implementation; restored walk comments preserve the rule-independence contract. Current technical hosted checks pass.

My prior a089d8b companion remains withdrawn and must not be applied: its depth stop is incompatible with this walk's completeness contract. This approval covers the author's current implementation and does not revive that alternative or dismiss another reviewer's formal changes request. No production platform appraisal, independent key enrollment or broader PIC verification claim is made. No additional blocker found in this scope.

@lywinged lywinged left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 547a4ef on 4c2883d. The four things I asked for are done. One small thing, and then this is an approval; I will approve the head that carries it.

What I checked rather than read:

  • iat is decided by value. _validate_record_shape and _credential_window both go through sign._integer_value, and the new test pins the first: with that call put back to a type test, test_verify_delegation_chain_decides_iat_by_value fails and the other 155 tests in the three delegation files pass. The second call is belt and braces; the raw comparison it replaced passes the same test, because the shape check has already decided the value.
  • Both halves of the second point are load-bearing on their own. With _b64url_decode swapped back for base64.urlsafe_b64decode, _signature_invalid returns False on the non-canonical spelling and the new test fails there; with the validate_json call removed, the same test fails at its first schema assertion, since that record now comes back provenance-invalid instead of refused, and the record carrying an extra top-level member, probed directly, walks to verified.
  • The counts match the tree: 26 vector files, 11 entries in RULES, 11 keys in DEFECTS, data_class_unknown in the margins file at 2, and nothing left saying 24 vectors or ten rules outside the CHANGELOG history. Under the new declared defect, vector 25 still reaches its outcome and vector 26 does not, which is the independence the margins require.
  • No except ImportError left in the three delegation test files. The review bar against the merge base reports 368 changed tests failing on the base for the missing module and none passing, which is what a new module should look like.
  • CI's steps with the pinned install: ruff, the dash check and mypy clean; 4668 passed and 48 skipped on this head on 3.11 and on 3.12, against 4603 and 48 on main on 3.12, the difference being the 65 tests this adds; the experiments lane and the delegation files under LC_ALL=C PYTHONUTF8=0 pass.

The one thing. verify_delegation_link compares the stated and recomputed digests with hmac.compare_digest on str, and that raises TypeError ("comparing strings with non-ASCII characters is not supported") when parent_record_hash carries a non-ASCII character after a supported prefix: sha256:é followed by 63 zeros, with a well-formed credential_id, reaches it. The docstring promises DelegationError. The chain walk never gets there, because the schema pattern refuses the value first; this function's input arrives as given. The TypeScript verifyDelegationLink reports delegation_parent_mismatch on the same input, since its timingSafeEqual compares char codes, so the two implementations the CHANGELOG says match part ways there. A guard on the comparison closes it:

    if not (stated.isascii() and hmac.compare_digest(computed, stated)):

With that line every existing test stays green and the input comes back as the documented refusal, as does a lone surrogate, sha256:\ud800 and 63 zeros, which json.loads yields for the escape and which encoding the string to bytes would turn into UnicodeEncodeError instead. Two cases in test_verify_delegation_link_refuses_absent_malformed_unsupported_or_mismatched would pin it; the public-surface sweep cannot reach it, because none of its junk values carries a delegation block.

Three things I would not hold the merge for:

  • _validate_context checks that each trusted root key is an object and nothing more, so a key whose x is a list passes it and _jwk_key raises TypeError when the trusted set is built. Context is the caller's own, which is why this is not the one thing; it is the same contract, and a string check on x closes it.
  • The module docstring says the chain walk is "specified in" the RFC, and the RFC's status line says it binds nothing. The sentence the test module used to carry, that the package gains no public API for rules that are not yet normative, left with the move. One clause saying the link digest is the normative part and the chain walk executes a draft profile keeps the package from claiming more than the spec does.
  • The new ### Added heading is the first sub-heading under ## [Unreleased], so it now sits above every entry there, three of which are marked breaking. Not this change's doing; a ### Changed above the next entry would keep the heading honest.

Copy link
Copy Markdown
Contributor

Implemented lywinged's requested ASCII guard as a one-commit author-adoption companion: dinakarjs#2, commit 892d7a9, based on your exact 547a4ef head.

Reproduced four failures on the original (non-ASCII and lone-surrogate digests, SHA256/SHA384); all return DelegationError with the fix. Final focused selection: 160 tests pass on Python 3.12.14; Ruff and targeted mypy pass. A UTF-8-encoding near-miss still fails both surrogate cases. This keeps the chain walk unchanged and does not revive the withdrawn depth-stop companion.

Please cherry-pick if useful, then request lywinged's promised current-head re-review. The nonblocking trusted-key typing, draft-profile wording and changelog-heading points still need your disposition. This companion is not independent approval of my own correction.

@imran-siddique
imran-siddique dismissed their stale review October 22, 2026 00:05

All three of my points are in 547a4ef: a class outside the lattice is now D-11 unverifiable (vectors 25 and 26), test_delegation_vectors.py imports the module so there is one walk, and the CHANGELOG line is there. Dismissing so it does not hold the merge. @lywinged has the last review.

@drk-ram
drk-ram force-pushed the drk-ram-feat-python-a2a-delegation-verifier branch from 547a4ef to 4616300 Compare October 22, 2026 01:14
@drk-ram

drk-ram commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Thank you @lywinged and @dinakarjs! Addressed the required item and all three polish items in 4616300 (rebased onto origin/main):

  1. Guard verify_delegation_link against non-ASCII / lone-surrogate digests: Updated the digest comparison to if not (stated.isascii() and hmac.compare_digest(computed, stated)): and added the sha256: / sha384: non-ASCII (\u00e9) and lone-surrogate (\ud800) cases to test_verify_delegation_link_refuses_absent_malformed_unsupported_or_mismatched.
  2. Validate trusted_root_keys JWK member types in _validate_context: Verified that each JWK in trusted_root_keys carries non-empty string kty, crv, x (and optional y) members so _jwk_key never raises TypeError on unhashable values, with regression cases in test_verify_delegation_chain_refuses_malformed_caller_inputs.
  3. Clarify normative vs draft scope in src/agentrust_trace/delegation.py docstring: Stated explicitly that parent_record_hash and verify_delegation_link implement the normative section 3.1.3 single-hop link digest while verify_delegation_chain executes the draft profile in docs/rfcs/a2a-delegation-profile.md (which is informative and binds no implementation yet).
  4. CHANGELOG.md sub-heading: Added ### Changed immediately below the new ### Added entry so the existing [Unreleased] entries sit under ### Changed.

@drk-ram
drk-ram force-pushed the drk-ram-feat-python-a2a-delegation-verifier branch from 4616300 to 33af303 Compare October 22, 2026 04:27

@dinakarjs dinakarjs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorporation follow-through at 33af303: the ASCII guard, trusted-root member typing, normative single-hop versus informative chain-walk distinction, and changelog heading are present. Independent local Linux/Python 3.12.14 selection tests/test_delegation*.py: 161 passed.

This closes my bounded follow-up on those four items. I supplied the ASCII-guard companion, so this is incorporation verification and does not supply independent approval of my correction. Please retain lywinged's current-head re-review and ordinary maintainer gates. Reviewed with OpenAI Codex.

drk-ram and others added 3 commits October 23, 2026 23:12
… verify_delegation_chain

Implement the section 3.1.3 single-hop delegation-link digest and link
verifier (parent_record_hash, verify_delegation_link) alongside the ten-rule
A2A delegation-chain verifier (verify_delegation_chain) in
agentrust_trace.delegation, and register all three entry points in the public
surface sweep.

Closes agentrust-io#581

Signed-off-by: Raghuvar Durga <177662415+drk-ram@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…st imports

- Decide `iat` by value via `sign._integer_value` so whole-valued floats (such
  as `1785000000.0`) are accepted consistently with `sign.verify_record`.
- Validate records against the TRACE v0.2 JSON Schema via `validate_json` in
  `_validate_record_shape` and decode `cnf.jwk.x` and `signature` via
  `sign._b64url_decode` in D-1 so non-canonical base64url spellings and
  unknown members are refused.
- Document `D-11` (`data_class_unknown`) and the 26-vector / 11-rule counts in
  `docs/rfcs/a2a-delegation-profile.md`, `examples/delegation-link/README.md`,
  `src/agentrust_trace/delegation.py`, and `tests/test_delegation_vectors.py`.
- Replace `except ImportError` test guards with plain imports and carry the
  walk design comments into `verify_delegation_chain`.

Signed-off-by: Raghuvar Durga <177662415+drk-ram@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Guard `verify_delegation_link` with `stated.isascii()` before
  `hmac.compare_digest` so a `parent_record_hash` carrying non-ASCII or
  lone-surrogate characters after a supported prefix raises `DelegationError`
  rather than `TypeError`.
- Validate in `_validate_context` that each JWK in `trusted_root_keys` carries
  non-empty string `kty`, `crv`, `x` (and optional `y`) members so `_jwk_key`
  never raises `TypeError` on unhashable member types.
- Clarify in `src/agentrust_trace/delegation.py` that the single-hop link
  digest is normative (`spec/trace-v0.2.md` section 3.1.3) while
  `verify_delegation_chain` executes the draft profile in
  `docs/rfcs/a2a-delegation-profile.md`.
- Add `### Changed` below the `### Added` entry in `CHANGELOG.md`.

Signed-off-by: Raghuvar Durga <177662415+drk-ram@users.noreply.github.com>
Co-authored-by: Srinivasa Consultants <78673153+dinakarjs@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@drk-ram
drk-ram force-pushed the drk-ram-feat-python-a2a-delegation-verifier branch from 33af303 to 23cfc2b Compare October 24, 2026 04:12

This branch has not been deployed

No deployments
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.

feat(delegation): add parent_record_hash, verify_delegation_link, and verify_delegation_chain to agentrust_trace

4 participants