Skip to content

conformance: pre-filled Signet self-certification template (for @willamhou review)#1

Merged
tomjwxf merged 2 commits intomainfrom
conformance/signet-template
Apr 20, 2026
Merged

conformance: pre-filled Signet self-certification template (for @willamhou review)#1
tomjwxf merged 2 commits intomainfrom
conformance/signet-template

Conversation

@tomjwxf
Copy link
Copy Markdown
Contributor

@tomjwxf tomjwxf commented Apr 19, 2026

Summary

Adds a pre-filled Signet conformance template under conformance/signet/ and updates the Signet row in IMPLEMENTATIONS.md from "Under review" to "Self-certification template staged".

Intent: lower @willamhou / Signet-maintainer activation energy from "design a conformance mapping from scratch" to "confirm, correct, or extend a pre-filled mapping."

What's in the template

  • conformance/signet/FIELD-MAPPING.md - Signet receipt fields mapped onto draft-farley-acta-signed-receipts-02 fields. Pre-populated from the public Signet source at crates/signet-core/src/. [CONFIRM] / [FILL] markers flag each inferred entry that needs maintainer sign-off.
  • conformance/signet/DEVIATIONS.md - Four documented wire-format deltas that are adapter-addressable but not structural conformance blockers:
    1. Envelope shape: flat struct vs {payload, signature} split
    2. Signature encoding: ed25519:<base64> vs <base64url> + alg field
    3. Chain linkage: parent_receipt_id (by ID) vs previousReceiptHash (by hash of canonical envelope)
    4. Key identifier: signer.pubkey in body vs signature.kid (JWK thumbprint) + external key discovery
  • conformance/signet/ADAPTER.md - Pseudocode sketch of a thin Signet -> draft-02 shim in co-signer mode. Includes open questions for the maintainer (live in Signet repo? out-of-tree crate? operator key-custody).
  • conformance/signet/README.md - What's here and what the maintainer needs to do to turn this into a filed conformance claim.

What this template is NOT

  • Not a binding claim of conformance. Signet is not conformant until the maintainer resolves the [CONFIRM] / [FILL] markers.
  • Not an adapter implementation. ADAPTER.md is pseudocode, not code.
  • Not a fork-and-rewrite proposal. Signet's existing wire format is its own design; this template documents how it maps, nothing more.

What triggered this

Thread on microsoft/agent-governance-toolkit#1201. Signet shares the same crypto primitives with draft-02 (JCS RFC 8785 canonicalization, Ed25519, SHA-256 hashing). The wire-format gap is isolated to field naming and encoding conventions. Template is the fastest way to confirm whether semantic conformance holds.

Next steps

This PR is a staging artifact - happy to hold it open for @willamhou to review, comment on, or push commits into. Once the maintainer signs off on the mapping (or counter-proposes where the inference is wrong), I will merge, update IMPLEMENTATIONS.md to "Self-certified", and add a Signet entry to the draft-farley-acta-signed-receipts-02 Implementation Status appendix.

If an adapter implementation happens in parallel, that lives in its own PR.

Cc @willamhou - this is your canvas; please edit freely or tell me what I got wrong on the inferences.

Pre-fills a conformance mapping for Signet (Prismer-AI/signet) as a
template the maintainer can confirm, correct, or extend. Avoids
blocking conformance on a cold start from zero.

Populated from the public Signet source at
crates/signet-core/src/{receipt.rs, canonical.rs, sign.rs}:

- FIELD-MAPPING.md: Signet -> draft-02 field-by-field mapping with
  [CONFIRM] / [FILL] markers on each inferred entry.
- DEVIATIONS.md: four documented wire-format deltas (envelope shape,
  signature prefix, chain linkage by ID vs hash, key identifier
  format) with adapter guidance for each.
- ADAPTER.md: pseudocode sketch of a thin Signet -> draft-02 shim in
  co-signer mode, plus open questions for the maintainer.
- README.md: what is here and what the maintainer needs to do to
  turn this template into a conformance claim.

Updates IMPLEMENTATIONS.md: Signet row moves from "Under review" to
"Self-certification template staged" with a pointer to the template
directory.

Context: microsoft/agent-governance-toolkit#1201 (Tutorial 33 cross-
implementation table addition) triggered the conformance conversation
with @willamhou. The template is an artifact that lowers Signet-side
activation energy from "design a mapping from scratch" to "confirm or
correct a pre-filled mapping."
@willamhou
Copy link
Copy Markdown
Contributor

Thanks @tomjwxf — this is an extraordinary template. Resolving all markers below.

FIELD-MAPPING.md — [CONFIRM] / [FILL] Responses

action.params_hashpayload.action_refConfirmed. params_hash = "sha256:" + hex(SHA-256(JCS(params))). JCS via json_canon (RFC 8785). Direct semantic match with action_ref. Source: sign.rs:29-40.

action.target — Free-form URI, typically mcp://server-name or empty. Identifies the MCP server/endpoint. Not part of the tool name. Suggest mapping to an extension field.

