# Versioning and compatibility ## The scheme UHP versions are dates — `YYYY-MM-DD`, the day the version was published. `2026-10-19` is the current version; `2026-10-04`, `2026-09-28`, `2026-09-12` and `2026-08-11` remain published and served. Dates were chosen over semantic versioning deliberately. SemVer's promise is that a major bump means "expect breakage" and a minor bump means "safe" — a promise that is only as good as the discipline of whoever assigns the numbers, and one that is routinely broken in practice. A date claims nothing it cannot keep. It says when the version was published, it sorts, and it makes an implementation's age obvious at a glance. ## What may change within a version A published version is **immutable in structure**. Within a version, a server MAY: - add optional request fields; - add fields to response objects; - add new event types; - add new error codes with a vendor prefix; - relax a constraint (accept input it previously rejected). A server MUST NOT, within a version: - remove or rename a field; - change the type or meaning of a field; - add a required request field; - remove an event type or error code; - tighten a constraint (reject input it previously accepted). Anything in the second list requires a new version. ## Client rules A conformant client MUST: 1. **Ignore unknown fields.** Not warn, not error — ignore. 2. **Ignore unknown event types.** Skip and continue reading the stream. 3. **Ignore unknown output item types.** Render what it understands. 4. **Treat unknown error codes as their `type`.** An unrecognised `code` with `type: "server_error"` is still retryable. A client that follows these four rules keeps working across every additive change within a version, which is the entire point of writing them down. ## Server rules A server MUST: 1. Report the version it served in the `UHP-Version` response header. 2. Reject an unsupported requested version with `unsupported_protocol_version` rather than serving a different one. 3. Support at least one full version at a time, and SHOULD support the previous version for at least six months after a new one is published. When the newer version is additive, as `2026-10-04` is to `2026-09-28`, that one to `2026-09-12` and that one to `2026-08-11`, all are served from one code path: the same objects answer either request, and the only difference a client sees is the version echoed in the header. `2026-10-19` is additive to `2026-10-04` except in one rule, which the known compromises below describe. ## Deprecation A field or endpoint is deprecated by: 1. marking it deprecated in the specification and the OpenAPI document, with the reason and the replacement; 2. keeping it working for at least two published versions; 3. removing it no earlier than the second version after the announcement. Nothing is removed without a working replacement having existed first. ## The current version's known compromises Recorded here because a specification that hides its own rough edges cannot be trusted about the smooth ones. - **Mixed field casing.** The task surface is `snake_case`; the harness object is `camelCase`. Both are load-bearing in shipped clients. A future major version should unify them. - **Session deletion also lives at `/v1/traces/{id}`.** The path predates the session vocabulary. The protocol now names `DELETE /v1/sessions/{id}` and keeps the old path as an alias rather than renaming it, because renaming would break existing clients for a cosmetic gain. A future major version may retire the old path through the process above. - **Harness writes refuse what they cannot store.** Since 2026-10-10 both maintained servers refuse a harness create or update that carries a field the harness does not have (`422`, naming the field and the nearest one it does have), or a `default_model` its base does not run (`422`, `model_not_available`). Both are tightenings the rules above reserve for a new version. They were made inside `2026-10-04` because the input they refuse was being stored as nothing behind a `200`, and a harness on a model no base runs refused every task given to it; a client, and above all an agent driving the API, had no way to learn why. What the harness object comes back with and cannot be written (`id`, `object`, `createdAt` and the server's own read-only fields) is still accepted and ignored, so a harness read and sent back saves. `2026-10-19` states both rules in [Harnesses §5.1](versions/2026-10-19/harnesses.md#51-create). - **Retiring a harness under an earlier version.** `2026-10-19` lets a server that reports `harness_retirement` retire a harness's sessions with it, restorable for a window it states and removed after it ([Harnesses §5.3](versions/2026-10-19/harnesses.md#53-delete)). Every earlier version says a server MUST NOT delete them. A server that retires sessions this way and also serves an earlier version from one code path departs from that version's §5.3 for those requests; a client that depends on a retired harness's history reads `harness_retirement` from discovery, which a server reports whatever version the request names.