Skip to main content

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.

VersionReleasedStatusSunset
2026-04-112026-04-11Latest, 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:

RuleValue
inputContext.maxPromptLength50,000 chars
inputContext.maxSystemPromptLength50,000 chars
inputContext.maxContextBytes100 KiB
inputContext.maxConversationIdLength256 chars
outputDecision.maxActionObjectBytes10 KiB
outputDecision.maxRationaleLength50,000 chars
outputDecision.maxAlternatives10
outputDecision.maxToolCalls50

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:

  1. The version's registry entry flips deprecated: true and gets a sunsetDate set 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.
  2. Every response served under the deprecated version carries advisory headers: a Deprecation: true flag, a Sunset: <date> target, and a Link: <migration-guide> pointer.
  3. 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:

  1. Pin the schema version explicitly — set X-Adjudon-Version: 2026-04-11 in the SDK config rather than letting the header default to latest. Pinning makes the wire contract part of the integration's commit history.
  2. Subscribe to the changelog — the public RSS feed at /changelog/rss.xml is the single source of truth for incoming deprecations.
  3. Watch the Deprecation header — an SDK should log the header on the first response of every cold start. A sudden Deprecation: true is the earliest signal that a sunset is approaching.
  4. 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 surfaceWhat this concept satisfies
EU AI Act Art. 12Logging stability — the schemaVersion field on every trace is what makes a five-year-old log resolvable to its original shape
ISO 42001 § 8.4Operational 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 schemaVersion field this concept describes
  • Error Codes — where VERSION_SUNSET lives in the broader taxonomy