Versioning & the Changelog
Adjudon ships breaking changes by adding a new version, never by
mutating the old one. There are two independent versioning axes
running on the API today: the URL axis (/api/v1/* vs the
legacy /api/* prefix) and the schema axis (the date-stamped
X-Adjudon-Version header that identifies the exact wire contract
a request is asking for). They are deliberately separate. URL
versions move once a decade; schema versions move whenever the
DecisionTrace shape gets a new required field.
This page explains both axes, the deprecation envelope each one carries, and the timeline a customer can plan against. The visible changelog lives at /changelog; the contract for clients is here.
The URL axis: /api/v1/*
Every public endpoint mounts at /api/v1/<resource>. The
apiVersionMiddleware adds an X-Adjudon-API-Version: v1 header
to every response so an SDK can confirm which mount it reached.
Legacy unversioned mounts at /api/<resource> are still wired and
return identical payloads, but with three RFC 8594 headers
attached:
HTTP/1.1 200 OK
Deprecation: true
Sunset: 2027-04-12
Link: <https://docs.adjudon.com/migration/api-v1>; rel="deprecation"
The Sunset date is 2027-04-12 — twelve months after the
versioned mount went live (backend/middleware/deprecationMiddleware.js:8).
After that date, the legacy /api/* routes return 410 Gone. Until
then they are functionally equivalent to /api/v1/* and the
deprecation is purely advisory.
The next URL version — /api/v2/* — will land only
when the API needs a backwards-incompatible change that cannot be
expressed via the schema axis. As a contract, expect the v1 mount
to live for at least three years from its public-availability
date and to overlap with v2 by twelve months.
The schema axis: X-Adjudon-Version: YYYY-MM-DD
Inside /api/v1/*, the wire-shape contract evolves on a separate
axis. Stripe-style date-stamped versions identify the exact
DecisionTrace schema, validation rules, and SDK contract a
request expects. Clients opt in by setting the header:
POST /api/v1/traces
X-Adjudon-Version: 2026-04-11
A request without the header falls through to the registry's
LATEST_VERSION constant. The current latest is 2026-04-11
(backend/utils/schemaVersions.js:18). The frozen registry today
contains exactly one entry; the deliberate posture is to add
new versions only when a change is actually breaking, not on a
calendar.
| Version | Released | Status | Sunset |
|---|---|---|---|
2026-04-11 | 2026-04-11 | Latest, recommended | — |
Every trace persisted in MongoDB carries the schemaVersion field
that was active at ingestion time. A regulator reading a five-year-
old trace can resolve its shape exactly because the wire version is
embedded in the row.
Validation rules per schema version
The schema version also carries the validation envelope. The
2026-04-11 version sets:
| Rule | Value |
|---|---|
inputContext.maxPromptLength | 50,000 chars |
inputContext.maxSystemPromptLength | 50,000 chars |
inputContext.maxContextBytes | 100 KiB |
inputContext.maxConversationIdLength | 256 chars |
outputDecision.maxActionObjectBytes | 10 KiB |
outputDecision.maxRationaleLength | 50,000 chars |
outputDecision.maxAlternatives | 10 |
outputDecision.maxToolCalls | 50 |
A future schema version that loosens or tightens any of these limits is a new version — an existing trace ingested under the old envelope keeps its old guarantees forever.
How a deprecation actually works
When a schema version is marked deprecated, three things happen at once:
- The version's registry entry flips
deprecated: trueand gets asunsetDateset to today + 90 days minimum. This is the floor; in practice we publish a longer window for major versions and a shorter one for hot security fixes. - Every response served under the deprecated version carries
advisory headers: a
Deprecation: trueflag, aSunset: <date>target, and aLink: <migration-guide>pointer. - The Changelog entry lands the same day, with the migration guide live before the headers go on.
After the sunset date, the deprecated version returns 410 Gone
with code: 'VERSION_SUNSET' and the Link header pointing to
the migration guide. There is no silent reroute — a request
that asked for a sunset version learns explicitly. The API never
quietly substitutes a different version's contract for a request
that asked for an exact one.
What this is NOT
- Not semver. Adjudon does not ship
1.2.3-style versions on the API. Date-stamped versions are unambiguous on which contract a request is asking for; semver requires a translation layer (which minor incremented when?) that adds nothing for an HTTP contract. - Not auto-rolling. A request without the header gets the latest version, but the latest version does not change behind the customer's back — it changes on a published deploy with a Changelog entry and a header-flip on the new version.
- Not the SDK version. Each Adjudon SDK has its own semver
release cadence (
@adjudon/[email protected],[email protected]for Python, etc.). The SDK version is the package version; the schema version is what the SDK sends on the wire. They move on different clocks. - Not a billing-plan dimension. Schema versions are not gated by plan. Sandbox and Custom orgs run the same schema registry. Plans gate features (see plans-and-features); versions gate wire shapes.
- Not infinite backwards-compatibility. The 90-day floor on a deprecated version is the minimum migration window, not a perpetual support tier. After the sunset date, the contract is gone; a customer who needs an extension talks to support before the date.
How to plan against the contract
A customer integrating today should:
- Pin the schema version explicitly — set
X-Adjudon-Version: 2026-04-11in the SDK config rather than letting the header default to latest. Pinning makes the wire contract part of the integration's commit history. - Subscribe to the changelog — the public RSS feed at
/changelog/rss.xmlis the single source of truth for incoming deprecations. - Watch the Deprecation header — an SDK should log the
header on the first response of every cold start. A sudden
Deprecation: trueis the earliest signal that a sunset is approaching. - Plan the migration inside the 90-day floor — the minimum window is 90 days from sunset announcement; major versions are typically longer. Treat the 90-day number as the commit deadline for testing the new version, not the start of it.
Regulator mapping
| Regulator surface | What this concept satisfies |
|---|---|
| EU AI Act Art. 12 | Logging stability — the schemaVersion field on every trace is what makes a five-year-old log resolvable to its original shape |
| ISO 42001 § 8.4 | Operational planning & control — documented version contract is part of the documented operational control |
| GDPR Art. 5(1)(d) | Accuracy principle — pinned versions prevent silent contract drift that would corrupt the audit record |
See also
- Changelog — the authoritative timeline of what shipped when
- Plans & Features — the per-plan feature contract this versioning protects
- Idempotency — another contract that survives across versions
- POST /traces — the endpoint
whose
schemaVersionfield this concept describes - Error Codes — where
VERSION_SUNSETlives in the broader taxonomy