action.transport — Default "stdio". Other values: "http", "sse". Free-form string, no closed enum. Maps to transport_hint with custom for non-standard values.

action.sessionYes, optional MCP session ID. Application-scoped extension, not agent_id.

action.call_idYes, optional JSON-RPC request ID. Used in bilateral co-signing to bind agent receipt to server response. Application-scoped extension.

action.response_hashOne receipt. Signet signs at call time. response_hash is optional — when present, it's SHA-256 of the tool's response in the same receipt (not a separate post-execution receipt). Superset of draft-02's pre-execution model. Exception: our LangChain callback handler emits two receipts (tool_start + tool_end), but that's application-level, not core format.

signer.pubkeysignature.kidConfirmed. Adapter computes RFC 7638 JWK thumbprint from raw Ed25519 pubkey, emits as signature.kid. Raw pubkey NOT in draft-02 envelope.

signer.owner — Optional organizational label (e.g. "acme-corp"). Metadata only, not a cryptographic identity. Multi-level authority lives in authorization (delegation chain). Mapping to holder_binding is incorrect — signer.owner is informational.

signer.namepayload.issuer_id — Acceptable with caveat: signer.name is application-assigned (e.g. "deploy-bot"), not a registered issuer. Consumers should treat as informational.

action.trace_idpayload.iteration_idConfirmed. Workflow-level correlation string. Semantically identical to iteration_id. Inside signature scope — tampering detectable.

receipt.idid = "rec_" + hex(SHA-256(sig_bytes))[..16]. Derived from the signature, NOT the hash of the canonical envelope. The adapter must compute SHA-256 of the canonical draft-02 envelope as the draft-02 identifier.

authorization — [FILL]:

pub struct Authorization {
    pub chain: Vec<DelegationToken>,  // for storage/transfer
    pub chain_hash: String,           // "sha256:<hex>" of JCS(chain)
    pub root_pubkey: String,          // must match chain[0].delegator.pubkey
}

Important: only chain_hash and root_pubkey enter the v4 signature scope (build_v4_receipt_signable). The full chain array is carried for storage but is NOT signed. Maps to holder_binding with jwk_thumbprint derived from root_pubkey. Chain is Signet-specific — carried as extension or dropped at adapt time.

Each DelegationToken also has correlation_id: Option<String> (unsigned annotation, absent from signed payloads).

policy (PolicyAttestation) — [FILL]:

pub struct PolicyAttestation {
    pub policy_hash: String,        // "sha256:<hex>" of JCS(policy)
    pub policy_name: String,        // e.g. "production-agents"
    pub matched_rules: Vec<String>, // rule names that matched
    pub decision: RuleAction,       // allow | deny | require_approval
    pub reason: String,             // human-readable
}

Mapping: policy_hashpolicy_digest, policy_namepolicy_id, decisiondecision. matched_rules + reason → suggest attestation_evidence extension.

expHard verification gate. verify() rejects expired receipts (InvalidReceipt("receipt expired at {exp}")). Separate verify_allow_expired() for forensic contexts. Verifier-behavior delta vs draft-02 (no expiration on decision receipts). Adapter should drop or carry as informational extension.

nonceFreshness token. 128-bit cryptographically random (OsRng, 16 bytes, hex, prefixed rnd_). Not a counter, not VOPRF. Inside signature scope. No direct draft-02 mapping — nullifier is semantically different. Suggest extension or omit.

Decision enum — Three values: allow, deny, require_approval. All three direct-match draft-02.

DEVIATIONS.md — Maintainer Preference

Deviation 3 (chain linkage): Option 2 — add parent_hash alongside parent_receipt_id. Additive, low-effort. Both coexist. Note: requires signer to have prior receipt's canonical bytes at sign time; signer API needs minor extension. We can ship in a point release.

ADAPTER.md — Open Questions

Q1: Feature flag. --emit-draft02 on signet sign, both envelopes per operation. Main repo, discoverable, tested.

Q2: signet-draft02-adapter crate in workspace is welcome. Timeline depends on conformance bar — we'd prioritize once field mapping is confirmed.

Q3: Operator private key accessible at adapter site. Co-signer mode is the right default.

ADAPTER.md — Correction

The pseudocode uses policy.get("id") and policy.get("digest") — these should be policy.get("policy_name") and policy.get("policy_hash") respectively, matching the PolicyAttestation struct.


Happy to push commits directly to this branch, drop fixture receipts, or iterate on any of the above. This is clean work — appreciate you reading the source.

@tomjwxf
Copy link
Copy Markdown
Contributor Author

tomjwxf commented Apr 20, 2026

Thanks @willamhou - Really appreciate the thoughtful review. The level of detail (source file references, full struct definitions, verifier-behaviour notes on exp and nonce) is beyond what my inital template deserved! Will push a commit to this branch incorporating all your answers (co-authored by you), then merge.

