Detect breaking changes in API contracts across REST, GraphQL, and gRPC interfaces with semver enforcement
Scanned 9/3/2026
Install to Claude Code
npx -y skills add jmagly/aiwg --skill regression-api-contract --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Regression Api Contract?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/jmagly-regression-api-contract-6cd51e37)More formats (shields.io, HTML) on the badges page.
---
namespace: aiwg
name: regression-api-contract
platforms: [all]
description: Detect breaking changes in API contracts across REST, GraphQL, and gRPC interfaces with semver enforcement
---
# regression-api-contract
Detect breaking changes in API contracts across REST, GraphQL, and gRPC interfaces.
## Triggers
Alternate expressions and non-obvious activations (primary phrases are matched automatically from the skill description):
- "breaking change" → API contract regression
- "schema compatibility" → contract validation
- "Pact" / "Swagger diff" → contract testing tool names
## Purpose
This skill detects API contract regressions by:
- Identifying breaking changes in REST API endpoints
- Detecting schema changes in request/response contracts
- Validating GraphQL schema compatibility
- Checking gRPC/protobuf definition changes
- Enforcing semantic versioning compliance
- Integrating consumer contract testing (Pact, Spring Cloud Contract)
## Behavior
When triggered, this skill:
1. **Identifies API contract scope**:
- Discover API definition files (OpenAPI, GraphQL, protobuf)
- Identify baseline version for comparison
- Determine API type (REST, GraphQL, gRPC)
- Locate consumer contract tests
2. **Compares contracts to baseline**:
- Load current API definition
- Load baseline API definition
- Run compatibility analysis using appropriate tools
- Generate detailed diff of changes
3. **Classifies changes by severity**:
- **BREAKING**: Removed endpoints, fields, or enum values; type changes; new required fields
- **NON-BREAKING**: New optional fields, new endpoints, extended enums
- **DEPRECATED**: Marked for future removal
- **INTERNAL**: Implementation changes with no contract impact
4. **Validates semantic versioning**:
- Check if version increment matches change type
- Ensure breaking changes trigger major version bump
- Verify non-breaking changes use minor/patch versions
- Flag version mismatches
5. **Runs consumer contract tests**:
- Execute Pact or Spring Cloud Contract tests
- Validate against consumer expectations
- Identify consumers affected by changes
- Generate compatibility matrix
6. **Generates compatibility report**:
- List all breaking changes with locations
- Document affected consumers
- Recommend version bump strategy
- Suggest migration paths for consumers
## Breaking Change Categories
### REST API Breaking Changes
```yaml
rest_breaking_changes:
removed:
- endpoint: "DELETE /api/v1/users/{id}"
severity: BREAKING
reason: "Endpoint removed entirely"
- field: "email" from "User" response
severity: BREAKING
reason: "Required field removed from response"
- enum_value: "PENDING" from "OrderStatus"
severity: BREAKING
reason: "Enum value removed"
modified:
- field: "created_at"
from_type: "string"
to_type: "integer"
severity: BREAKING
reason: "Field type changed"
- field: "email"
from_required: false
to_required: true
severity: BREAKING
reason: "Optional field made required in request"
- constraint: "password"
from: "minLength: 6"
to: "minLength: 12"
severity: BREAKING
reason: "Stricter validation on request field"
renamed:
- endpoint: "GET /api/v1/user/{id}"
to: "GET /api/v1/users/{id}"
severity: BREAKING
reason: "Path renamed without redirect/alias"
- parameter: "userId"
to: "user_id"
severity: BREAKING
reason: "Parameter renamed without backward compatibility"
```
### GraphQL Schema Breaking Changes
```yaml
graphql_breaking_changes:
removed:
- field: "User.email"
severity: BREAKING
reason: "Field removed from type"
- argument: "Query.users(filter: UserFilter)"
severity: BREAKING
reason: "Required argument removed"
- type: "Address"
severity: BREAKING
reason: "Type removed from schema"
modified:
- field: "User.age"
from_type: "Int"
to_type: "String"
severity: BREAKING
reason: "Field type changed"
- field: "User.email"
from_nullable: true
to_nullable: false
severity: BREAKING
reason: "Field made non-nullable"
- argument: "Query.user(id: ID)"
from_optional: true
to_optional: false
severity: BREAKING
reason: "Argument made required"
interface_changes:
- interface: "Node"
removed_implementation: "User"
severity: BREAKING
reason: "Type no longer implements interface"
```
### gRPC/Protobuf Breaking Changes
```yaml
grpc_breaking_changes:
removed:
- field: "UserMessage.email"
field_number: 3
severity: BREAKING
reason: "Field removed from message"
- service: "UserService"
severity: BREAKING
reason: "Service removed"
- rpc: "UserService.GetUser"
severity: BREAKING
reason: "RPC method removed"
modified:
- field: "UserMessage.age"
from_type: "int32"
to_type: "string"
severity: BREAKING
reason: "Field type changed"
- field: "UserMessage.name"
from_label: "optional"
to_label: "required"
severity: BREAKING
reason: "Field made required"
- field_number: 5
from_reserved: false
to_reserved: true
severity: BREAKING
reason: "Field number reserved (deletion)"
renamed:
- message: "User"
to: "UserAccount"
severity: BREAKING
reason: "Message type renamed"
- enum: "Status"
to: "OrderStatus"
severity: BREAKING
reason: "Enum renamed"
```
## API Contract Tools Integration
### OpenAPI/REST
```yaml
openapi_tools:
primary: openapi-diff
alternatives:
- oasdiff
- swagger-diff
- api-diff
usage:
install: "npm install -g openapi-diff"
compare: |
openapi-diff \
.aiwg/api/baselines/openapi-v1.yaml \
.aiwg/api/current/openapi.yaml \
--format markdown \
--breaking-only
output: ".aiwg/api/compatibility/openapi-diff.md"
configuration:
strict_mode: true
ignore_descriptions: true
treat_as_breaking:
- removed_endpoints
- removed_fields
- type_changes
- required_field_additions
- enum_value_removals
```
### GraphQL
```yaml
graphql_tools:
primary: graphql-inspector
alternatives:
- apollo-cli (schema:check)
- graphql-schema-diff
usage:
install: "npm install -g @graphql-inspector/cli"
compare: |
graphql-inspector diff \
.aiwg/api/baselines/schema-v1.graphql \
.aiwg/api/current/schema.graphql \
--onComplete report.json
output: ".aiwg/api/compatibility/graphql-diff.json"
configuration:
fail_on_breaking: true
include_dangerous: true
schema_extensions: true
```
### gRPC/Protobuf
```yaml
protobuf_tools:
primary: buf
alternatives:
- prototool
- protoc-gen-validate
usage:
install: "brew install buf" # or "go install github.com/bufbuild/buf/cmd/buf@latest"
setup: |
# Create buf.yaml
version: v1
breaking:
use:
- FILE
lint:
use:
- DEFAULT
compare: |
buf breaking \
.aiwg/api/current \
--against .aiwg/api/baselines/v1
output: "Breaking change detection via buf CLI"
configuration:
breaking_rules:
- FIELD_SAME_TYPE
- FIELD_NO_DELETE
- ENUM_VALUE_NO_DELETE
- RPC_NO_DELETE
- MESSAGE_NO_DELETE
```
## Semantic Versioning Compliance
```yaml
semver_validation:
rules:
breaking_change:
requires: major_version_bump
examples:
- "v1.2.3 → v2.0.0"
violations:
- detected: breaking_change
version_change: "v1.2.3 → v1.3.0"
verdict: VIOLATION
message: "Breaking change detected but only minor version bumped"
non_breaking_addition:
requires: minor_version_bump
examples:
- "v1.2.3 → v1.3.0"
acceptable:
- "v1.2.3 → v2.0.0" # Major bump also acceptable
bug_fix:
requires: patch_version_bump
examples:
- "v1.2.3 → v1.2.4"
acceptable:
- "v1.2.3 → v1.3.0" # Minor/major also acceptable
enforcement:
block_deployment: true # Block if version mismatch
require_override: true # Allow manual override with justification
```
## Consumer Contract Testing
### Pact Integration
```yaml
pact_integration:
provider: api-service
consumers:
- name: web-frontend
pact_file: ".aiwg/api/pacts/web-frontend.json"
criticality: high
- name: mobile-app
pact_file: ".aiwg/api/pacts/mobile-app.json"
criticality: high
- name: partner-api
pact_file: ".aiwg/api/pacts/partner-api.json"
criticality: medium
verification:
run: |
npm run test:pact
# Verifies provider meets all consumer contracts
on_failure:
action: block_deployment
notification: consumers_affected
compatibility_matrix:
provider_version: v2.0.0
consumers:
- consumer: web-frontend
version: v1.5.0
compatible: true
tests_passing: 45/45
- consumer: mobile-app
version: v2.1.0
compatible: false
tests_passing: 38/42
failing_tests:
- "POST /api/users - email field type mismatch"
- "GET /api/users/{id} - missing 'phone' field"
- consumer: partner-api
version: v1.0.0
compatible: true
tests_passing: 12/12
```
### Spring Cloud Contract
```yaml
spring_cloud_contract:
contracts_location: ".aiwg/api/contracts/"
consumers:
- name: order-service
contracts: "contracts/order-service/**/*.groovy"
- name: payment-service
contracts: "contracts/payment-service/**/*.groovy"
verification:
run: "./mvnw clean test"
stub_generation: true
publish_stubs: true
compatibility_check:
baseline: v1.0.0
current: v2.0.0
results:
- consumer: order-service
compatible: true
contracts_verified: 8/8
- consumer: payment-service
compatible: false
contracts_verified: 5/7
failures:
- "User schema missing 'email' field"
- "Order status enum missing 'PENDING'"
```
## API Compatibility Report
```markdown
# API Compatibility Report
**Date**: 2026-01-28
**Baseline**: v1.5.0 (OpenAPI)
**Current**: v2.0.0
**API Type**: REST (OpenAPI 3.0)
## Executive Summary
**Status**: ⚠️ BREAKING CHANGES DETECTED
**Severity**: HIGH
**Breaking Changes**: 5
**Non-Breaking Changes**: 12
**Version Compliance**: ✅ CORRECT (major bump)
**Consumer Impact**: 2 of 4 consumers affected
## Version Validation
| Aspect | Baseline | Current | Required | Status |
|--------|----------|---------|----------|--------|
| Version | v1.5.0 | v2.0.0 | v2.x.x | ✅ CORRECT |
| Reason | - | Breaking changes detected | Major bump | ✅ VALID |
## Breaking Changes
### 1. Removed Endpoint
**Endpoint**: `DELETE /api/v1/users/{id}`
**Severity**: BREAKING
**Impact**: HIGH
**Details**:
- Endpoint removed entirely from API
- No replacement or redirect provided
- Used by 2 consumers: `web-frontend`, `admin-panel`
**Consumer Impact**:
- web-frontend: 3 call sites affected
- admin-panel: 1 call site affected
**Recommendation**:
- Provide migration path: Use `POST /api/v1/users/{id}/deactivate` instead
- Update consumer documentation
- Consider deprecation period instead of immediate removal
### 2. Field Removed: `User.email`
**Resource**: `User` (GET /api/v1/users/{id} response)
**Field**: `email`
**Severity**: BREAKING
**Impact**: CRITICAL
**Details**:
- Required field `email` removed from User response
- Breaking for consumers expecting this field
- No alternative field provided
**Consumer Impact**:
- web-frontend: AFFECTED (displays user email in profile)
- mobile-app: AFFECTED (uses email for contact)
- partner-api: NOT AFFECTED (does not use email)
**Recommendation**:
- DO NOT REMOVE - Add deprecation warning instead
- Or provide migration: Add `contactInfo.email` as replacement
- Document migration path clearly
### 3. Field Type Changed: `created_at`
**Field**: `created_at`
**From**: `string` (ISO-8601)
**To**: `integer` (Unix timestamp)
**Severity**: BREAKING
**Impact**: HIGH
**Details**:
- Field type incompatible change
- All consumers parsing as ISO-8601 will break
- No backward compatibility layer
**Consumer Impact**:
- ALL CONSUMERS AFFECTED (4/4)
- Requires code changes in all consumers
**Recommendation**:
- Add `created_at_unix` as new field (non-breaking)
- Deprecate `created_at` string format
- Maintain both for 2 versions before removing string format
### 4. New Required Field: `password_policy`
**Endpoint**: `POST /api/v1/users`
**Field**: `password_policy`
**Severity**: BREAKING
**Impact**: MEDIUM
**Details**:
- New field added as required in request body
- Consumers not sending this field will get 400 errors
- Breaking for existing integrations
**Consumer Impact**:
- web-frontend: AFFECTED (user registration form)
- mobile-app: AFFECTED (sign-up flow)
**Recommendation**:
- Make field optional with sensible default
- Or add default value if not provided
- Document new requirement clearly
### 5. Enum Value Removed: `OrderStatus.PENDING`
**Enum**: `OrderStatus`
**Value**: `PENDING`
**Severity**: BREAKING
**Impact**: HIGH
**Details**:
- Enum value removed without replacement
- Consumers comparing against `PENDING` will break
- Orders in `PENDING` state require migration
**Consumer Impact**:
- order-service: CRITICAL (manages pending orders)
- payment-service: AFFECTED (checks pending status)
**Recommendation**:
- DO NOT REMOVE - Deprecate instead
- Or provide mapping: `PENDING` → `AWAITING_CONFIRMATION`
- Migrate existing data before API deployment
## Non-Breaking Changes
### Safe Additions
| Change | Type | Impact |
|--------|------|--------|
| New endpoint: `GET /api/v2/users/search` | Addition | None |
| New optional field: `User.avatar_url` | Addition | None |
| New enum value: `OrderStatus.CANCELLED` | Addition | None |
| New query parameter: `?include_inactive` | Addition | None |
### Deprecations
| Item | Deprecated In | Remove In | Replacement |
|------|---------------|-----------|-------------|
| `GET /api/v1/users/list` | v2.0.0 | v3.0.0 | `GET /api/v2/users` |
| Field `User.phone` | v2.0.0 | v3.0.0 | `User.contactInfo.phone` |
## Consumer Contract Test Results
### Pact Verification
| Consumer | Version | Compatible | Tests | Failures |
|----------|---------|------------|-------|----------|
| web-frontend | v1.5.0 | ❌ NO | 38/45 | 7 |
| mobile-app | v2.1.0 | ❌ NO | 40/42 | 2 |
| partner-api | v1.0.0 | ✅ YES | 12/12 | 0 |
| admin-panel | v0.9.0 | ❌ NO | 15/18 | 3 |
### Failing Contract Tests
**web-frontend failures**:
1. `GET /api/v1/users/{id}` - Missing `email` field in response
2. `POST /api/v1/users` - Missing required field `password_policy`
3. `DELETE /api/v1/users/{id}` - Endpoint not found (404)
**mobile-app failures**:
1. `GET /api/v1/users/{id}` - Field type mismatch: `created_at`
2. `POST /api/v1/users` - Validation error: `password_policy` required
**admin-panel failures**:
1. `DELETE /api/v1/users/{id}` - Endpoint removed
2. `GET /api/v1/orders` - Enum value `PENDING` not recognized
3. `GET /api/v1/users/{id}` - Missing `email` field
## Backward Compatibility Analysis
```yaml
compatibility_assessment:
backward_compatible: false
reason: "5 breaking changes detected"
migration_effort:
web-frontend: HIGH (7 changes required)
mobile-app: MEDIUM (2 changes required)
partner-api: NONE (no changes needed)
admin-panel: HIGH (3 changes required)
recommended_strategy:
option_1:
name: "Parallel API versions"
description: "Maintain v1 and v2 simultaneously"
effort: HIGH
timeline: "6 months dual support"
option_2:
name: "Phased migration"
description: "Reduce breaking changes, migrate in phases"
effort: MEDIUM
timeline: "3 months migration window"
preferred: true
option_3:
name: "Hard cutover"
description: "Deploy v2, deprecate v1 immediately"
effort: LOW
timeline: "1 month notice"
risk: HIGH
```
## Recommendations
### Immediate Actions
- [ ] Revert breaking changes or provide backward compatibility layer
- [ ] Make `password_policy` field optional with default value
- [ ] Add `created_at_unix` alongside `created_at` string
- [ ] Do not remove `email` field - deprecate with timeline instead
- [ ] Provide `PENDING` → `AWAITING_CONFIRMATION` enum mapping
### Consumer Migration
- [ ] Notify all consumers of breaking changes
- [ ] Provide migration guide with code examples
- [ ] Offer migration support timeline (3 months)
- [ ] Update consumer contract tests
- [ ] Coordinate deployment across consumers
### Process Improvements
- [ ] Add contract testing to CI/CD pipeline
- [ ] Require compatibility report in PR template
- [ ] Enforce semantic versioning in release process
- [ ] Implement API deprecation policy (6-month notice)
- [ ] Add breaking change review gate
## Migration Guide
### For web-frontend
```diff
// User profile display
- const email = user.email;
+ const email = user.contactInfo?.email || user.email;
// User registration
const userData = {
username: form.username,
password: form.password,
+ password_policy: 'default',
};
// Delete user
- await api.delete(`/api/v1/users/${id}`);
+ await api.post(`/api/v1/users/${id}/deactivate`);
```
### For mobile-app
```diff
// Timestamp parsing
- const createdAt = new Date(user.created_at); // ISO string
+ const createdAt = user.created_at_unix
+ ? new Date(user.created_at_unix * 1000)
+ : new Date(user.created_at);
// User registration
const userData = {
...
+ password_policy: 'default',
};
```
## Tool Output
### OpenAPI Diff
```bash
$ openapi-diff baseline.yaml current.yaml --breaking-only
BREAKING CHANGES DETECTED (5):
1. DELETE /api/v1/users/{id}
- Endpoint removed
2. GET /api/v1/users/{id}
- Response schema changed
- Field 'email' removed
3. POST /api/v1/users
- Request schema changed
- Field 'password_policy' now required
4. OrderStatus enum
- Value 'PENDING' removed
5. Multiple endpoints
- Field 'created_at' type changed: string → integer
See full report: openapi-diff-report.md
```
```
## Usage Examples
### Detect REST API Regression
```
User: "Check API contract for breaking changes"
Skill executes:
1. Locate OpenAPI spec files
2. Load baseline (v1.5.0)
3. Load current (v2.0.0)
4. Run openapi-diff
5. Classify changes
6. Check semantic versioning
7. Run Pact tests
Output:
"API Compatibility Report
Status: BREAKING CHANGES DETECTED
Breaking: 5
Non-Breaking: 12
Version: v1.5.0 → v2.0.0 (CORRECT major bump)
Consumer Impact: 3 of 4 consumers affected
Critical Issues:
1. Field removed: User.email (affects web-frontend, mobile-app)
2. Endpoint removed: DELETE /api/v1/users/{id}
3. Type change: created_at string → integer
See full report: .aiwg/api/compatibility/report-2026-01-28.md
Recommendation: Revert breaking changes or add compatibility layer"
```
### Detect GraphQL Schema Regression
```
User: "API breaking change check for GraphQL"
Skill executes:
1. Locate GraphQL schema files
2. Load baseline schema
3. Load current schema
4. Run graphql-inspector diff
5. Identify breaking vs safe changes
Output:
"GraphQL Schema Compatibility
Status: BREAKING CHANGES DETECTED
Breaking: 2
Dangerous: 3
Safe: 8
Breaking Changes:
1. Field 'User.email' removed
2. Type 'Address' removed
Dangerous Changes:
1. Field 'User.age' type changed: Int → String
2. Argument 'Query.users(limit)' default changed: 10 → 100
3. Enum 'Status' value 'ACTIVE' description changed
Recommendation: Review breaking changes before deployment"
```
### Consumer Contract Verification
```
User: "Run consumer contract tests"
Skill executes:
1. Locate Pact contracts
2. Run provider verification tests
3. Generate compatibility matrix
Output:
"Consumer Contract Verification
Status: INCOMPATIBLE CONSUMERS DETECTED
Compatible: 1/4
Failing: 3/4
Results:
✅ partner-api (12/12 tests passing)
❌ web-frontend (38/45 passing, 7 failures)
❌ mobile-app (40/42 passing, 2 failures)
❌ admin-panel (15/18 passing, 3 failures)
Common Failures:
- Missing field: User.email (3 consumers)
- Endpoint not found: DELETE /api/v1/users/{id} (2 consumers)
Action Required: Update consumers or revert breaking changes"
```
## Integration
This skill uses:
- `regression-baseline`: Store API contract baselines
- `regression-bisect`: Find commit that introduced breaking change
- `regression-report`: Generate comprehensive regression report
- `project-awareness`: Detect API framework (OpenAPI, GraphQL, gRPC)
## Agent Orchestration
```yaml
agents:
detection:
agent: api-designer
focus: Identify and classify API changes
analysis:
agent: architecture-designer
focus: Assess impact and recommend migration
testing:
agent: test-engineer
focus: Run consumer contract tests
approval:
agent: tech-lead
focus: Approve breaking changes or require fixes
```
## Configuration
### Detection Settings
```yaml
api_contract_detection:
api_types:
- rest_openapi
- graphql
- grpc_protobuf
tools:
rest: openapi-diff
graphql: graphql-inspector
grpc: buf
baselines:
storage: .aiwg/api/baselines/
naming: "{api-name}-{version}.{ext}"
strict_mode: true # Fail on any breaking change
semver_enforcement: true
```
### Breaking Change Rules
```yaml
breaking_rules:
rest:
- removed_endpoints
- removed_fields
- type_changes
- new_required_fields
- enum_value_removals
- stricter_validations
graphql:
- removed_fields
- removed_types
- type_changes
- non_nullable_additions
- argument_removals
grpc:
- removed_services
- removed_rpcs
- removed_fields
- type_changes
- required_field_additions
```
### Consumer Contract Testing
```yaml
consumer_contracts:
enabled: true
framework: pact # or spring-cloud-contract
pact:
broker_url: https://pact-broker.example.com
publish_verification: true
contracts_location: .aiwg/api/contracts/
fail_on_incompatibility: true
```
## Output Locations
- Baselines: `.aiwg/api/baselines/{api-name}-{version}.{yaml|graphql|proto}`
- Reports: `.aiwg/api/compatibility/report-{date}.md`
- Diffs: `.aiwg/api/compatibility/diff-{baseline}-to-{current}.md`
- Pact Results: `.aiwg/api/pact-results/`
- Migration Guides: `.aiwg/api/migration/{version}/MIGRATION.md`
## References
- @$AIWG_ROOT/agentic/code/frameworks/sdlc-complete/schemas/testing/regression.yaml
- @$AIWG_ROOT/agentic/code/frameworks/sdlc-complete/agents/api-designer.md
- @$AIWG_ROOT/agentic/code/frameworks/sdlc-complete/skills/regression-baseline/SKILL.md
- @$AIWG_ROOT/agentic/code/frameworks/sdlc-complete/skills/regression-bisect/SKILL.md
- @.aiwg/research/findings/REF-013-metagpt.md
- @$AIWG_ROOT/agentic/code/frameworks/sdlc-complete/rules/executable-feedback.md
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!