agentic-qe 1.5.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/.claude-flow/metrics/agent-metrics.json +1 -0
- package/.claude/agents/.claude-flow/metrics/performance.json +87 -0
- package/.claude/agents/.claude-flow/metrics/task-metrics.json +10 -0
- package/.claude/agents/qe-api-contract-validator.md +118 -0
- package/.claude/agents/qe-chaos-engineer.md +320 -5
- package/.claude/agents/qe-code-complexity.md +360 -0
- package/.claude/agents/qe-coverage-analyzer.md +112 -0
- package/.claude/agents/qe-deployment-readiness.md +322 -6
- package/.claude/agents/qe-flaky-test-hunter.md +115 -0
- package/.claude/agents/qe-fleet-commander.md +319 -6
- package/.claude/agents/qe-performance-tester.md +234 -0
- package/.claude/agents/qe-production-intelligence.md +114 -0
- package/.claude/agents/qe-quality-analyzer.md +126 -0
- package/.claude/agents/qe-quality-gate.md +119 -0
- package/.claude/agents/qe-regression-risk-analyzer.md +114 -0
- package/.claude/agents/qe-requirements-validator.md +114 -0
- package/.claude/agents/qe-security-scanner.md +118 -0
- package/.claude/agents/qe-test-data-architect.md +234 -0
- package/.claude/agents/qe-test-executor.md +115 -0
- package/.claude/agents/qe-test-generator.md +114 -0
- package/.claude/agents/qe-visual-tester.md +305 -6
- package/.claude/agents/subagents/qe-code-reviewer.md +0 -4
- package/.claude/agents/subagents/qe-data-generator.md +0 -16
- package/.claude/agents/subagents/qe-integration-tester.md +0 -17
- package/.claude/agents/subagents/qe-performance-validator.md +0 -16
- package/.claude/agents/subagents/qe-security-auditor.md +0 -16
- package/.claude/agents/subagents/qe-test-implementer.md +0 -17
- package/.claude/agents/subagents/qe-test-refactorer.md +0 -17
- package/.claude/agents/subagents/qe-test-writer.md +0 -19
- package/CHANGELOG.md +261 -0
- package/README.md +37 -5
- package/dist/adapters/MemoryStoreAdapter.d.ts +38 -0
- package/dist/adapters/MemoryStoreAdapter.d.ts.map +1 -1
- package/dist/adapters/MemoryStoreAdapter.js +22 -0
- package/dist/adapters/MemoryStoreAdapter.js.map +1 -1
- package/dist/agents/BaseAgent.d.ts.map +1 -1
- package/dist/agents/BaseAgent.js +13 -0
- package/dist/agents/BaseAgent.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +32 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/core/memory/AgentDBService.d.ts +33 -28
- package/dist/core/memory/AgentDBService.d.ts.map +1 -1
- package/dist/core/memory/AgentDBService.js +233 -290
- package/dist/core/memory/AgentDBService.js.map +1 -1
- package/dist/core/memory/EnhancedAgentDBService.d.ts.map +1 -1
- package/dist/core/memory/EnhancedAgentDBService.js +5 -3
- package/dist/core/memory/EnhancedAgentDBService.js.map +1 -1
- package/dist/core/memory/RealAgentDBAdapter.d.ts +9 -2
- package/dist/core/memory/RealAgentDBAdapter.d.ts.map +1 -1
- package/dist/core/memory/RealAgentDBAdapter.js +126 -100
- package/dist/core/memory/RealAgentDBAdapter.js.map +1 -1
- package/dist/core/memory/SwarmMemoryManager.d.ts +58 -0
- package/dist/core/memory/SwarmMemoryManager.d.ts.map +1 -1
- package/dist/core/memory/SwarmMemoryManager.js +176 -0
- package/dist/core/memory/SwarmMemoryManager.js.map +1 -1
- package/dist/core/memory/index.d.ts.map +1 -1
- package/dist/core/memory/index.js +2 -1
- package/dist/core/memory/index.js.map +1 -1
- package/dist/learning/LearningEngine.d.ts +14 -27
- package/dist/learning/LearningEngine.d.ts.map +1 -1
- package/dist/learning/LearningEngine.js +57 -119
- package/dist/learning/LearningEngine.js.map +1 -1
- package/dist/learning/index.d.ts +0 -1
- package/dist/learning/index.d.ts.map +1 -1
- package/dist/learning/index.js +0 -1
- package/dist/learning/index.js.map +1 -1
- package/dist/mcp/handlers/learning/learning-query.d.ts +34 -0
- package/dist/mcp/handlers/learning/learning-query.d.ts.map +1 -0
- package/dist/mcp/handlers/learning/learning-query.js +156 -0
- package/dist/mcp/handlers/learning/learning-query.js.map +1 -0
- package/dist/mcp/handlers/learning/learning-store-experience.d.ts +30 -0
- package/dist/mcp/handlers/learning/learning-store-experience.d.ts.map +1 -0
- package/dist/mcp/handlers/learning/learning-store-experience.js +86 -0
- package/dist/mcp/handlers/learning/learning-store-experience.js.map +1 -0
- package/dist/mcp/handlers/learning/learning-store-pattern.d.ts +31 -0
- package/dist/mcp/handlers/learning/learning-store-pattern.d.ts.map +1 -0
- package/dist/mcp/handlers/learning/learning-store-pattern.js +126 -0
- package/dist/mcp/handlers/learning/learning-store-pattern.js.map +1 -0
- package/dist/mcp/handlers/learning/learning-store-qvalue.d.ts +30 -0
- package/dist/mcp/handlers/learning/learning-store-qvalue.d.ts.map +1 -0
- package/dist/mcp/handlers/learning/learning-store-qvalue.js +100 -0
- package/dist/mcp/handlers/learning/learning-store-qvalue.js.map +1 -0
- package/dist/mcp/server.d.ts +11 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +98 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/services/LearningEventListener.d.ts +123 -0
- package/dist/mcp/services/LearningEventListener.d.ts.map +1 -0
- package/dist/mcp/services/LearningEventListener.js +322 -0
- package/dist/mcp/services/LearningEventListener.js.map +1 -0
- package/dist/mcp/tools.d.ts +4 -0
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +179 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/types/memory-interfaces.d.ts +71 -0
- package/dist/types/memory-interfaces.d.ts.map +1 -1
- package/dist/utils/Calculator.d.ts +35 -0
- package/dist/utils/Calculator.d.ts.map +1 -0
- package/dist/utils/Calculator.js +50 -0
- package/dist/utils/Calculator.js.map +1 -0
- package/dist/utils/Logger.d.ts.map +1 -1
- package/dist/utils/Logger.js +4 -1
- package/dist/utils/Logger.js.map +1 -1
- package/package.json +7 -5
- package/.claude/agents/qe-api-contract-validator.md.backup +0 -1148
- package/.claude/agents/qe-api-contract-validator.md.backup-20251107-134747 +0 -1148
- package/.claude/agents/qe-api-contract-validator.md.backup-phase2-20251107-140039 +0 -1123
- package/.claude/agents/qe-chaos-engineer.md.backup +0 -808
- package/.claude/agents/qe-chaos-engineer.md.backup-20251107-134747 +0 -808
- package/.claude/agents/qe-chaos-engineer.md.backup-phase2-20251107-140039 +0 -787
- package/.claude/agents/qe-code-complexity.md.backup +0 -291
- package/.claude/agents/qe-code-complexity.md.backup-20251107-134747 +0 -291
- package/.claude/agents/qe-code-complexity.md.backup-phase2-20251107-140039 +0 -286
- package/.claude/agents/qe-coverage-analyzer.md.backup +0 -467
- package/.claude/agents/qe-coverage-analyzer.md.backup-20251107-134747 +0 -467
- package/.claude/agents/qe-coverage-analyzer.md.backup-phase2-20251107-140039 +0 -438
- package/.claude/agents/qe-deployment-readiness.md.backup +0 -1166
- package/.claude/agents/qe-deployment-readiness.md.backup-20251107-134747 +0 -1166
- package/.claude/agents/qe-deployment-readiness.md.backup-phase2-20251107-140039 +0 -1140
- package/.claude/agents/qe-flaky-test-hunter.md.backup +0 -1195
- package/.claude/agents/qe-flaky-test-hunter.md.backup-20251107-134747 +0 -1195
- package/.claude/agents/qe-flaky-test-hunter.md.backup-phase2-20251107-140039 +0 -1162
- package/.claude/agents/qe-fleet-commander.md.backup +0 -718
- package/.claude/agents/qe-fleet-commander.md.backup-20251107-134747 +0 -718
- package/.claude/agents/qe-fleet-commander.md.backup-phase2-20251107-140039 +0 -697
- package/.claude/agents/qe-performance-tester.md.backup +0 -428
- package/.claude/agents/qe-performance-tester.md.backup-20251107-134747 +0 -428
- package/.claude/agents/qe-performance-tester.md.backup-phase2-20251107-140039 +0 -372
- package/.claude/agents/qe-production-intelligence.md.backup +0 -1219
- package/.claude/agents/qe-production-intelligence.md.backup-20251107-134747 +0 -1219
- package/.claude/agents/qe-production-intelligence.md.backup-phase2-20251107-140039 +0 -1194
- package/.claude/agents/qe-quality-analyzer.md.backup +0 -425
- package/.claude/agents/qe-quality-analyzer.md.backup-20251107-134747 +0 -425
- package/.claude/agents/qe-quality-analyzer.md.backup-phase2-20251107-140039 +0 -394
- package/.claude/agents/qe-quality-gate.md.backup +0 -446
- package/.claude/agents/qe-quality-gate.md.backup-20251107-134747 +0 -446
- package/.claude/agents/qe-quality-gate.md.backup-phase2-20251107-140039 +0 -415
- package/.claude/agents/qe-regression-risk-analyzer.md.backup +0 -1009
- package/.claude/agents/qe-regression-risk-analyzer.md.backup-20251107-134747 +0 -1009
- package/.claude/agents/qe-regression-risk-analyzer.md.backup-phase2-20251107-140039 +0 -984
- package/.claude/agents/qe-requirements-validator.md.backup +0 -748
- package/.claude/agents/qe-requirements-validator.md.backup-20251107-134747 +0 -748
- package/.claude/agents/qe-requirements-validator.md.backup-phase2-20251107-140039 +0 -723
- package/.claude/agents/qe-security-scanner.md.backup +0 -634
- package/.claude/agents/qe-security-scanner.md.backup-20251107-134747 +0 -634
- package/.claude/agents/qe-security-scanner.md.backup-phase2-20251107-140039 +0 -573
- package/.claude/agents/qe-test-data-architect.md.backup +0 -1064
- package/.claude/agents/qe-test-data-architect.md.backup-20251107-134747 +0 -1064
- package/.claude/agents/qe-test-data-architect.md.backup-phase2-20251107-140039 +0 -1040
- package/.claude/agents/qe-test-executor.md.backup +0 -389
- package/.claude/agents/qe-test-executor.md.backup-20251107-134747 +0 -389
- package/.claude/agents/qe-test-executor.md.backup-phase2-20251107-140039 +0 -369
- package/.claude/agents/qe-test-generator.md.backup +0 -997
- package/.claude/agents/qe-test-generator.md.backup-20251107-134747 +0 -997
- package/.claude/agents/qe-visual-tester.md.backup +0 -777
- package/.claude/agents/qe-visual-tester.md.backup-20251107-134747 +0 -777
- package/.claude/agents/qe-visual-tester.md.backup-phase2-20251107-140039 +0 -756
|
@@ -1,1123 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: qe-api-contract-validator
|
|
3
|
-
description: Validates API contracts, detects breaking changes, and ensures backward compatibility across services
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# QE API Contract Validator Agent
|
|
7
|
-
|
|
8
|
-
## Mission Statement
|
|
9
|
-
|
|
10
|
-
The API Contract Validator agent **prevents breaking API changes** by validating contracts against consumer expectations, detecting backward compatibility issues, and ensuring semantic versioning compliance. Using contract-first testing, schema validation, and consumer-driven contracts, this agent catches 95% of integration issues before deployment. It transforms API evolution from a risky breaking-change minefield into a safe, predictable process with confidence in backward compatibility.
|
|
11
|
-
|
|
12
|
-
## Skills Available
|
|
13
|
-
|
|
14
|
-
### Core Testing Skills (Phase 1)
|
|
15
|
-
- **agentic-quality-engineering**: Using AI agents as force multipliers in quality work
|
|
16
|
-
- **api-testing-patterns**: Comprehensive API testing patterns including contract testing, REST/GraphQL testing
|
|
17
|
-
|
|
18
|
-
### Phase 2 Skills (NEW in v1.3.0)
|
|
19
|
-
- **contract-testing**: Consumer-driven contract testing for microservices using Pact and API versioning
|
|
20
|
-
- **regression-testing**: Strategic regression testing with test selection, impact analysis, and continuous regression management
|
|
21
|
-
|
|
22
|
-
Use these skills via:
|
|
23
|
-
```bash
|
|
24
|
-
# Via CLI
|
|
25
|
-
aqe skills show contract-testing
|
|
26
|
-
|
|
27
|
-
# Via Skill tool in Claude Code
|
|
28
|
-
Skill("contract-testing")
|
|
29
|
-
Skill("regression-testing")
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Core Capabilities
|
|
33
|
-
|
|
34
|
-
### 1. Schema Validation
|
|
35
|
-
|
|
36
|
-
Validates API requests and responses against OpenAPI, GraphQL, or JSON Schema specifications.
|
|
37
|
-
|
|
38
|
-
**Schema Validator:**
|
|
39
|
-
```javascript
|
|
40
|
-
class APISchemaValidator {
|
|
41
|
-
async validate(request, response, schema) {
|
|
42
|
-
const validation = {
|
|
43
|
-
valid: true,
|
|
44
|
-
errors: [],
|
|
45
|
-
warnings: []
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// Validate request
|
|
49
|
-
const requestValidation = this.validateRequest(request, schema);
|
|
50
|
-
if (!requestValidation.valid) {
|
|
51
|
-
validation.valid = false;
|
|
52
|
-
validation.errors.push(...requestValidation.errors);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Validate response
|
|
56
|
-
const responseValidation = this.validateResponse(response, schema);
|
|
57
|
-
if (!responseValidation.valid) {
|
|
58
|
-
validation.valid = false;
|
|
59
|
-
validation.errors.push(...responseValidation.errors);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Validate headers
|
|
63
|
-
const headerValidation = this.validateHeaders(request, response, schema);
|
|
64
|
-
validation.warnings.push(...headerValidation.warnings);
|
|
65
|
-
|
|
66
|
-
// Validate status codes
|
|
67
|
-
const statusValidation = this.validateStatusCodes(response, schema);
|
|
68
|
-
if (!statusValidation.valid) {
|
|
69
|
-
validation.errors.push(...statusValidation.errors);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return validation;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
validateRequest(request, schema) {
|
|
76
|
-
const errors = [];
|
|
77
|
-
|
|
78
|
-
// Validate path parameters
|
|
79
|
-
for (const param of schema.parameters || []) {
|
|
80
|
-
if (param.in === 'path' && param.required) {
|
|
81
|
-
if (request.params[param.name] === undefined) {
|
|
82
|
-
errors.push({
|
|
83
|
-
type: 'MISSING_PATH_PARAM',
|
|
84
|
-
param: param.name,
|
|
85
|
-
message: `Required path parameter '${param.name}' is missing`
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Validate query parameters
|
|
92
|
-
for (const param of schema.parameters || []) {
|
|
93
|
-
if (param.in === 'query' && param.required) {
|
|
94
|
-
if (request.query[param.name] === undefined) {
|
|
95
|
-
errors.push({
|
|
96
|
-
type: 'MISSING_QUERY_PARAM',
|
|
97
|
-
param: param.name,
|
|
98
|
-
message: `Required query parameter '${param.name}' is missing`
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Validate request body against schema
|
|
105
|
-
if (schema.requestBody) {
|
|
106
|
-
const bodySchema = schema.requestBody.content['application/json'].schema;
|
|
107
|
-
const bodyValidation = this.validateAgainstJSONSchema(request.body, bodySchema);
|
|
108
|
-
errors.push(...bodyValidation.errors);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return { valid: errors.length === 0, errors };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
validateResponse(response, schema) {
|
|
115
|
-
const errors = [];
|
|
116
|
-
|
|
117
|
-
const statusSchema = schema.responses[response.status];
|
|
118
|
-
if (!statusSchema) {
|
|
119
|
-
errors.push({
|
|
120
|
-
type: 'UNDOCUMENTED_STATUS',
|
|
121
|
-
status: response.status,
|
|
122
|
-
message: `Status code ${response.status} not documented in schema`
|
|
123
|
-
});
|
|
124
|
-
return { valid: false, errors };
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Validate response body
|
|
128
|
-
const contentType = response.headers['content-type'] || 'application/json';
|
|
129
|
-
const responseSchema = statusSchema.content?.[contentType]?.schema;
|
|
130
|
-
|
|
131
|
-
if (responseSchema) {
|
|
132
|
-
const bodyValidation = this.validateAgainstJSONSchema(response.body, responseSchema);
|
|
133
|
-
errors.push(...bodyValidation.errors);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return { valid: errors.length === 0, errors };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
validateAgainstJSONSchema(data, schema) {
|
|
140
|
-
const ajv = new Ajv({ allErrors: true });
|
|
141
|
-
const validate = ajv.compile(schema);
|
|
142
|
-
const valid = validate(data);
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
valid,
|
|
146
|
-
errors: valid ? [] : validate.errors.map(error => ({
|
|
147
|
-
type: 'SCHEMA_VALIDATION',
|
|
148
|
-
path: error.instancePath,
|
|
149
|
-
message: error.message,
|
|
150
|
-
params: error.params
|
|
151
|
-
}))
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
**Validation Example:**
|
|
158
|
-
```javascript
|
|
159
|
-
// OpenAPI Schema
|
|
160
|
-
const schema = {
|
|
161
|
-
paths: {
|
|
162
|
-
'/users/{userId}': {
|
|
163
|
-
get: {
|
|
164
|
-
parameters: [
|
|
165
|
-
{ name: 'userId', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } }
|
|
166
|
-
],
|
|
167
|
-
responses: {
|
|
168
|
-
200: {
|
|
169
|
-
content: {
|
|
170
|
-
'application/json': {
|
|
171
|
-
schema: {
|
|
172
|
-
type: 'object',
|
|
173
|
-
required: ['id', 'email', 'name'],
|
|
174
|
-
properties: {
|
|
175
|
-
id: { type: 'string', format: 'uuid' },
|
|
176
|
-
email: { type: 'string', format: 'email' },
|
|
177
|
-
name: { type: 'string', minLength: 1, maxLength: 100 },
|
|
178
|
-
age: { type: 'integer', minimum: 0, maximum: 120 }
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
},
|
|
184
|
-
404: {
|
|
185
|
-
content: {
|
|
186
|
-
'application/json': {
|
|
187
|
-
schema: {
|
|
188
|
-
type: 'object',
|
|
189
|
-
properties: {
|
|
190
|
-
error: { type: 'string' },
|
|
191
|
-
message: { type: 'string' }
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
// Valid response
|
|
204
|
-
const validResponse = {
|
|
205
|
-
status: 200,
|
|
206
|
-
body: {
|
|
207
|
-
id: "550e8400-e29b-41d4-a716-446655440000",
|
|
208
|
-
email: "alice@example.com",
|
|
209
|
-
name: "Alice Johnson",
|
|
210
|
-
age: 34
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
// ✅ Validation passes
|
|
215
|
-
|
|
216
|
-
// Invalid response
|
|
217
|
-
const invalidResponse = {
|
|
218
|
-
status: 200,
|
|
219
|
-
body: {
|
|
220
|
-
id: "not-a-uuid", // Invalid UUID format
|
|
221
|
-
email: "invalid-email", // Invalid email format
|
|
222
|
-
// name missing - required field
|
|
223
|
-
age: 150 // Exceeds maximum
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
// ❌ Validation errors:
|
|
228
|
-
// - id: must match format "uuid"
|
|
229
|
-
// - email: must match format "email"
|
|
230
|
-
// - name: required property missing
|
|
231
|
-
// - age: must be <= 120
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### 2. Breaking Change Detection
|
|
235
|
-
|
|
236
|
-
Detects breaking changes between API versions using sophisticated schema comparison.
|
|
237
|
-
|
|
238
|
-
**Breaking Change Detector:**
|
|
239
|
-
```javascript
|
|
240
|
-
class BreakingChangeDetector {
|
|
241
|
-
detectBreakingChanges(baselineSchema, candidateSchema) {
|
|
242
|
-
const breakingChanges = [];
|
|
243
|
-
const nonBreakingChanges = [];
|
|
244
|
-
|
|
245
|
-
// Compare endpoints
|
|
246
|
-
for (const [path, methods] of Object.entries(baselineSchema.paths)) {
|
|
247
|
-
if (!candidateSchema.paths[path]) {
|
|
248
|
-
breakingChanges.push({
|
|
249
|
-
type: 'ENDPOINT_REMOVED',
|
|
250
|
-
severity: 'CRITICAL',
|
|
251
|
-
path: path,
|
|
252
|
-
message: `Endpoint ${path} was removed`
|
|
253
|
-
});
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
for (const [method, operation] of Object.entries(methods)) {
|
|
258
|
-
if (!candidateSchema.paths[path][method]) {
|
|
259
|
-
breakingChanges.push({
|
|
260
|
-
type: 'METHOD_REMOVED',
|
|
261
|
-
severity: 'CRITICAL',
|
|
262
|
-
path: path,
|
|
263
|
-
method: method,
|
|
264
|
-
message: `Method ${method.toUpperCase()} ${path} was removed`
|
|
265
|
-
});
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Compare parameters
|
|
270
|
-
const paramChanges = this.compareParameters(
|
|
271
|
-
operation.parameters || [],
|
|
272
|
-
candidateSchema.paths[path][method].parameters || []
|
|
273
|
-
);
|
|
274
|
-
breakingChanges.push(...paramChanges.breaking);
|
|
275
|
-
nonBreakingChanges.push(...paramChanges.nonBreaking);
|
|
276
|
-
|
|
277
|
-
// Compare request body
|
|
278
|
-
const requestChanges = this.compareRequestBody(
|
|
279
|
-
operation.requestBody,
|
|
280
|
-
candidateSchema.paths[path][method].requestBody
|
|
281
|
-
);
|
|
282
|
-
breakingChanges.push(...requestChanges.breaking);
|
|
283
|
-
nonBreakingChanges.push(...requestChanges.nonBreaking);
|
|
284
|
-
|
|
285
|
-
// Compare responses
|
|
286
|
-
const responseChanges = this.compareResponses(
|
|
287
|
-
operation.responses,
|
|
288
|
-
candidateSchema.paths[path][method].responses
|
|
289
|
-
);
|
|
290
|
-
breakingChanges.push(...responseChanges.breaking);
|
|
291
|
-
nonBreakingChanges.push(...responseChanges.nonBreaking);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
return {
|
|
296
|
-
breaking: breakingChanges,
|
|
297
|
-
nonBreaking: nonBreakingChanges,
|
|
298
|
-
hasBreakingChanges: breakingChanges.length > 0,
|
|
299
|
-
summary: this.generateSummary(breakingChanges, nonBreakingChanges)
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
compareParameters(baseline, candidate) {
|
|
304
|
-
const breaking = [];
|
|
305
|
-
const nonBreaking = [];
|
|
306
|
-
|
|
307
|
-
// Check for removed required parameters
|
|
308
|
-
for (const param of baseline) {
|
|
309
|
-
const candidateParam = candidate.find(p => p.name === param.name && p.in === param.in);
|
|
310
|
-
|
|
311
|
-
if (!candidateParam) {
|
|
312
|
-
if (param.required) {
|
|
313
|
-
breaking.push({
|
|
314
|
-
type: 'REQUIRED_PARAM_REMOVED',
|
|
315
|
-
severity: 'CRITICAL',
|
|
316
|
-
param: param.name,
|
|
317
|
-
location: param.in,
|
|
318
|
-
message: `Required parameter '${param.name}' (${param.in}) was removed`
|
|
319
|
-
});
|
|
320
|
-
} else {
|
|
321
|
-
nonBreaking.push({
|
|
322
|
-
type: 'OPTIONAL_PARAM_REMOVED',
|
|
323
|
-
param: param.name,
|
|
324
|
-
location: param.in,
|
|
325
|
-
message: `Optional parameter '${param.name}' (${param.in}) was removed`
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
} else {
|
|
329
|
-
// Check if parameter became required
|
|
330
|
-
if (!param.required && candidateParam.required) {
|
|
331
|
-
breaking.push({
|
|
332
|
-
type: 'PARAM_BECAME_REQUIRED',
|
|
333
|
-
severity: 'HIGH',
|
|
334
|
-
param: param.name,
|
|
335
|
-
location: param.in,
|
|
336
|
-
message: `Parameter '${param.name}' (${param.in}) became required`
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// Check for type changes
|
|
341
|
-
if (param.schema?.type !== candidateParam.schema?.type) {
|
|
342
|
-
breaking.push({
|
|
343
|
-
type: 'PARAM_TYPE_CHANGED',
|
|
344
|
-
severity: 'HIGH',
|
|
345
|
-
param: param.name,
|
|
346
|
-
oldType: param.schema?.type,
|
|
347
|
-
newType: candidateParam.schema?.type,
|
|
348
|
-
message: `Parameter '${param.name}' type changed from ${param.schema?.type} to ${candidateParam.schema?.type}`
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Check for new required parameters (breaking)
|
|
355
|
-
for (const param of candidate) {
|
|
356
|
-
const baselineParam = baseline.find(p => p.name === param.name && p.in === param.in);
|
|
357
|
-
if (!baselineParam && param.required) {
|
|
358
|
-
breaking.push({
|
|
359
|
-
type: 'NEW_REQUIRED_PARAM',
|
|
360
|
-
severity: 'HIGH',
|
|
361
|
-
param: param.name,
|
|
362
|
-
location: param.in,
|
|
363
|
-
message: `New required parameter '${param.name}' (${param.in}) was added`
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
return { breaking, nonBreaking };
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
compareRequestBody(baseline, candidate) {
|
|
372
|
-
const breaking = [];
|
|
373
|
-
const nonBreaking = [];
|
|
374
|
-
|
|
375
|
-
if (!baseline && candidate?.required) {
|
|
376
|
-
breaking.push({
|
|
377
|
-
type: 'REQUEST_BODY_REQUIRED',
|
|
378
|
-
severity: 'HIGH',
|
|
379
|
-
message: 'Request body became required'
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
if (baseline && !candidate) {
|
|
384
|
-
breaking.push({
|
|
385
|
-
type: 'REQUEST_BODY_REMOVED',
|
|
386
|
-
severity: 'CRITICAL',
|
|
387
|
-
message: 'Request body was removed'
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// Compare schema if both exist
|
|
392
|
-
if (baseline?.content && candidate?.content) {
|
|
393
|
-
const baselineSchema = baseline.content['application/json']?.schema;
|
|
394
|
-
const candidateSchema = candidate.content['application/json']?.schema;
|
|
395
|
-
|
|
396
|
-
if (baselineSchema && candidateSchema) {
|
|
397
|
-
const schemaChanges = this.compareSchemas(baselineSchema, candidateSchema);
|
|
398
|
-
breaking.push(...schemaChanges.breaking);
|
|
399
|
-
nonBreaking.push(...schemaChanges.nonBreaking);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
return { breaking, nonBreaking };
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
compareResponses(baseline, candidate) {
|
|
407
|
-
const breaking = [];
|
|
408
|
-
const nonBreaking = [];
|
|
409
|
-
|
|
410
|
-
// Check for removed success responses
|
|
411
|
-
for (const [status, response] of Object.entries(baseline)) {
|
|
412
|
-
if (!candidate[status]) {
|
|
413
|
-
if (status.startsWith('2')) { // Success status codes
|
|
414
|
-
breaking.push({
|
|
415
|
-
type: 'RESPONSE_STATUS_REMOVED',
|
|
416
|
-
severity: 'CRITICAL',
|
|
417
|
-
status: status,
|
|
418
|
-
message: `Success response ${status} was removed`
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
} else {
|
|
422
|
-
// Compare response schemas
|
|
423
|
-
const baselineSchema = response.content?.['application/json']?.schema;
|
|
424
|
-
const candidateSchema = candidate[status].content?.['application/json']?.schema;
|
|
425
|
-
|
|
426
|
-
if (baselineSchema && candidateSchema) {
|
|
427
|
-
const schemaChanges = this.compareResponseSchemas(baselineSchema, candidateSchema);
|
|
428
|
-
breaking.push(...schemaChanges.breaking.map(c => ({ ...c, status })));
|
|
429
|
-
nonBreaking.push(...schemaChanges.nonBreaking.map(c => ({ ...c, status })));
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
return { breaking, nonBreaking };
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
compareResponseSchemas(baseline, candidate) {
|
|
438
|
-
const breaking = [];
|
|
439
|
-
const nonBreaking = [];
|
|
440
|
-
|
|
441
|
-
// Check for removed required fields
|
|
442
|
-
if (baseline.required) {
|
|
443
|
-
for (const field of baseline.required) {
|
|
444
|
-
if (!candidate.required?.includes(field)) {
|
|
445
|
-
breaking.push({
|
|
446
|
-
type: 'REQUIRED_FIELD_REMOVED',
|
|
447
|
-
severity: 'CRITICAL',
|
|
448
|
-
field: field,
|
|
449
|
-
message: `Required response field '${field}' was removed`
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
// Check for type changes in existing fields
|
|
456
|
-
if (baseline.properties && candidate.properties) {
|
|
457
|
-
for (const [field, fieldSchema] of Object.entries(baseline.properties)) {
|
|
458
|
-
const candidateFieldSchema = candidate.properties[field];
|
|
459
|
-
|
|
460
|
-
if (!candidateFieldSchema) {
|
|
461
|
-
breaking.push({
|
|
462
|
-
type: 'FIELD_REMOVED',
|
|
463
|
-
severity: 'HIGH',
|
|
464
|
-
field: field,
|
|
465
|
-
message: `Response field '${field}' was removed`
|
|
466
|
-
});
|
|
467
|
-
} else if (fieldSchema.type !== candidateFieldSchema.type) {
|
|
468
|
-
breaking.push({
|
|
469
|
-
type: 'FIELD_TYPE_CHANGED',
|
|
470
|
-
severity: 'HIGH',
|
|
471
|
-
field: field,
|
|
472
|
-
oldType: fieldSchema.type,
|
|
473
|
-
newType: candidateFieldSchema.type,
|
|
474
|
-
message: `Response field '${field}' type changed from ${fieldSchema.type} to ${candidateFieldSchema.type}`
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// New fields are non-breaking
|
|
480
|
-
for (const field of Object.keys(candidate.properties)) {
|
|
481
|
-
if (!baseline.properties[field]) {
|
|
482
|
-
nonBreaking.push({
|
|
483
|
-
type: 'FIELD_ADDED',
|
|
484
|
-
field: field,
|
|
485
|
-
message: `Response field '${field}' was added`
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
return { breaking, nonBreaking };
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
**Breaking Change Report:**
|
|
497
|
-
```json
|
|
498
|
-
{
|
|
499
|
-
"comparison": {
|
|
500
|
-
"baseline": "v2.4.0",
|
|
501
|
-
"candidate": "v2.5.0",
|
|
502
|
-
"timestamp": "2025-09-30T14:23:45Z"
|
|
503
|
-
},
|
|
504
|
-
|
|
505
|
-
"breakingChanges": [
|
|
506
|
-
{
|
|
507
|
-
"type": "REQUIRED_FIELD_REMOVED",
|
|
508
|
-
"severity": "CRITICAL",
|
|
509
|
-
"endpoint": "GET /api/users/{id}",
|
|
510
|
-
"status": 200,
|
|
511
|
-
"field": "username",
|
|
512
|
-
"message": "Required response field 'username' was removed",
|
|
513
|
-
"impact": {
|
|
514
|
-
"affectedConsumers": 23,
|
|
515
|
-
"estimatedRequests": "1.2M/day",
|
|
516
|
-
"migrationEffort": "HIGH"
|
|
517
|
-
},
|
|
518
|
-
"recommendation": "Deprecate in v2.5.0, remove in v3.0.0"
|
|
519
|
-
},
|
|
520
|
-
{
|
|
521
|
-
"type": "PARAM_TYPE_CHANGED",
|
|
522
|
-
"severity": "HIGH",
|
|
523
|
-
"endpoint": "POST /api/orders",
|
|
524
|
-
"param": "quantity",
|
|
525
|
-
"oldType": "integer",
|
|
526
|
-
"newType": "string",
|
|
527
|
-
"message": "Parameter 'quantity' type changed from integer to string",
|
|
528
|
-
"impact": {
|
|
529
|
-
"affectedConsumers": 8,
|
|
530
|
-
"estimatedRequests": "450K/day",
|
|
531
|
-
"migrationEffort": "MEDIUM"
|
|
532
|
-
},
|
|
533
|
-
"recommendation": "Revert change or bump major version"
|
|
534
|
-
}
|
|
535
|
-
],
|
|
536
|
-
|
|
537
|
-
"nonBreakingChanges": [
|
|
538
|
-
{
|
|
539
|
-
"type": "FIELD_ADDED",
|
|
540
|
-
"endpoint": "GET /api/users/{id}",
|
|
541
|
-
"status": 200,
|
|
542
|
-
"field": "profilePicture",
|
|
543
|
-
"message": "Response field 'profilePicture' was added",
|
|
544
|
-
"impact": "None - backward compatible addition"
|
|
545
|
-
},
|
|
546
|
-
{
|
|
547
|
-
"type": "OPTIONAL_PARAM_ADDED",
|
|
548
|
-
"endpoint": "GET /api/products",
|
|
549
|
-
"param": "sortBy",
|
|
550
|
-
"message": "Optional parameter 'sortBy' was added",
|
|
551
|
-
"impact": "None - existing clients unaffected"
|
|
552
|
-
}
|
|
553
|
-
],
|
|
554
|
-
|
|
555
|
-
"summary": {
|
|
556
|
-
"totalBreaking": 2,
|
|
557
|
-
"totalNonBreaking": 2,
|
|
558
|
-
"recommendation": "🚨 BLOCK DEPLOYMENT - Breaking changes detected",
|
|
559
|
-
"suggestedVersion": "v3.0.0", // Major version bump required
|
|
560
|
-
"estimatedMigrationTime": "2-3 weeks",
|
|
561
|
-
"affectedConsumers": 31
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
### 3. Version Compatibility
|
|
567
|
-
|
|
568
|
-
Validates semantic versioning compliance and ensures proper version bumps for API changes.
|
|
569
|
-
|
|
570
|
-
**Version Compatibility Checker:**
|
|
571
|
-
```javascript
|
|
572
|
-
class VersionCompatibilityChecker {
|
|
573
|
-
validateVersionBump(currentVersion, proposedVersion, changes) {
|
|
574
|
-
const current = this.parseVersion(currentVersion);
|
|
575
|
-
const proposed = this.parseVersion(proposedVersion);
|
|
576
|
-
|
|
577
|
-
const required = this.calculateRequiredVersionBump(changes);
|
|
578
|
-
|
|
579
|
-
const validation = {
|
|
580
|
-
valid: false,
|
|
581
|
-
currentVersion,
|
|
582
|
-
proposedVersion,
|
|
583
|
-
requiredBump: required.type,
|
|
584
|
-
actualBump: this.getActualBump(current, proposed),
|
|
585
|
-
recommendation: required.recommendedVersion,
|
|
586
|
-
violations: []
|
|
587
|
-
};
|
|
588
|
-
|
|
589
|
-
// Validate version bump is sufficient
|
|
590
|
-
if (required.type === 'MAJOR' && (proposed.major <= current.major)) {
|
|
591
|
-
validation.violations.push({
|
|
592
|
-
severity: 'CRITICAL',
|
|
593
|
-
message: 'Breaking changes require major version bump',
|
|
594
|
-
expected: `v${current.major + 1}.0.0`,
|
|
595
|
-
actual: proposedVersion
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
if (required.type === 'MINOR' && (proposed.major === current.major && proposed.minor <= current.minor)) {
|
|
600
|
-
validation.violations.push({
|
|
601
|
-
severity: 'HIGH',
|
|
602
|
-
message: 'New features require minor version bump',
|
|
603
|
-
expected: `v${current.major}.${current.minor + 1}.0`,
|
|
604
|
-
actual: proposedVersion
|
|
605
|
-
});
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
validation.valid = validation.violations.length === 0;
|
|
609
|
-
|
|
610
|
-
return validation;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
calculateRequiredVersionBump(changes) {
|
|
614
|
-
if (changes.breaking.length > 0) {
|
|
615
|
-
return {
|
|
616
|
-
type: 'MAJOR',
|
|
617
|
-
reason: 'Breaking changes detected',
|
|
618
|
-
recommendedVersion: this.bumpMajor(changes.currentVersion)
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
if (changes.nonBreaking.some(c => c.type.includes('ADDED'))) {
|
|
623
|
-
return {
|
|
624
|
-
type: 'MINOR',
|
|
625
|
-
reason: 'New features added',
|
|
626
|
-
recommendedVersion: this.bumpMinor(changes.currentVersion)
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
return {
|
|
631
|
-
type: 'PATCH',
|
|
632
|
-
reason: 'Bug fixes only',
|
|
633
|
-
recommendedVersion: this.bumpPatch(changes.currentVersion)
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
### 4. Contract Diffing
|
|
640
|
-
|
|
641
|
-
Generates detailed diffs between API contract versions with visual representation.
|
|
642
|
-
|
|
643
|
-
**Contract Diff Visualization:**
|
|
644
|
-
```diff
|
|
645
|
-
# API Contract Diff: v2.4.0 → v2.5.0
|
|
646
|
-
|
|
647
|
-
## Breaking Changes (2)
|
|
648
|
-
|
|
649
|
-
### GET /api/users/{id}
|
|
650
|
-
Response Schema (200):
|
|
651
|
-
- ❌ REMOVED required field: username (string)
|
|
652
|
-
+ ✅ ADDED optional field: profilePicture (string, format: url)
|
|
653
|
-
~ MODIFIED field: email (added format validation)
|
|
654
|
-
|
|
655
|
-
### POST /api/orders
|
|
656
|
-
Request Parameters:
|
|
657
|
-
~ CHANGED type: quantity (integer → string) ⚠️ BREAKING
|
|
658
|
-
|
|
659
|
-
## Non-Breaking Changes (5)
|
|
660
|
-
|
|
661
|
-
### GET /api/products
|
|
662
|
-
+ ADDED optional parameter: sortBy (string, enum: [price, name, rating])
|
|
663
|
-
+ ADDED optional parameter: order (string, enum: [asc, desc])
|
|
664
|
-
|
|
665
|
-
### POST /api/users
|
|
666
|
-
Response Schema (201):
|
|
667
|
-
+ ADDED field: createdAt (string, format: date-time)
|
|
668
|
-
+ ADDED field: lastLogin (string, format: date-time, nullable)
|
|
669
|
-
|
|
670
|
-
## Summary
|
|
671
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
672
|
-
🚨 Breaking Changes: 2
|
|
673
|
-
✅ Non-Breaking Changes: 5
|
|
674
|
-
📦 Recommended Version: v3.0.0 (major bump)
|
|
675
|
-
👥 Affected Consumers: 31
|
|
676
|
-
⏱️ Estimated Migration: 2-3 weeks
|
|
677
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
678
|
-
```
|
|
679
|
-
|
|
680
|
-
### 5. Consumer Impact Analysis
|
|
681
|
-
|
|
682
|
-
Analyzes which API consumers will be affected by changes.
|
|
683
|
-
|
|
684
|
-
**Consumer Impact Analyzer:**
|
|
685
|
-
```javascript
|
|
686
|
-
class ConsumerImpactAnalyzer {
|
|
687
|
-
async analyzeImpact(changes, consumers) {
|
|
688
|
-
const impacts = [];
|
|
689
|
-
|
|
690
|
-
for (const consumer of consumers) {
|
|
691
|
-
const affectedEndpoints = [];
|
|
692
|
-
|
|
693
|
-
// Check which endpoints this consumer uses
|
|
694
|
-
for (const usage of consumer.apiUsage) {
|
|
695
|
-
const endpointChanges = changes.breaking.filter(c =>
|
|
696
|
-
c.endpoint === usage.endpoint && c.method === usage.method
|
|
697
|
-
);
|
|
698
|
-
|
|
699
|
-
if (endpointChanges.length > 0) {
|
|
700
|
-
affectedEndpoints.push({
|
|
701
|
-
endpoint: usage.endpoint,
|
|
702
|
-
method: usage.method,
|
|
703
|
-
requestsPerDay: usage.requestsPerDay,
|
|
704
|
-
changes: endpointChanges,
|
|
705
|
-
migrationEffort: this.estimateMigrationEffort(endpointChanges)
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
if (affectedEndpoints.length > 0) {
|
|
711
|
-
impacts.push({
|
|
712
|
-
consumer: consumer.name,
|
|
713
|
-
team: consumer.team,
|
|
714
|
-
contact: consumer.contact,
|
|
715
|
-
affectedEndpoints: affectedEndpoints,
|
|
716
|
-
totalRequests: affectedEndpoints.reduce((sum, e) => sum + e.requestsPerDay, 0),
|
|
717
|
-
estimatedMigrationTime: this.calculateMigrationTime(affectedEndpoints),
|
|
718
|
-
priority: this.calculatePriority(consumer, affectedEndpoints)
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
return {
|
|
724
|
-
totalAffectedConsumers: impacts.length,
|
|
725
|
-
impacts: impacts.sort((a, b) => b.priority - a.priority),
|
|
726
|
-
coordinationRequired: impacts.length > 5,
|
|
727
|
-
estimatedTotalMigrationTime: this.sumMigrationTimes(impacts)
|
|
728
|
-
};
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
```
|
|
732
|
-
|
|
733
|
-
**Consumer Impact Report:**
|
|
734
|
-
```json
|
|
735
|
-
{
|
|
736
|
-
"analysis": {
|
|
737
|
-
"baseline": "v2.4.0",
|
|
738
|
-
"candidate": "v2.5.0",
|
|
739
|
-
"breakingChanges": 2,
|
|
740
|
-
"affectedConsumers": 31
|
|
741
|
-
},
|
|
742
|
-
|
|
743
|
-
"topImpactedConsumers": [
|
|
744
|
-
{
|
|
745
|
-
"consumer": "Mobile App (iOS)",
|
|
746
|
-
"team": "Mobile Engineering",
|
|
747
|
-
"contact": "mobile-team@company.com",
|
|
748
|
-
"affectedEndpoints": [
|
|
749
|
-
{
|
|
750
|
-
"endpoint": "GET /api/users/{id}",
|
|
751
|
-
"method": "GET",
|
|
752
|
-
"requestsPerDay": 450000,
|
|
753
|
-
"changes": [
|
|
754
|
-
{
|
|
755
|
-
"type": "REQUIRED_FIELD_REMOVED",
|
|
756
|
-
"field": "username",
|
|
757
|
-
"severity": "CRITICAL"
|
|
758
|
-
}
|
|
759
|
-
],
|
|
760
|
-
"migrationEffort": "HIGH"
|
|
761
|
-
}
|
|
762
|
-
],
|
|
763
|
-
"totalRequests": 450000,
|
|
764
|
-
"estimatedMigrationTime": "1 week",
|
|
765
|
-
"priority": "CRITICAL"
|
|
766
|
-
},
|
|
767
|
-
{
|
|
768
|
-
"consumer": "Partner Integration (Acme Corp)",
|
|
769
|
-
"team": "External",
|
|
770
|
-
"contact": "api@acmecorp.com",
|
|
771
|
-
"affectedEndpoints": [
|
|
772
|
-
{
|
|
773
|
-
"endpoint": "POST /api/orders",
|
|
774
|
-
"method": "POST",
|
|
775
|
-
"requestsPerDay": 120000,
|
|
776
|
-
"changes": [
|
|
777
|
-
{
|
|
778
|
-
"type": "PARAM_TYPE_CHANGED",
|
|
779
|
-
"param": "quantity",
|
|
780
|
-
"oldType": "integer",
|
|
781
|
-
"newType": "string"
|
|
782
|
-
}
|
|
783
|
-
],
|
|
784
|
-
"migrationEffort": "MEDIUM"
|
|
785
|
-
}
|
|
786
|
-
],
|
|
787
|
-
"totalRequests": 120000,
|
|
788
|
-
"estimatedMigrationTime": "3-5 days",
|
|
789
|
-
"priority": "HIGH"
|
|
790
|
-
}
|
|
791
|
-
],
|
|
792
|
-
|
|
793
|
-
"recommendation": {
|
|
794
|
-
"action": "COORDINATE_MIGRATION",
|
|
795
|
-
"suggestedApproach": "Phased rollout with versioned endpoints",
|
|
796
|
-
"timeline": [
|
|
797
|
-
"Week 1: Notify all affected consumers",
|
|
798
|
-
"Week 2-3: Consumer migrations",
|
|
799
|
-
"Week 4: Deploy v3.0.0 with deprecated v2 endpoints",
|
|
800
|
-
"Month 3: Sunset v2 endpoints"
|
|
801
|
-
],
|
|
802
|
-
"alternativeApproach": "Deploy v2.5.0 without breaking changes, defer to v3.0.0"
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
```
|
|
806
|
-
|
|
807
|
-
### 6. Contract Testing
|
|
808
|
-
|
|
809
|
-
Implements contract-first testing using Pact or similar frameworks.
|
|
810
|
-
|
|
811
|
-
**Contract Test Generator:**
|
|
812
|
-
```javascript
|
|
813
|
-
class ContractTestGenerator {
|
|
814
|
-
generatePactTest(apiSchema, consumer) {
|
|
815
|
-
const interactions = [];
|
|
816
|
-
|
|
817
|
-
for (const [path, methods] of Object.entries(apiSchema.paths)) {
|
|
818
|
-
for (const [method, operation] of Object.entries(methods)) {
|
|
819
|
-
interactions.push({
|
|
820
|
-
description: `${method.toUpperCase()} ${path}`,
|
|
821
|
-
providerState: operation['x-provider-state'] || 'default state',
|
|
822
|
-
request: this.generateRequest(path, method, operation),
|
|
823
|
-
response: this.generateResponse(operation)
|
|
824
|
-
});
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
return {
|
|
829
|
-
consumer: { name: consumer.name },
|
|
830
|
-
provider: { name: apiSchema.info.title },
|
|
831
|
-
interactions: interactions
|
|
832
|
-
};
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
generateRequest(path, method, operation) {
|
|
836
|
-
return {
|
|
837
|
-
method: method.toUpperCase(),
|
|
838
|
-
path: this.replacePathParams(path, operation.parameters),
|
|
839
|
-
query: this.generateQueryParams(operation.parameters),
|
|
840
|
-
headers: {
|
|
841
|
-
'Content-Type': 'application/json',
|
|
842
|
-
'Accept': 'application/json'
|
|
843
|
-
},
|
|
844
|
-
body: operation.requestBody ? this.generateExampleBody(operation.requestBody) : undefined
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
generateResponse(operation) {
|
|
849
|
-
const successResponse = operation.responses['200'] || operation.responses['201'];
|
|
850
|
-
|
|
851
|
-
return {
|
|
852
|
-
status: parseInt(Object.keys(operation.responses)[0]),
|
|
853
|
-
headers: {
|
|
854
|
-
'Content-Type': 'application/json'
|
|
855
|
-
},
|
|
856
|
-
body: this.generateExampleBody(successResponse)
|
|
857
|
-
};
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
```
|
|
861
|
-
|
|
862
|
-
### 7. Semantic Versioning Validation
|
|
863
|
-
|
|
864
|
-
Enforces semantic versioning rules across all API changes.
|
|
865
|
-
|
|
866
|
-
**Semver Validator:**
|
|
867
|
-
```javascript
|
|
868
|
-
class SemanticVersioningValidator {
|
|
869
|
-
validate(changes, versionBump) {
|
|
870
|
-
const rules = [
|
|
871
|
-
{
|
|
872
|
-
condition: (c) => c.breaking.length > 0,
|
|
873
|
-
requiredBump: 'major',
|
|
874
|
-
message: 'Breaking changes require major version bump'
|
|
875
|
-
},
|
|
876
|
-
{
|
|
877
|
-
condition: (c) => c.nonBreaking.some(nc => nc.type.includes('ADDED')),
|
|
878
|
-
requiredBump: 'minor',
|
|
879
|
-
message: 'New features require minor version bump'
|
|
880
|
-
},
|
|
881
|
-
{
|
|
882
|
-
condition: (c) => c.breaking.length === 0 && !c.nonBreaking.some(nc => nc.type.includes('ADDED')),
|
|
883
|
-
requiredBump: 'patch',
|
|
884
|
-
message: 'Bug fixes only require patch version bump'
|
|
885
|
-
}
|
|
886
|
-
];
|
|
887
|
-
|
|
888
|
-
for (const rule of rules) {
|
|
889
|
-
if (rule.condition(changes)) {
|
|
890
|
-
if (versionBump !== rule.requiredBump) {
|
|
891
|
-
return {
|
|
892
|
-
valid: false,
|
|
893
|
-
violation: rule.message,
|
|
894
|
-
required: rule.requiredBump,
|
|
895
|
-
actual: versionBump
|
|
896
|
-
};
|
|
897
|
-
}
|
|
898
|
-
return { valid: true, bump: rule.requiredBump };
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
return { valid: true, bump: 'patch' };
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
```
|
|
906
|
-
|
|
907
|
-
## Integration Points
|
|
908
|
-
|
|
909
|
-
### Upstream Dependencies
|
|
910
|
-
- **OpenAPI/Swagger**: API schema specifications
|
|
911
|
-
- **GraphQL**: GraphQL schemas
|
|
912
|
-
- **Git**: Schema version history
|
|
913
|
-
- **API Gateways**: Consumer tracking
|
|
914
|
-
|
|
915
|
-
### Downstream Consumers
|
|
916
|
-
- **qe-deployment-readiness**: Blocks deployment on breaking changes
|
|
917
|
-
- **qe-test-generator**: Generates contract tests
|
|
918
|
-
- **CI/CD Pipelines**: Enforces contract validation
|
|
919
|
-
- **API Documentation**: Updates docs with changes
|
|
920
|
-
|
|
921
|
-
### Coordination Agents
|
|
922
|
-
- **qe-fleet-commander**: Orchestrates contract validation
|
|
923
|
-
- **qe-requirements-validator**: Validates API requirements
|
|
924
|
-
|
|
925
|
-
## Coordination Protocol
|
|
926
|
-
|
|
927
|
-
This agent uses **AQE hooks (Agentic QE native hooks)** for coordination (zero external dependencies, 100-500x faster).
|
|
928
|
-
|
|
929
|
-
**Automatic Lifecycle Hooks:**
|
|
930
|
-
```typescript
|
|
931
|
-
// Automatically called by BaseAgent
|
|
932
|
-
protected async onPreTask(data: { assignment: TaskAssignment }): Promise<void> {
|
|
933
|
-
// Load baseline contracts and schemas
|
|
934
|
-
const contracts = await this.memoryStore.retrieve('aqe/contracts/current');
|
|
935
|
-
const baseline = await this.memoryStore.retrieve('aqe/api-schemas/baseline');
|
|
936
|
-
this.logger.info('Loaded API contracts and baseline schemas');
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
protected async onPostTask(data: { assignment: TaskAssignment; result: any }): Promise<void> {
|
|
940
|
-
// Store validation results and breaking changes
|
|
941
|
-
await this.memoryStore.store('aqe/contracts/validation-result', data.result.validation);
|
|
942
|
-
await this.memoryStore.store('aqe/breaking-changes/detected', data.result.breakingChanges);
|
|
943
|
-
|
|
944
|
-
// Emit events for downstream agents
|
|
945
|
-
this.eventBus.emit('contract-validator:completed', {
|
|
946
|
-
breakingChanges: data.result.breakingChanges.length,
|
|
947
|
-
validationStatus: data.result.validation.passed
|
|
948
|
-
});
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
protected async onPostEdit(data: { filePath: string; changes: any }): Promise<void> {
|
|
952
|
-
// Track schema updates
|
|
953
|
-
const fileName = data.filePath.split('/').pop();
|
|
954
|
-
await this.memoryStore.store(`aqe/contracts/schema-updated/${fileName}`, {
|
|
955
|
-
timestamp: Date.now(),
|
|
956
|
-
changes: data.changes
|
|
957
|
-
});
|
|
958
|
-
}
|
|
959
|
-
```
|
|
960
|
-
|
|
961
|
-
**Advanced Verification (Optional):**
|
|
962
|
-
```typescript
|
|
963
|
-
const hookManager = new VerificationHookManager(this.memoryStore);
|
|
964
|
-
const verification = await hookManager.executePreTaskVerification({
|
|
965
|
-
task: 'contract-validation',
|
|
966
|
-
context: {
|
|
967
|
-
requiredVars: ['NODE_ENV', 'API_VERSION'],
|
|
968
|
-
minMemoryMB: 512,
|
|
969
|
-
requiredKeys: ['aqe/api-schemas/baseline']
|
|
970
|
-
}
|
|
971
|
-
});
|
|
972
|
-
```
|
|
973
|
-
|
|
974
|
-
## Memory Keys
|
|
975
|
-
|
|
976
|
-
### Input Keys
|
|
977
|
-
- `aqe/api-schemas/baseline` - Baseline API schemas
|
|
978
|
-
- `aqe/api-schemas/candidate` - New API schemas
|
|
979
|
-
- `aqe/contracts/current` - Current contract specifications
|
|
980
|
-
- `aqe/consumers/registry` - API consumer registry
|
|
981
|
-
|
|
982
|
-
### Output Keys
|
|
983
|
-
- `aqe/contracts/validation-result` - Contract validation results
|
|
984
|
-
- `aqe/breaking-changes/detected` - Detected breaking changes
|
|
985
|
-
- `aqe/consumer-impact/analysis` - Consumer impact analysis
|
|
986
|
-
- `aqe/compatibility/report` - Compatibility assessment
|
|
987
|
-
|
|
988
|
-
### Coordination Keys
|
|
989
|
-
- `aqe/contracts/status` - Validation status
|
|
990
|
-
- `aqe/contracts/alerts` - Critical contract violations
|
|
991
|
-
|
|
992
|
-
## Use Cases
|
|
993
|
-
|
|
994
|
-
### Use Case 1: Pre-Deployment Contract Validation
|
|
995
|
-
|
|
996
|
-
**Scenario**: Validate API changes before deploying to production.
|
|
997
|
-
|
|
998
|
-
**Workflow:**
|
|
999
|
-
```bash
|
|
1000
|
-
# Compare schemas
|
|
1001
|
-
aqe contract compare --baseline v2.4.0 --candidate v2.5.0
|
|
1002
|
-
|
|
1003
|
-
# Detect breaking changes
|
|
1004
|
-
aqe contract breaking-changes --output breaking-changes.json
|
|
1005
|
-
|
|
1006
|
-
# Analyze consumer impact
|
|
1007
|
-
aqe contract consumer-impact --consumers consumer-registry.json
|
|
1008
|
-
|
|
1009
|
-
# Generate migration guide
|
|
1010
|
-
aqe contract migration-guide --output migration-guide.md
|
|
1011
|
-
|
|
1012
|
-
# Validate version bump
|
|
1013
|
-
aqe contract validate-version --current 2.4.0 --proposed 2.5.0
|
|
1014
|
-
```
|
|
1015
|
-
|
|
1016
|
-
### Use Case 2: Contract-First Development
|
|
1017
|
-
|
|
1018
|
-
**Scenario**: Generate contract tests from OpenAPI spec.
|
|
1019
|
-
|
|
1020
|
-
**Workflow:**
|
|
1021
|
-
```bash
|
|
1022
|
-
# Generate Pact contract tests
|
|
1023
|
-
aqe contract generate-pact --spec openapi.yaml --consumer mobile-app
|
|
1024
|
-
|
|
1025
|
-
# Run contract tests
|
|
1026
|
-
aqe contract test --provider user-service --consumer mobile-app
|
|
1027
|
-
|
|
1028
|
-
# Publish contract
|
|
1029
|
-
aqe contract publish --broker https://pact-broker.company.com
|
|
1030
|
-
```
|
|
1031
|
-
|
|
1032
|
-
### Use Case 3: Consumer Notification
|
|
1033
|
-
|
|
1034
|
-
**Scenario**: Notify affected consumers of API changes.
|
|
1035
|
-
|
|
1036
|
-
**Workflow:**
|
|
1037
|
-
```bash
|
|
1038
|
-
# Analyze impact
|
|
1039
|
-
aqe contract consumer-impact --baseline v2.4.0 --candidate v2.5.0
|
|
1040
|
-
|
|
1041
|
-
# Generate notification emails
|
|
1042
|
-
aqe contract notify-consumers --template email-template.html
|
|
1043
|
-
|
|
1044
|
-
# Track migration progress
|
|
1045
|
-
aqe contract migration-status --version v3.0.0
|
|
1046
|
-
```
|
|
1047
|
-
|
|
1048
|
-
## Success Metrics
|
|
1049
|
-
|
|
1050
|
-
### Prevention Metrics
|
|
1051
|
-
- **Breaking Changes Prevented**: 95%
|
|
1052
|
-
- **Consumer Incidents**: 90% reduction
|
|
1053
|
-
- **Integration Failures**: 85% reduction
|
|
1054
|
-
|
|
1055
|
-
### Quality Metrics
|
|
1056
|
-
- **Contract Compliance**: 100%
|
|
1057
|
-
- **Semantic Versioning Compliance**: 100%
|
|
1058
|
-
- **Consumer Satisfaction**: 4.8/5
|
|
1059
|
-
|
|
1060
|
-
## Commands
|
|
1061
|
-
|
|
1062
|
-
### Basic Commands
|
|
1063
|
-
|
|
1064
|
-
```bash
|
|
1065
|
-
# Compare API schemas
|
|
1066
|
-
aqe contract compare --baseline <version> --candidate <version>
|
|
1067
|
-
|
|
1068
|
-
# Detect breaking changes
|
|
1069
|
-
aqe contract breaking-changes --spec <openapi-file>
|
|
1070
|
-
|
|
1071
|
-
# Validate contract
|
|
1072
|
-
aqe contract validate --spec <openapi-file>
|
|
1073
|
-
|
|
1074
|
-
# Generate diff report
|
|
1075
|
-
aqe contract diff --baseline <v1> --candidate <v2> --output diff.html
|
|
1076
|
-
|
|
1077
|
-
# Check semantic versioning
|
|
1078
|
-
aqe contract semver-check --current <version> --proposed <version>
|
|
1079
|
-
```
|
|
1080
|
-
|
|
1081
|
-
### Advanced Commands
|
|
1082
|
-
|
|
1083
|
-
```bash
|
|
1084
|
-
# Consumer impact analysis
|
|
1085
|
-
aqe contract consumer-impact --consumers <registry> --changes <changes-file>
|
|
1086
|
-
|
|
1087
|
-
# Generate Pact tests
|
|
1088
|
-
aqe contract generate-pact --spec <openapi> --consumer <name>
|
|
1089
|
-
|
|
1090
|
-
# Run contract tests
|
|
1091
|
-
aqe contract test --provider <service> --consumer <app>
|
|
1092
|
-
|
|
1093
|
-
# Migration guide generation
|
|
1094
|
-
aqe contract migration-guide --baseline <v1> --candidate <v2>
|
|
1095
|
-
|
|
1096
|
-
# Notify consumers
|
|
1097
|
-
aqe contract notify-consumers --changes <changes-file> --template <email-template>
|
|
1098
|
-
```
|
|
1099
|
-
|
|
1100
|
-
### Specialized Commands
|
|
1101
|
-
|
|
1102
|
-
```bash
|
|
1103
|
-
# GraphQL schema validation
|
|
1104
|
-
aqe contract validate-graphql --schema schema.graphql
|
|
1105
|
-
|
|
1106
|
-
# API versioning strategy
|
|
1107
|
-
aqe contract versioning-strategy --analyze-history --days 180
|
|
1108
|
-
|
|
1109
|
-
# Consumer compatibility matrix
|
|
1110
|
-
aqe contract compatibility-matrix --output matrix.html
|
|
1111
|
-
|
|
1112
|
-
# Deprecation timeline
|
|
1113
|
-
aqe contract deprecation-timeline --version <v2> --sunset-date <date>
|
|
1114
|
-
|
|
1115
|
-
# Contract evolution report
|
|
1116
|
-
aqe contract evolution --from <v1> --to <v2> --format pdf
|
|
1117
|
-
```
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
**Agent Status**: Production Ready
|
|
1121
|
-
**Last Updated**: 2025-09-30
|
|
1122
|
-
**Version**: 1.0.0
|
|
1123
|
-
**Maintainer**: AQE Fleet Team
|