# OSD 0.3.0 specification

## Overview and authority

<span id="first-release-osd-030"></span>

OSD contract set `0.3.0` is a draft. It uses ARD
v0.91 at upstream revision `aa3e598bb7752a9175897823234311216acfa864`.

The `0.3.0` JSON Schemas, release manifest, and fixtures are the normative
source for this OSD wire contract. Use its
[schemas, manifest, and fixtures](/0.3.0/specifications/contracts/) together.

<span id="authority"></span>

The authority order for `0.3.0` is:

1. The pinned ARD v0.91 specification defines inherited fields and their
   meanings.
2. The `0.3.0` OSD JSON Schemas define OSD data structures and profile rules.
3. The [endorsement matching](#endorsement-matching),
   [version negotiation](#version-negotiation), and
   [compatibility and releases](#compatibility-and-releases) sections define
   requirements not expressed in JSON Schema.

The entry, manifest, and Registry API profiles below summarize the contract set.
They do not add requirements.

## OSD entry profile

An OSD entry must satisfy the pinned ARD v0.91 `ArdEntry` schema and include:

```json
{
  "@context": {
    "osd": "https://openservicedirectory.org/ns#"
  },
  "osd:brandName": "Example Air",
  "osd:brandDomain": "airline.example"
}
```

The ARD v0.91 base context is applied by a conforming ARD consumer. The
entry-level context declares the additional OSD namespace. Brand identity terms
are top-level entry fields. The agent's native protocol defines its operations;
OSD does not define support-specific capability values.

## Brand-domain manifest

An ARD manifest requires an `entries` array containing complete entries.
Additional top-level properties are permitted. The pinned upstream
`ard-entry.schema.json` defines both `ArdEntry` and `ArdManifest`.

An OSD `0.3.0` publisher must make its static brand-domain manifest available
at:

```text
https://{osd:brandDomain}/.well-known/ard.json
```

## Endorsement matching

Each entry published on the intended brand's domain independently endorses the
resource it describes. Endorsement does not extend to other resources hosted
by the same provider or listed by the same registry.

A registry candidate has brand-domain endorsement only when its complete parsed
ARD entry structurally matches a published entry:

- Include every required and optional field, extension, nested value, and inline
  `data` value. A field present on only one side is a mismatch.
- Exclude search annotations such as `score` and `source`; those are outside the
  endorsed entry.
- Ignore object property order and insignificant JSON whitespace.
- Compare strings and URLs exactly, without URL normalization, case folding,
  fuzzy matching, or visual-similarity repair.
- Compare numbers, booleans, and null through their JSON values. Compare nested
  objects recursively.
- Treat arrays as unordered sets unless the field's owning specification gives
  order meaning. Members use structural equality; duplicates in unordered
  arrays are invalid. Compare ordered arrays position by position.
- For a `url` entry, compare the published reference. Matching does not assert
  that the fetched artifact or the agent's behavior is unchanged.

A mismatch does not establish its cause. A missing or invalid publication makes
verification inconclusive. Redirect handling does not relax comparison rules.
Matching does not verify signatures or establish business legitimacy, action
permissions, or authorization.

See the current [entry profile](/0.3.0/docs/reference/osd-profile/) and
[trust model](/0.3.0/docs/concepts/trust-model/) for examples and outcomes.

## Registry API profile

The `registry-search-request`, `registry-search-response`, and `error-response`
schemas follow the ARD v0.91 Registry REST API models. OSD search results are
stricter than ARD's partial search-result model: each result carries a complete
OSD catalog entry together with the required ARD `score` and `source` fields.

## Version negotiation

<span id="compatibility"></span>

Select the exact contract version `0.3.0` with `OSD-Accept-Contract-Version`;
successful responses declare that same version. Validate documents with the `0.3.0`
schemas.

Request one exact version with `OSD-Accept-Contract-Version`. Version ranges and
preference lists are not supported. A successful response declares exactly the
selected version in `OSD-Contract-Version`, includes
`Vary: OSD-Accept-Contract-Version`, and links the immutable release manifest
with `Link: <https://openservicedirectory.org/contracts/<version>/manifest.json>; rel="describedby"`.

A service that cannot produce the requested version returns `406 Not Acceptable`
with `UNSUPPORTED_CONTRACT_VERSION`; it must not silently substitute another
version. A registry may use a configured default when the request omits the
version header. A resolver requires an exact version header.

A resolver forwards the selected version unchanged, accepts only successful
upstream responses that declare that exact version, and never mixes versions or
translates between them. It returns the selected version, includes it in cache
keys, and binds pagination tokens to it. If all queried registries explicitly
reject the version, it returns `406`. Transport failures, timeouts, and malformed
or mismatched responses are not version rejections. This release does not define
the resolver's aggregation envelope or partial-result reporting.

Implementations document supported contract versions. Before OSD `1.0.0`, an
implementation is not required to support multiple versions at one endpoint.
Static brand manifests follow their release's ARD baseline rather than these
HTTP negotiation headers.

## Compatibility and releases

An OSD contract set is versioned as one release. Bindings and implementation
packages have independent versions and identify the exact contract set they use.
Each release manifest pins both the upstream ARD version and its exact revision.

Before `1.0.0`, breaking changes increment `y` in `0.y.z`; compatible changes
increment `z`. From `1.0.0`, breaking changes increment the major version,
compatible features the minor version, and compatible corrections the patch
version. Prereleases are not stable compatibility targets.

Compatibility covers both newer consumers reading older documents and older
consumers reading newer documents, unless a release explicitly declares a
narrower guarantee. A change is breaking when a previously conformant producer
or consumer could fail validation, misinterpret a field, or change required
behavior. Treat uncertain compatibility as breaking until demonstrated otherwise.

Adding an optional field to a closed object can break existing validators.
Changes to required fields, types, accepted values, meanings, defaults,
identifiers, reference targets, ordering, pagination, or error behavior can also
be breaking. Deprecation does not permit removal within the same stable major
version; removal follows the breaking-version rules.

OSD-owned objects are closed unless a schema explicitly defines an extension
point. ARD-owned objects retain their pinned baseline's extension rules.
Extension points identify namespace ownership and how unknown keys are handled,
and must not change standard field meanings.

Published schema IDs identify immutable content. Corrections require a new
contract version and ID. Resolve references within the selected contract set;
do not depend on moving `latest` aliases. Schema validation and fixture checks
establish structural consistency; behavioral compatibility also requires review.

## Release artifacts

The contract set contains:

- the immutable `0.3.0` `ard-entry` schema vendored from the pinned ARD v0.91
  revision, with an OSD-owned immutable schema ID;
- OSD `ard-manifest`, catalog-entry, registry search, error, and contract
  manifest schemas;
- a `0.3.0` release manifest; and
- valid and invalid `0.3.0` fixtures.

The fixture index identifies the schema and expected validation result for each
fixture. A validator must accept the valid fixtures and reject the invalid fixtures
against their indexed versioned schemas.

Download the [schemas and release artifacts](/0.3.0/specifications/contracts/).