---
type: Axis
title: api-evolution (contract-evolution axis)
description: The API/contract-evolution architecture axis — how the system's external contract is allowed to change (unversioned → versioned → negotiated → compatibility-guaranteed). A system-singleton axis whose commitment surface is the interface/wire contract; worked example is the skill⇄MCP semver coupling.
tags: [axis, architecture, api-evolution, versioning, contract, semver, rfc-75, deep]
timestamp: 2026-06-18T00:00:00Z
---

# API-evolution (contract-evolution axis)

> **DEEP axis (5A.2).** Full §6 depth with a worked example from the skill's own
> history — the skill-prose ⇄ MCP-server semver coupling + check_skill_version.

## Concept

API-evolution is the **contract-evolution** axis (RFC #75 §3): how the
system's external contract (its API / wire shape) is allowed to change without
breaking consumers. The ladder runs unversioned (change at will; consumers
break) → versioned (a version label distinguishes contracts; consumers pin) →
negotiated (client + server agree a mutually-supported version at connect) →
compatibility-guaranteed (changes are constrained to be backward/forward
compatible; old clients keep working). Its **commitment surface is the
interface/wire contract** (§4): the contract is the thing being evolved, and a
break ripples to every consumer. Its **scope is system-singleton** (§5).

## Why it is an axis (discriminator test — §2)

1. **Ordered tiers** — each rung gives consumers a stronger non-breakage
   guarantee across change.
2. **Cross-cutting bundle** — a rung dictates the version label, the negotiation
   handshake, the compatibility policy, the deprecation process, and the
   contract tests.
3. **Asymmetric migration cost** — once consumers depend on an unversioned
   contract, introducing versioning means a coordinated cutover; promising
   compatibility means never breaking the shapes already shipped.
4. **Requirement-keyed selection** — falsifiable probes pick the rung.

## Schema view (the §6 entry — validated by `axis_catalog`)

```yaml
id: api-evolution
kind: architecture-axis
scope: system-singleton
selection:
  probes:
    - "Do you control every consumer + deploy them together? → unversioned may be acceptable."
    - "Do consumers deploy independently of the server? → versioned (they pin a version)."
    - "Do client + server versions drift apart at runtime? → negotiated (agree a version at connect)."
    - "Must already-shipped clients keep working across server changes indefinitely? → compatibility-guaranteed."
    - "Did a contract change break a consumer that pinned an older shape? → the guarantee tier was needed but not held."
composes_with:
  - "version coupling interacts with distribution (a wire boundary forces this axis)"
applies_when: []
tiers:
  - tier: unversioned
    commitment_delta:
      surface: interface-wire-contract
      delta: "the contract has no version; a change applies to all consumers immediately. Safe only when all consumers deploy in lockstep with the server."
    admin_tool: "none — coordinate deploys manually."
    enforcement:
      - "consumers + server ship together; no independently-deployed old client."
    tests:
      - "the current contract round-trips between current client + server."
    forecloses: "independent consumer deployment."
    migration_cost_to_next: "medium — introduce a version label + let consumers pin it."
  - tier: versioned
    commitment_delta:
      surface: interface-wire-contract
      delta: "the contract carries a version (semver); consumers pin a version + a mismatch is detectable. Breaking changes bump the major."
    admin_tool: "version-check tool that compares consumer-expected vs server-actual + warns on drift."
    enforcement:
      - "a breaking change bumps the major version; the version is exposed + checkable."
    tests:
      - "a consumer pinned to vN against a server at vN+major is detected as incompatible."
    forecloses: "silent breaking changes; a bump is now a visible event."
    migration_cost_to_next: "medium — negotiate a mutually-supported version at connect instead of static pinning."
  - tier: negotiated
    commitment_delta:
      surface: interface-wire-contract
      delta: "client + server exchange supported version ranges at connect + agree on the highest mutually-supported one; runtime drift is tolerated within the overlap."
    admin_tool: "negotiation-log / supported-range config."
    enforcement:
      - "every connection negotiates a version; an empty overlap fails the connection cleanly."
    tests:
      - "a client + server with overlapping ranges agree; a disjoint pair fails closed with a clear error."
    forecloses: "assuming a single global version; drift within the overlap is normal."
    migration_cost_to_next: "high — guarantee compatibility so old clients never need to renegotiate-or-break."
  - tier: compatibility-guaranteed
    commitment_delta:
      surface: interface-wire-contract
      delta: "changes are constrained to be backward (and/or forward) compatible; shapes once shipped keep working. Deprecation is a long, announced process, never a break."
    admin_tool: "compatibility checker in CI; deprecation tracker."
    enforcement:
      - "a change that would break a shipped shape is rejected pre-merge; removals go through a deprecation window."
    tests:
      - "an old-client message still parses against the new server; a breaking diff fails the compatibility gate."
    forecloses: "ever removing/changing a shipped shape without a deprecation cycle."
    migration_cost_to_next: "n/a — top of the ladder."
examples:
  - "The skill's own climb: the skill prose ⇄ MCP server are coupled by semver — check_skill_version compares the installed MCP version against what the skill prose expects + warns on drift (the MCP-version-stale-in-session quirk). The 4.x line treats a skill/MCP contract change as a version bump (#750 version-coupling-unify). Sits at versioned (semver + a drift check); not negotiated — the session pins one MCP build, and a stale build is detected, not negotiated around."
```

## Selection procedure (§8)

Bidirectional check; chosen once. Recorded in the system architecture record; a
breaking contract change shipped without the version bump the declared tier
requires is a systems-analysis D-finding.

## Composition (§5)

API-evolution is forced on by **distribution**: a wire boundary (multi-process)
makes the contract independently deployable, which is what makes this axis bite.
Rule authored in 5A.3.
