diff --git a/adr/0016-displayname-optional.md b/adr/0016-displayname-optional.md index 282372c..b9db59a 100644 --- a/adr/0016-displayname-optional.md +++ b/adr/0016-displayname-optional.md @@ -1,10 +1,10 @@ # ADR-0016: displayName Is Optional on a Catalog Entry ## Status -Proposed +Accepted ## Date -2026-06-18 (Proposed) +2026-06-18 ## Context A Catalog Entry is a thin pointer: it carries an `identifier`, a `mediaType`, and exactly one of `url` or `data` locating the full artifact. `displayName` (a human-readable name for the artifact) is a REQUIRED member of every Catalog Entry, and is listed among the required-at-minimum members of a Minimal Catalog (Level 1). @@ -42,4 +42,4 @@ This decision concerns only the Catalog Entry. `displayName` on `HostInfo` and ` An MCP Server Card's `title` is itself OPTIONAL. The guidance above is keyed on whether the artifact *carries a canonical name*, not on its media type: if a referenced Server Card omits `title`, the entry SHOULD keep `displayName` so the artifact is not left with only a reverse-DNS identifier and a prose description. ## Meeting Reference -Slated for discussion at the 2026-06-18 AI Catalog bi-weekly working-group call; this ADR records the proposal ahead of that discussion. Update the Status and Date (and note who raised concerns and the agreed outcome, as in ADR-0011) once the working group ratifies it. +Ratified at the 2026-06-18 AI Catalog bi-weekly working-group call: `displayName` was made OPTIONAL on the Catalog Entry as proposed. Removing the field entirely was considered and rejected so that opaque, self-nameless artifacts retain a place for a human-readable name. diff --git a/adr/0018-entry-field-authoritative-source-parity.md b/adr/0018-entry-field-authoritative-source-parity.md new file mode 100644 index 0000000..77f3cc0 --- /dev/null +++ b/adr/0018-entry-field-authoritative-source-parity.md @@ -0,0 +1,71 @@ +# ADR-0018: `description` and `version` Follow `displayName`'s Authoritative-Source Rule + +## Status +Proposed + +## Date +2026-07-02 (Proposed) + +## Context +[ADR-0016](0016-displayname-optional.md) made the Catalog Entry `displayName` OPTIONAL and gave it a precise "authoritative-source" rule: a publisher SHOULD set `displayName` only when the referenced artifact does not already carry its own canonical human-readable name; when the artifact does carry one (an A2A Agent Card `name`, an MCP Server Card `title`), that artifact is the authoritative source and `displayName` SHOULD be omitted to avoid a value that drifts out of sync; and when `displayName` *is* present it takes precedence for display. A companion [Resolving an Artifact's Display Name](../specification/ai-catalog.md#resolving-an-artifacts-display-name) section defines the consumer resolution order. + +`displayName` is not the only Catalog Entry member that can restate a value the referenced artifact already carries. Two others do, and today they are documented as plain optional fields with no equivalent guidance: + +- **`description`** — a short prose description of the artifact. An **A2A Agent Card carries a REQUIRED `description`**, and an **MCP Server Card carries a `description`** (optional in [SEP-2127](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2127), where only `name` and `version` are required). When the referenced artifact does carry a description, an entry that copies it restates a value that lives, canonically, in the document the consumer is about to fetch. +- **`version`** — the artifact's version. An **A2A Agent Card carries a REQUIRED `version`**, an **MCP Server Card carries a `version`**, and an MCP Registry `server.json` carries a `version`. + +This is incoherent at the field-definition level: the `displayName` field description tells a publisher to omit it when the Server Card already carries a `title`, while the `description` and `version` field descriptions — which have the *same* duplication-and-drift problem against the *same* Server Card — give no such steer. (The MCP mapping appendix already applies the omit-to-avoid-drift rule to `description` and `version` as part of the Server Card mapping, which makes the gap in the field descriptions themselves the remaining inconsistency.) A publisher reading the field list has no reason to treat them differently, so entries end up carrying a copied `description`/`version` that silently drifts from the artifact. + +Not every Catalog Entry member has this problem, and the rule should be applied only where it holds (see [Scope](#scope-fields-in-and-out) below). + +## Decision +Extend the `displayName` authoritative-source rule (ADR-0016) to the other Catalog Entry members that duplicate a value the referenced artifact carries canonically: **`description`** and **`version`**. + +**`description`.** A publisher SHOULD set entry `description` only when the referenced artifact does not already carry its own canonical description. When the artifact does carry one (an A2A Agent Card `description`, an MCP Server Card `description`), that artifact is the authoritative source and entry `description` SHOULD be omitted to avoid duplicating a value that can drift out of sync. When entry `description` *is* present it takes precedence for display: a consumer SHOULD render it as given even when it differs from the artifact's description — this is how a publisher deliberately provides a listing-specific blurb. A new "Resolving an Artifact's Description" section records the consumer resolution order, mirroring "Resolving an Artifact's Display Name". + +**`version`.** A publisher SHOULD set entry `version` only when the referenced artifact does not carry its own version, **or** when the entry participates in a multi-version listing. `version` differs from `displayName`/`description` in that it is not merely cosmetic: the combination of `identifier` + `version` is the uniqueness key for [Multi-Version Entries](../specification/ai-catalog.md#multi-version-entries), and consumers sort on it to select the latest. Two consequences follow: + +1. When a single entry references an artifact that carries its own version, entry `version` merely restates that value and SHOULD be omitted to avoid drift — the consumer can read the version from the artifact. +2. When a catalog lists multiple versions of the same `identifier`, each such entry needs a distinct `version` to be uniquely addressable (it is what makes `identifier` + `version` the uniqueness key; see [Multi-Version Entries](../specification/ai-catalog.md#multi-version-entries)), so `version` is required there — it is doing structural disambiguation, not display. + +Unlike `displayName`/`description`, a present entry `version` is **not** an authorial override of the artifact's value: it is used for sorting and version selection, so it SHOULD equal the version the referenced artifact reports. An entry `version` that contradicts the artifact's own version is a publishing error (it breaks latest-selection), not a deliberate override. Consumers MAY surface such a mismatch but SHOULD treat the entry `version`, when present, as authoritative for catalog-level sorting and selection. A new "Resolving an Artifact's Version" section records the consumer resolution order, adapted for these sorting/selection semantics. + +This decision concerns only Catalog Entry members. It does not change `displayName` on `HostInfo` / `Publisher`, nor any Trust Manifest field. + +## Scope: fields in and out +In scope (duplicate an artifact's canonical value): + +- `displayName` — already covered by ADR-0016 (A2A Agent Card `name`, MCP Server Card `title`). +- `description` — A2A Agent Card `description`, MCP Server Card `description`. +- `version` — A2A Agent Card `version`, MCP Server Card `version`, MCP Registry `server.json` `version`. + +Deliberately out of scope (no canonical artifact counterpart, or catalog-owned by design): + +- `tags` — a discovery aid the catalog author curates for cross-artifact filtering. Card formats do not expose a canonical top-level tag list (A2A tags live per-skill), so there is nothing authoritative to defer to. +- `updatedAt` — records when the *entry* changed; it describes the catalog record, not a value the artifact carries. +- `publisher`, `trustManifest` — the catalog's deliberate value-add (publisher identity and trust), explicitly the information the referenced artifact formats *lack*; the catalog is the authoritative home, so there is nothing to omit. (A2A's `provider` overlaps loosely with `publisher`, but publisher identity is the catalog's trust anchor by design and is intentionally owned here.) +- `metadata` — the open extension point, already governed by the specification's Metadata Extensibility rules, which themselves say to avoid keys that duplicate defined fields. +- `identifier`, `type`, `url` / `data` — required structural fields, not duplicated human-readable values. + +## Rationale +- **Consistency.** The same duplication-and-drift argument that made `displayName` optional applies verbatim to `description` and `version`; treating them differently is an inconsistency publishers will trip over. +- **Single authoritative source.** Keeping the value at its source (the referenced card) keeps it fresh and avoids the "two conflicting values, no principled tiebreak" failure mode. +- **Thin entry.** Reinforces the entry-as-thin-pointer posture ([ADR-0013](0013-authoring-vs-distribution-formats.md)): an entry adds the discovery/trust metadata the artifact lacks, rather than mirroring what it already has. +- **Field-appropriate nuance.** `description` is prose and behaves exactly like `displayName` (a present value is a deliberate override). `version` carries structural meaning (uniqueness + sorting), so the rule is adapted: omit the redundant single-entry case, keep it required for multi-version listings, and treat a present value as sort-authoritative rather than a free-form override. + +## Consequences +- The spec's `description` and `version` field descriptions gain the SHOULD-omit-when-authoritative / present-takes-precedence language, and "Resolving an Artifact's Description" and "Resolving an Artifact's Version" sections are added next to the display-name one. The `version` resolution section adapts the pattern to `version`'s structural role: the entry value is authoritative for sorting and selection (not a display override), a single entry that omits `version` resolves it from the referenced artifact, and an entry that carries no version at all falls back to `updatedAt`. The MCP mapping-appendix rows for `description` and `version` already carry the equivalent guidance (from the Server Card mapping); the Claude Plugins mapping-appendix `description` row is aligned to match, and the Claude Plugins example entries drop the now-redundant `description` accordingly (the nested-catalog entry keeps it, since a catalog artifact carries no canonical description of its own). +- No schema change: `description` and `version` are already OPTIONAL in the CDDL, so this ADR is guidance only and is not a breaking change. +- Existing catalogs that populate `description` / `version` on every entry remain conformant; the guidance is a SHOULD, and any publisher that wants a self-describing list view may still populate them. +- Consumers gain a defined resolution order for `description` and `version`, matching the one they already implement for `displayName`. + +## Alternatives Considered +- **Leave `description` / `version` as plain optional fields.** Rejected: it is the status quo that motivated this ADR — the guidance gap is exactly the inconsistency being closed. +- **Apply the identical "present takes precedence as a deliberate override" wording to `version`.** Rejected: a `version` that contradicts the artifact would break Multi-Version selection; version needs the sort-authoritative-but-SHOULD-match framing instead. +- **Generalize into one rule over an open set of "duplicating fields."** Rejected for now as over-abstraction; the concrete set is small (`displayName`, `description`, `version`) and each has enough field-specific nuance to warrant explicit treatment. A future field that duplicates an artifact value should follow this same pattern. + +## Open Question +As with ADR-0016's note that a Server Card `title` is itself optional: the guidance keys on whether the artifact *actually carries* the value, not on its media type. If a referenced artifact omits its own `description` (or `version`), the entry SHOULD keep the field so the value is not lost. + +## Meeting Reference +Records a proposal ahead of an AI Catalog bi-weekly working-group discussion; drafted as a follow-up to [ADR-0016](0016-displayname-optional.md). Update the Status and Date (and note who raised concerns and the agreed outcome, as in ADR-0011) once the working group ratifies it. diff --git a/specification/ai-catalog.md b/specification/ai-catalog.md index 88ac5d0..81d2245 100644 --- a/specification/ai-catalog.md +++ b/specification/ai-catalog.md @@ -259,7 +259,19 @@ The following members are OPTIONAL: for the full consumer resolution order. `description` -: A string containing a short description of the artifact. +: A string containing a short description of the artifact. Like + `displayName`, `description` is OPTIONAL and follows the same + authoritative-source rule: when the referenced artifact carries its + own canonical description — for example the `description` field of an + A2A Agent Card or an MCP Server Card — that artifact is the + authoritative source and entry `description` SHOULD be omitted to + avoid duplicating a value that can drift out of sync. When entry + `description` *is* present, however, it takes precedence: a consumer + SHOULD render it as given even when it differs from a description + carried by the referenced artifact, which is how a publisher provides + a listing-specific blurb. See + [Resolving an Artifact's Description](#resolving-an-artifact-s-description) + for the full consumer resolution order. `tags` : An array of strings serving as keywords for filtering and discovery. @@ -270,6 +282,23 @@ The following members are OPTIONAL: required. See [Multi-Version Entries](#multi-version-entries) for how versions interact with `identifier`. + Like `displayName` and `description`, `version` can restate a value + the referenced artifact already carries (an A2A Agent Card + `version`, an MCP Server Card `version`), and when a single entry + references such an artifact the entry `version` SHOULD be omitted to + avoid drift — the consumer can read it from the artifact. Unlike + `displayName` and `description`, however, `version` is not merely + cosmetic: it is part of the entry's uniqueness key, so it is + REQUIRED when a catalog lists multiple versions of the same + `identifier` (see [Multi-Version Entries](#multi-version-entries)). + A present `version` is used for catalog-level sorting and selection + rather than as a free-form display override, so it SHOULD equal the + version the referenced artifact reports; an entry `version` that + contradicts the artifact's own version is a publishing error, not a + deliberate override. See + [Resolving an Artifact's Version](#resolving-an-artifact-s-version) + for the full consumer resolution order. + `updatedAt` : A string containing an ISO 8601 [[RFC3339]] timestamp indicating when this entry was last modified. @@ -318,6 +347,64 @@ the `identifier` segment in step 3. A publisher MAY still set `displayName` on such an entry to provide a better name than the bare identifier segment. +### Resolving an Artifact's Description + +Because `description` is OPTIONAL, a consumer that wants to show a +description cannot assume the entry carries one. It SHOULD resolve one in +the following order: + +1. **`description` on the entry**, if present. A publisher-supplied + `description` always wins, even when it differs from a description + carried by the referenced artifact. +2. **The referenced artifact's own canonical description**, if the + consumer has already fetched or cached the artifact — for example the + `description` field of an A2A Agent Card or an MCP Server Card. +3. **No description**, if neither is available. Unlike a name, a + description has no identifier-derived fallback; a consumer SHOULD + simply render the entry without one. + +As with name resolution, a consumer SHOULD NOT dereference an artifact at +render time solely to obtain a description. A registry, directory, or +other service built on top of a catalog SHOULD resolve the description +once at ingestion and cache the result, rather than fetching artifacts on +the rendering path. + +### Resolving an Artifact's Version + +Because `version` is OPTIONAL on a single entry — and present only when +the entry disambiguates others that share its `identifier` (see +[Multi-Version Entries](#multi-version-entries)) or deliberately restates +the artifact's version — a consumer cannot assume every entry carries +one. To obtain a version, a consumer SHOULD resolve one in the following +order: + +1. **`version` on the entry**, if present. Unlike `displayName` and + `description`, a present `version` is not a free-form display + override: it is authoritative for catalog-level sorting and version + selection. Within a multi-version listing it is REQUIRED and, combined + with `identifier`, uniquely addresses the entry. +2. **The referenced artifact's own version**, if the consumer has already + fetched or cached the artifact — for example the `version` field of an + A2A Agent Card, an MCP Server Card, or an MCP Registry `server.json`. + A single entry that omits `version` because the artifact already + carries it is resolved here. +3. **No version**, if neither is available — the entry represents an + unversioned artifact. A consumer that needs to order such entries + SHOULD fall back to `updatedAt`, consistent with + [Multi-Version Entries](#multi-version-entries). + +When both the entry and the referenced artifact carry a `version` and +they disagree, the entry `version` is authoritative for catalog-level +sorting and selection; the mismatch is a publishing error (it breaks +latest-selection) that a consumer MAY surface but SHOULD NOT resolve by +silently preferring the artifact's value. + +As with name and description resolution, a consumer SHOULD NOT dereference +an artifact at render time solely to obtain a version. A registry, +directory, or other service built on top of a catalog SHOULD resolve the +version once at ingestion and cache the result, rather than fetching +artifacts on the rendering path. + ## Multi-Version Entries A catalog MAY contain multiple entries with the same `identifier` and @@ -1973,7 +2060,7 @@ plugins/ | Marketplace `owner` | Catalog `host` (with `identifier` derived from owner) | | `plugins[]` array | Catalog `entries[]` array | | Plugin `name` | Entry `identifier` (derived as URN); the plugin manifest carries its own name, so entry `displayName` is omitted | -| Plugin `description` | Entry `description` | +| Plugin `description` | Stays in the plugin manifest (which carries its own `description`); entry `description` is omitted to avoid duplicating a value that can drift | | Plugin `category` | Entry `tags[]` (first tag) | | Plugin `tags` | Entry `tags[]` (merged with category) | | Plugin `author` | Entry `publisher` | @@ -2022,7 +2109,6 @@ maps to an AI Catalog where each plugin is an entry: "identifier": "urn:claude-plugin:anthropic:agent-sdk-dev", "type": "application/vnd.anthropic.claude-plugin+json", "url": "https://github.com/anthropics/claude-plugins-official/tree/main/plugins/agent-sdk-dev", - "description": "Development kit for working with the Claude Agent SDK", "tags": ["development"], "publisher": { "identifier": "did:web:anthropic.com", @@ -2036,7 +2122,6 @@ maps to an AI Catalog where each plugin is an entry: "identifier": "urn:claude-plugin:adspirer:ads-agent", "type": "application/vnd.anthropic.claude-plugin+json", "url": "https://github.com/amekala/adspirer-mcp-plugin.git", - "description": "Cross-platform ad management for Google Ads, Meta Ads, TikTok Ads, and LinkedIn Ads.", "tags": ["productivity", "ads"], "metadata": { "homepage": "https://www.adspirer.com" @@ -2056,7 +2141,6 @@ maps to an AI Catalog where each plugin is an entry: "identifier": "urn:claude-plugin:aikido:security", "type": "application/vnd.anthropic.claude-plugin+json", "url": "https://github.com/AikidoSec/aikido-claude-plugin.git", - "description": "Aikido Security scanning — SAST, secrets, and IaC vulnerability detection.", "tags": ["security"], "publisher": { "identifier": "did:web:aikido.dev",