chore: upgrade BMAD framework to skill-based architecture
Migrates from slash-command files (.claude/commands, .cursor/commands) to the new skill-based architecture with workflow step files.
This commit is contained in:
@@ -714,4 +714,4 @@ Before deploying your CI pipeline, verify:
|
||||
- Related fragments: `selective-testing.md`, `playwright-config.md`, `test-quality.md`
|
||||
- CI tools: GitHub Actions, GitLab CI, CircleCI, Jenkins
|
||||
|
||||
_Source: Murat CI/CD strategy blog, Playwright/Cypress workflow examples, SEON production pipelines_
|
||||
_Source: Murat CI/CD strategy blog, Playwright/Cypress workflow examples, enterprise production pipelines_
|
||||
|
||||
@@ -944,6 +944,67 @@ jobs:
|
||||
|
||||
---
|
||||
|
||||
## Provider Scrutiny Protocol
|
||||
|
||||
When generating consumer contract tests, the agent **MUST** analyze provider source code — or the provider's OpenAPI/Swagger spec — before writing any Pact interaction. Generating contracts from consumer-side assumptions alone leads to mismatches that only surface during provider verification — wrong response shapes, wrong status codes, wrong field names, wrong types, missing required fields, and wrong enum values.
|
||||
|
||||
**Source priority**: Provider source code is the most authoritative reference. When an OpenAPI/Swagger spec exists (`openapi.yaml`, `openapi.json`, `swagger.json`), use it as a complementary or alternative source — it documents the provider's contract explicitly and can be faster to parse than tracing through handler code. When both exist, cross-reference them; if they disagree, the source code wins.
|
||||
|
||||
### Provider Endpoint Comment
|
||||
|
||||
Every Pact interaction MUST include a provider endpoint comment immediately above the `.given()` call:
|
||||
|
||||
```typescript
|
||||
// Provider endpoint: server/src/routes/userRouteHandlers.ts -> GET /api/v2/users/:userId
|
||||
await provider.given('user with id 1 exists').uponReceiving('a request for user 1');
|
||||
```
|
||||
|
||||
**Format**: `// Provider endpoint: <relative-path-to-handler> -> <METHOD> <route-pattern>`
|
||||
|
||||
If the provider source is not accessible, use: `// Provider endpoint: TODO — provider source not accessible, verify manually`
|
||||
|
||||
### Seven-Point Scrutiny Checklist
|
||||
|
||||
Before generating each Pact interaction, read the provider route handler and/or OpenAPI spec and verify:
|
||||
|
||||
| # | Check | What to Read (source code / OpenAPI spec) | Common Mismatch |
|
||||
| --- | --------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------- |
|
||||
| 1 | **Response shape** | Handler's `res.json()` calls / OpenAPI `responses.content.schema` | Nested object vs flat; array wrapper vs direct |
|
||||
| 2 | **Status codes** | Handler's `res.status()` calls / OpenAPI `responses` keys | 200 vs 201 for creation; 204 vs 200 for delete |
|
||||
| 3 | **Field names** | Response type/DTO definitions / OpenAPI `schema.properties` | `transaction_id` vs `transactionId`; `fraud_score` vs `score` |
|
||||
| 4 | **Enum values** | Validation schemas, constants / OpenAPI `schema.enum` | `"active"` vs `"ACTIVE"`; `"pending"` vs `"in_progress"` |
|
||||
| 5 | **Required fields** | Request validation (Joi, Zod) / OpenAPI `schema.required` | Missing required header; optional field assumed required |
|
||||
| 6 | **Data types** | TypeScript types, DB models / OpenAPI `schema.type` + `format` | `string` ID vs `number` ID; ISO date vs Unix timestamp |
|
||||
| 7 | **Nested structures** | Response builder, serializer / OpenAPI `$ref` + `allOf`/`oneOf` | `{ data: { items: [] } }` vs `{ items: [] }` |
|
||||
|
||||
### Scrutiny Evidence Block
|
||||
|
||||
Document what was found from provider source and/or OpenAPI spec as a block comment in the test file:
|
||||
|
||||
```typescript
|
||||
/*
|
||||
* Provider Scrutiny Evidence:
|
||||
* - Handler: server/src/routes/userRouteHandlers.ts:45
|
||||
* - OpenAPI: server/openapi.yaml paths./api/v2/users/{userId}.get (if available)
|
||||
* - Response type: UserResponseDto (server/src/types/user.ts:12)
|
||||
* - Status: 200 (line 52), 404 (line 48)
|
||||
* - Fields: { id: number, name: string, email: string, role: "user" | "admin", createdAt: string }
|
||||
* - Required request headers: Authorization (Bearer token)
|
||||
* - Validation: Zod schema at server/src/validation/user.ts:8
|
||||
*/
|
||||
```
|
||||
|
||||
### Graceful Degradation
|
||||
|
||||
When provider source code is not accessible (different repo, no access, closed source):
|
||||
|
||||
1. **OpenAPI/Swagger spec available**: Use the spec as the source of truth for response shapes, status codes, and field names
|
||||
2. **Pact Broker has existing contracts**: Use `pact_mcp` tools to fetch existing provider states and verified interactions as reference
|
||||
3. **Neither available**: Generate contracts from consumer-side types but use the TODO form of the mandatory comment: `// Provider endpoint: TODO — provider source not accessible, verify manually` and add a `provider_scrutiny: "pending"` field to the output JSON
|
||||
4. **Never silently guess**: If you cannot verify, document what you assumed and why
|
||||
|
||||
---
|
||||
|
||||
## Contract Testing Checklist
|
||||
|
||||
Before implementing contract testing, verify:
|
||||
@@ -956,6 +1017,9 @@ Before implementing contract testing, verify:
|
||||
- [ ] **Webhooks configured**: Consumer changes trigger provider verification
|
||||
- [ ] **Retention policy**: Old pacts archived (keep 30 days, all production tags)
|
||||
- [ ] **Resilience tested**: Timeouts, retries, error codes in contracts
|
||||
- [ ] **Provider endpoint comments**: Every Pact interaction has `// Provider endpoint:` comment
|
||||
- [ ] **Provider scrutiny completed**: Seven-point checklist verified for each interaction
|
||||
- [ ] **Scrutiny evidence documented**: Block comment with handler, types, status codes, and fields
|
||||
|
||||
## Integration Points
|
||||
|
||||
|
||||
@@ -722,4 +722,4 @@ Before shipping error handling code, verify:
|
||||
- Related fragments: `network-first.md`, `test-quality.md`, `contract-testing.md`
|
||||
- Monitoring tools: Sentry, Datadog, LogRocket
|
||||
|
||||
_Source: Murat error-handling patterns, Pact resilience guidance, SEON production error handling_
|
||||
_Source: Murat error-handling patterns, Pact resilience guidance, enterprise production error handling_
|
||||
|
||||
@@ -747,4 +747,4 @@ Before merging flag-related code, verify:
|
||||
- Related fragments: `test-quality.md`, `selective-testing.md`
|
||||
- Flag services: LaunchDarkly, Split.io, Unleash, custom implementations
|
||||
|
||||
_Source: LaunchDarkly strategy blog, Murat test architecture notes, SEON feature flag governance_
|
||||
_Source: LaunchDarkly strategy blog, Murat test architecture notes, enterprise feature flag governance_
|
||||
|
||||
@@ -398,4 +398,4 @@ When deciding whether to create a fixture, follow these rules:
|
||||
- **1 use** → Keep inline (avoid premature abstraction)
|
||||
- **Complex logic** → Factory function pattern (dynamic data generation)
|
||||
|
||||
_Source: Murat Testing Philosophy (lines 74-122), SEON production patterns, Playwright fixture docs._
|
||||
_Source: Murat Testing Philosophy (lines 74-122), enterprise production patterns, Playwright fixture docs._
|
||||
|
||||
@@ -304,13 +304,13 @@ await networkRecorder.setup(context, {
|
||||
playback: {
|
||||
urlMapping: {
|
||||
hostMapping: {
|
||||
'localhost:3000': 'admin.seondev.space',
|
||||
'admin-staging.seon.io': 'admin.seondev.space',
|
||||
'admin.seon.io': 'admin.seondev.space',
|
||||
'localhost:3000': 'admin.example.com',
|
||||
'admin-staging.example.com': 'admin.example.com',
|
||||
'admin.example.com': 'admin.example.com',
|
||||
},
|
||||
patterns: [
|
||||
{ match: /admin-\d+\.seondev\.space/, replace: 'admin.seondev.space' },
|
||||
{ match: /admin-staging-pr-\w+-\d\.seon\.io/, replace: 'admin.seondev.space' },
|
||||
{ match: /admin-\d+\.example\.com/, replace: 'admin.example.com' },
|
||||
{ match: /admin-staging-pr-\w+-\d\.example\.com/, replace: 'admin.example.com' },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@ Writing Playwright utilities from scratch for every project leads to:
|
||||
|
||||
`@seontechnologies/playwright-utils` provides:
|
||||
|
||||
- **Production-tested utilities**: Used at SEON Technologies in production
|
||||
- **Production-tested**: Used in enterprise production environments
|
||||
- **Functional-first design**: Core logic as pure functions, fixtures for convenience
|
||||
- **Composable fixtures**: Use `mergeTests` to combine utilities
|
||||
- **TypeScript support**: Full type safety with generic types
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
Inject the Pact mock server URL into consumer code via an optional `baseUrl` field on the API context type instead of using raw `fetch()` inside `executeTest()`. This ensures contract tests exercise the real consumer HTTP client — including retry logic, header assembly, timeout configuration, error handling, and metrics — rather than testing Pact itself.
|
||||
|
||||
The base URL is typically a module-level constant evaluated at import time (`export const API_BASE_URL = env.SEON_API_URL`), but `mockServer.url` is only available at runtime inside `executeTest()`. Dependency injection solves this timing mismatch cleanly: add one optional field to the context type, use nullish coalescing in the HTTP client factory, and inject the mock server URL in tests.
|
||||
The base URL is typically a module-level constant evaluated at import time (`export const API_BASE_URL = env.API_BASE_URL`), but `mockServer.url` is only available at runtime inside `executeTest()`. Dependency injection solves this timing mismatch cleanly: add one optional field to the context type, use nullish coalescing in the HTTP client factory, and inject the mock server URL in tests.
|
||||
|
||||
## Rationale
|
||||
|
||||
@@ -124,7 +124,7 @@ export function createTestContext(mockServerUrl: string): ApiContext {
|
||||
|
||||
```typescript
|
||||
.executeTest(async (mockServer: V3MockServer) => {
|
||||
const api = createSeonApi(createTestContext(mockServer.url));
|
||||
const api = createApiClient(createTestContext(mockServer.url));
|
||||
const result = await api.getFilterFields();
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
@@ -277,7 +277,7 @@ expect(response.status).toBe(200);
|
||||
|
||||
```typescript
|
||||
// GOOD: Exercises real client, validates parsed return value
|
||||
const api = createSeonApi(createTestContext(mockServer.url));
|
||||
const api = createApiClient(createTestContext(mockServer.url));
|
||||
const result = await api.searchTransactions(request);
|
||||
expect(result.transactions).toBeDefined();
|
||||
```
|
||||
@@ -307,4 +307,4 @@ Used in workflows:
|
||||
|
||||
## Source
|
||||
|
||||
Pattern derived from seon-mcp-server Pact consumer test refactor (March 2026). Implements dependency injection for testability as described in Pact.js best practices.
|
||||
Pattern derived from my-consumer-app Pact consumer test refactor (March 2026). Implements dependency injection for testability as described in Pact.js best practices.
|
||||
|
||||
@@ -727,4 +727,4 @@ jobs:
|
||||
- [ ] Projects defined for cross-browser/device testing (if needed)
|
||||
- [ ] CI uploads artifacts on failure with 30-day retention
|
||||
|
||||
_Source: Playwright book repo, SEON configuration example, Murat testing philosophy (lines 216-271)._
|
||||
_Source: Playwright book repo, enterprise configuration example, Murat testing philosophy (lines 216-271)._
|
||||
|
||||
@@ -612,4 +612,4 @@ Before deploying to production, ensure:
|
||||
- **Related fragments**: `probability-impact.md` (scoring definitions), `test-priorities-matrix.md` (P0-P3 classification), `nfr-criteria.md` (non-functional risks)
|
||||
- **Tools**: Risk tracking dashboards (Jira, Linear), gate automation (CI/CD), traceability reports (Markdown, Confluence)
|
||||
|
||||
_Source: Murat risk governance notes, gate schema guidance, SEON production gate workflows, ISO 31000 risk management standards_
|
||||
_Source: Murat risk governance notes, gate schema guidance, enterprise production gate workflows, ISO 31000 risk management standards_
|
||||
|
||||
@@ -728,5 +728,5 @@ Before implementing selective testing, verify:
|
||||
- Related fragments: `ci-burn-in.md`, `test-priorities-matrix.md`, `test-quality.md`
|
||||
- Selection tools: Playwright --grep, Cypress @cypress/grep, git diff
|
||||
|
||||
_Source: 32+ selective testing strategies blog, Murat testing philosophy, SEON CI optimization_
|
||||
_Source: 32+ selective testing strategies blog, Murat testing philosophy, enterprise CI optimization_
|
||||
```
|
||||
|
||||
@@ -521,4 +521,4 @@ Before deploying tests to CI, ensure:
|
||||
- **Related fragments**: `playwright-config.md` (artifact configuration), `ci-burn-in.md` (CI artifact upload), `test-quality.md` (debugging best practices)
|
||||
- **Tools**: Playwright Trace Viewer, Cypress Debug UI, axe-core, HAR files
|
||||
|
||||
_Source: Playwright official docs, Murat testing philosophy (visual debugging manifesto), SEON production debugging patterns_
|
||||
_Source: Playwright official docs, Murat testing philosophy (visual debugging manifesto), enterprise production debugging patterns_
|
||||
|
||||
Reference in New Issue
Block a user