Skip to content

fix: make the Trust Manifest MUST rules satisfiable by the spec's own examples - #81

Open
liady wants to merge 1 commit into
Agent-Card:mainfrom
liady:fix/trust-manifest-must-rules
Open

fix: make the Trust Manifest MUST rules satisfiable by the spec's own examples#81
liady wants to merge 1 commit into
Agent-Card:mainfrom
liady:fix/trust-manifest-must-rules

Conversation

@liady

@liady liady commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #70.

Two normative MUSTs could not be satisfied by the Claude Plugins appendix examples:

  1. The identity binding rule assumed every identifier has a publisher domain segment, but identifier is an open format and the appendix uses urn:claude-plugin:... identifiers with no domain at all. A consumer following the rule as written would have to reject the Trust Manifests in the spec's own examples. The rule is now scoped to identifiers that carry a publisher domain segment (such as the urn:air form), with a fallback to other verification (attestations, signatures) for formats that don't.

  2. Digest Format requires consumers to reject digests weaker than SHA-256, yet the appendix mapped the marketplace's git commit sha to sourceDigest as sha1:.... A commit SHA is a revision identifier, not a content digest of anything a consumer can fetch and hash, so the mapping now lands it in entry metadata.sourceSha instead, and the examples no longer carry sourceDigest values that consumers are required to reject.

A dedicated sourceRevision field on the Provenance Link (as floated in the issue) would be a schema addition and would need its own ADR, so it is intentionally out of scope here.

Comment thread specification/ai-catalog.md
@olijboyd

Copy link
Copy Markdown

Reviewed this against the current head while bringing our verifier back into line with it. Two notes from the implementation side.

The sourceSha relocation lands on metadata, which the schema no longer defines.

ADR-0017 (#77, merged 30 July) moved custom data into the extensions map. The CDDL now carries ? extensions: { * text => any } on AICatalog, CatalogEntry and TrustManifest, and there is no metadata member in the schema at all. The only surviving field references in the normative document are four in the Claude Code Plugins Marketplace appendix: Catalog metadata.description, Entry metadata.homepage, and the metadata object in both worked examples. This PR adds metadata.sourceSha to the mapping table and to both of those examples, so it grows the count rather than clearing it.

Given that #70's whole point is that the appendix examples must be satisfiable by the normative text, the relocation probably wants to be:

"extensions": {
  "https://ai-catalog.org/extensions/metadata": {
    "homepage": "https://www.adspirer.com",
    "sourceSha": "aa70dbdbbbb843e94a794c10c2b13f5dd66b5e40"
  }
}

which also gives the existing homepage and description rows somewhere conformant to point at. The wider version of this is not yours to fix in this PR, so I have raised it separately in #103.

The identity scoping clause still needs a stated extraction rule.

Agreed with @rrrodzilla that the scoped MUST leaves a consumer without a defined test. Two things become undefined once "carries a publisher domain segment" is the trigger: how to extract that segment from identifier, and how to derive the trust domain from the identity URI. Two implementations must answer both identically or the MUST is not interoperable.

This is what we settled on in our verifier, offered as a starting point rather than a proposal:

  • Publisher segment: only urn:air:<publisher>:... is treated as carrying one. Everything else takes the "does not apply" branch. That makes the trigger a positive test against a named format rather than a guess at whether a string looks domain-shaped, which matters because the guess is the thing that would differ between implementations.
  • Identity domain: did:web yields the first colon-separated element with %3A decoded and the port retained, since the port is part of the origin a resolver contacts. https and spiffe yield host plus port. Every other scheme, dns: included, is rejected rather than parsed, because its authority is ambiguous and a permissive reading would name an authority the URI does not control.

The port is the detail that caught us. A port-bearing did:web must not align with the bare apex domain, and it does if you normalise the port away.

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.

Trust Manifest MUST rules cannot be satisfied by open identifier formats or the spec's own appendix examples

3 participants