Specifically:
FIELD-MAPPING.md: all markers resolved per your response; signer.owner remapped to informational; exp/nonce reclassified per the Signet verifier behaviour; authorization and policy structs filled in with the Rust definitions you provided.
DEVIATIONS.md: Deviation 3 updated to reflect Signet choosing Option 2 (additive parent_hash in an upcoming point release).
ADAPTER.md: fixing the policy.get typo you caught, replacing the open questions with your answers on --emit-draft02, workspace adapter crate, and co-signer-default posture.
IMPLEMENTATIONS.md: Signet row moves from "template staged" to "Self-certified (adapter crate pending)".
Once merged, I'll add Signet to the draft-farley-acta-signed-receipts-02 Implementation Status appendix before submission to IETF datatracker this week. That puts draft-02 across the five-implementation line with genuinely external adopters.

Flagging your aeoess/agent-governance-vocabulary#37 crosswalk in the Veritas Acta tracker too, with a note.

On the Signet-side follow-ups (point release with parent_hash, --emit-draft02 flag, adapter crate): no rush from this side. Whenever you ship, we'll cross-reference. If I can help, lmk! Thanks again.

Incorporates @willamhou's review of #1,
which resolved every [CONFIRM] / [FILL] marker in the original template
with production-source-level detail (struct definitions, source-file
line references, verifier-behaviour notes on `exp` and `nonce`, and
correction of inferred mappings that did not match reality).

FIELD-MAPPING.md:
  - All markers resolved.
  - signer.owner reclassified from inferred holder_binding mapping to
    informational metadata only (confirmed by maintainer: not a
    cryptographic identity; multi-level authority lives in
    Authorization).
  - exp reclassified from "soft hint" to hard verification gate
    (verify() rejects expired; verify_allow_expired() exists for
    forensic contexts); adapter drops or carries as informational.
  - nonce reclassified from inferred nullifier mapping to 128-bit
    OsRng freshness token; not a VOPRF artifact; adapter carries as
    Signet-specific extension or omits.
  - authorization struct expanded with full Rust definition provided
    by the maintainer: chain + chain_hash + root_pubkey; only
    chain_hash and root_pubkey enter signature scope.
  - policy (PolicyAttestation) struct expanded with full Rust
    definition: policy_hash/policy_name/matched_rules/decision/reason.
    Mapping to draft-02: policy_hash → policy_digest, policy_name →
    policy_id, decision → decision; matched_rules and reason mapped
    to a suggested attestation_evidence extension.
  - Decision enum confirmed as {allow, deny, require_approval}, all
    direct-match draft-02.

DEVIATIONS.md:
  - Deviation 3 (chain linkage by ID vs hash) resolved per maintainer
    preference: Option 2 (additive parent_hash alongside
    parent_receipt_id) in an upcoming Signet point release.

ADAPTER.md:
  - Fix wrong PolicyAttestation field names in the pseudocode
    (policy_name / policy_hash, not id / digest) per maintainer
    catch.
  - Expand Authorization mapping to reflect chain_hash + root_pubkey
    as the signature-scope fields.
  - Replace "Open questions for the Signet maintainer" with the
    answered section: co-signer via `signet sign --emit-draft02`;
    in-workspace signet-draft02-adapter crate; operator key
    accessible at adapter site; co-signer mode is the default.

README.md (conformance/signet/):
  - Lead with maintainer-confirmed status.
  - List Signet-side follow-ups (parent_hash field, --emit-draft02
    flag, signet-draft02-adapter crate) in flight.
  - Cross-link maintainer's parallel crosswalk at
    aeoess/agent-governance-vocabulary#37.

IMPLEMENTATIONS.md:
  - Signet row moves from "Self-certification template staged" to
    "Self-certified (adapter crate pending)".
  - Add pointers to the agt-integration-profile review PR and the
    aeoess vocabulary crosswalk.

Co-Authored-By: Will.hou <8574759+willamhou@users.noreply.github.com>
@tomjwxf tomjwxf merged commit 55c17a0 into main Apr 20, 2026
@tomjwxf tomjwxf deleted the conformance/signet-template branch April 20, 2026 00:52
tomjwxf pushed a commit that referenced this pull request Apr 20, 2026
Formalizes the template-based self-certification pattern that landed
via Signet (PR #1): maintainers pre-fill a conformance directory with
everything inferrable from public source, the implementer confirms
markers + resolves FILL entries, merge and add to draft-02 appendix.

Intent: reduce implementer activation energy from 'design a mapping
from scratch' to 'confirm, correct, or extend a pre-filled mapping'.
The Signet self-certification demonstrated this pattern works; this
commit codifies it so the next implementer doesn't need anyone to
pre-fill their template one-off.

Covers:
- Self-certification workflow (4 steps: open issue, maintainer
  pre-fills, implementer confirms, merge + appendix entry)
- What self-certified means and doesn't mean
- Alternative contribution paths (corrections, test vectors,
  consumer-only listings)
- conformance/ directory layout with Signet as canonical example
- Commit conventions (Conventional Commits + Co-Authored-By on
  incorporated review content)
- Normative source references
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.

3 participants