diff --git a/.coderifts.yml b/.coderifts.yml index 70b1a9a..046c2aa 100644 --- a/.coderifts.yml +++ b/.coderifts.yml @@ -1,15 +1,13 @@ schema: - api/openapi.yaml - fail_on_breaking: true - +comment_mode: full policy: max_breaking_changes: 3 no_delete_endpoints: true no_delete_required_fields: true require_deprecation_before_removal: true require_version_bump_on_breaking: true - domains: - name: payments paths: ["/payments/*"] @@ -22,24 +20,24 @@ domains: - name: webhooks paths: ["/webhooks/*"] sensitivity: webhook - app_versions: - name: "iOS 3.2" api_version: "v1" - name: "Android 4.0" api_version: "v1" - approval_matrix: required_field_removal: architect_approval response_type_change: senior_review critical_domain_breaking: cto_approval - freeze_periods: - start: "2026-11-25" end: "2026-12-02" reason: "Black Friday" - docs_paths: - "docs/*" - "README.md" fun_mode: true +notifications: + slack: + webhook_url: "https://hooks.slack.com/services/test/test/test" + events: [block] diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..18f42dd --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,2 @@ +# agent-native JSON block verification - 06:44:14 +# top_pattern verify - 07:26:34 diff --git a/README.md b/README.md index 14b7144..340dbf0 100644 --- a/README.md +++ b/README.md @@ -33,3 +33,15 @@ Full integration docs: [coderifts.com/integrations/](https://coderifts.com/integ - [Integrations](https://coderifts.com/integrations/) - [Documentation](https://coderifts.com/docs/) - [Pricing](https://coderifts.com/pricing/) + +# Policy verification trigger - 2026-03-14T22:06:34Z +# Policy webhook fix verification - 2026-03-14T22:12:54Z +# Policy fix deployed - 2026-03-14T22:16:26Z +# v23 deployed - 2026-03-14T22:21:06Z +# debug logging - 2026-03-14T22:24:58Z +# ledger fix deployed - 2026-03-14T22:31:16Z +# final verification - 2026-03-14T22:35:22Z +# debug marker test - 2026-03-14T22:42:37Z +# enhanced debug - 2026-03-14T22:46:58Z +# error debug - 2026-03-14T22:51:38Z +# lint fix + policy fix - 2026-03-14T22:59:21Z diff --git a/api/openapi.yaml b/api/openapi.yaml index 78a8673..ce7e1eb 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1,20 +1,26 @@ openapi: "3.0.3" info: - title: Acme API - description: "The Acme API provides programmatic access to user management, order processing, payment handling, and webhook integrations for the Acme platform." - version: "1.4.0" + title: Acme E-Commerce API + version: "2.0.0" + description: "Public API for the Acme e-commerce platform. Provides user management, order processing, and payment handling." contact: - name: Acme API Team + name: API Team email: api@acme.example.com - url: https://developer.acme.example.com license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0 + name: MIT + url: https://opensource.org/licenses/MIT +servers: + - url: https://api.acme.example.com + description: Production +security: + - bearerAuth: [] + - oauth2: [users:admin] paths: + # ── KEPT from base, with field-level changes ────────────────────── /users/{id}: get: summary: Get user by ID - description: "Retrieves a single user record by their unique identifier. Returns the full user profile including contact information and account metadata." + description: "Retrieves a single user by their unique identifier." operationId: getUser tags: - Users @@ -24,30 +30,28 @@ paths: - name: id in: path required: true - description: "The unique identifier of the user to retrieve." schema: type: string + description: "The unique user identifier." responses: "200": - description: User found + description: User details content: application/json: schema: $ref: "#/components/schemas/User" example: - id: "usr_abc123" - email: "jane@example.com" - name: "Jane Doe" - phone: "+1-555-0100" - created_at: "2025-01-15T10:30:00Z" + id: "usr_001" + email: "alice@example.com" + username: "alice" + role: "admin" "404": description: User not found - "401": - description: Unauthorized — missing or invalid bearer token + # REMOVED: "401" response that existed in base → Structural /users: post: summary: Create user - description: "Creates a new user account in the Acme platform. Requires a valid email address and display name. Returns the created user with a generated ID." + description: "Creates a new user account. Requires email, name, and email_verified (newly required)." operationId: createUser tags: - Users @@ -55,15 +59,14 @@ paths: - bearerAuth: [] requestBody: required: true - description: "The user details for account creation." content: application/json: schema: $ref: "#/components/schemas/CreateUserRequest" example: - email: "jane@example.com" - name: "Jane Doe" - phone: "+1-555-0100" + email: "bob@example.com" + name: "Bob Smith" + email_verified: false responses: "201": description: User created successfully @@ -74,11 +77,11 @@ paths: "400": description: Invalid request body "409": - description: Email already exists + description: Email already registered /orders: get: summary: List orders - description: "Returns a paginated list of all orders for the authenticated account. Orders are sorted by creation date in descending order." + description: "Returns all orders, optionally filtered by status." operationId: listOrders tags: - Orders @@ -97,7 +100,7 @@ paths: description: Unauthorized post: summary: Create order - description: "Creates a new order with the specified line items. The order total is calculated server-side from item prices and quantities." + description: "Creates a new order for a user. Requires at least one item." operationId: createOrder tags: - Orders @@ -105,17 +108,10 @@ paths: - bearerAuth: [] requestBody: required: true - description: "The order details including user ID and line items." content: application/json: schema: $ref: "#/components/schemas/CreateOrderRequest" - example: - user_id: "usr_abc123" - items: - - product_id: "prod_001" - quantity: 2 - price: 29.99 responses: "201": description: Order created @@ -128,7 +124,7 @@ paths: /orders/{id}: get: summary: Get order by ID - description: "Retrieves a single order by its unique identifier, including all line items, payment status, and shipping information." + description: "Retrieves a single order by its unique identifier." operationId: getOrder tags: - Orders @@ -153,52 +149,44 @@ paths: /payments/charge: post: summary: Charge payment - description: "Processes a payment charge for the specified order. Supports credit card and bank transfer payment methods. Returns a transaction ID on success." + description: "Processes a payment charge for an order. Auth downgraded from bearer+OAuth2 to API key only." operationId: chargePayment tags: - Payments + # SECURITY CHANGE: was bearerAuth + oauth2, now apiKey only → Security security: - - bearerAuth: [] - - oauth2: [payments:write] + - apiKey: [] requestBody: required: true - description: "The payment charge details including order ID, amount, and currency." content: application/json: schema: $ref: "#/components/schemas/ChargeRequest" - example: - order_id: "ord_xyz789" - amount: 59.98 - currency: "USD" responses: "200": - description: Payment processed successfully + description: Payment processed content: application/json: schema: $ref: "#/components/schemas/PaymentResult" "402": - description: Payment declined - "422": - description: Invalid payment data - /payments/refund: + description: Payment failed + # ── REMOVED from base (path removals) ───────────────────────────── + # /payments/refund → REMOVED (Structural, covered by exception EXC-002) + # /internal/health → REMOVED (Structural, covered by exception EXC-003) + # ── NEW endpoints (not in base — non-breaking additions) ────────── + /payments/v2/refund: post: - summary: Refund payment - description: "Initiates a refund for a previously completed transaction. Partial refunds are supported by specifying an amount less than the original charge." - operationId: refundPayment + summary: Refund payment (v2) + description: "New refund endpoint replacing the deprecated /payments/refund. Supports partial and full refunds with improved error handling." + operationId: refundPaymentV2 tags: - Payments - deprecated: true - x-deprecated-date: "2025-12-01" - x-sunset-date: "2026-04-01" - x-deprecated-replacement: "POST /payments/v2/refund" security: - bearerAuth: [] - oauth2: [payments:write] requestBody: required: true - description: "The refund request details." content: application/json: schema: @@ -208,10 +196,39 @@ paths: description: Refund processed "404": description: Transaction not found + "422": + description: Invalid refund amount + /v1/legacy/status: + get: + summary: Legacy status endpoint + description: "Returns system status. This endpoint is deprecated and will be removed in a future version." + operationId: legacyStatus + deprecated: true + x-deprecated-date: "2026-01-15" + x-sunset-date: "2026-07-15" + x-deprecated-replacement: "GET /internal/health" + tags: + - Internal + security: + - apiKey: [] + responses: + "200": + description: Status response + content: + application/json: + schema: + type: object + properties: + status: + type: string + description: "Current system status." + uptime: + type: integer + description: "System uptime in seconds." /webhooks/subscribe: post: summary: Subscribe to webhooks - description: "Registers a webhook endpoint to receive real-time notifications for specified event types. Supports order, payment, and user events." + description: "Register a URL to receive webhook notifications for order and payment events." operationId: subscribeWebhook tags: - Webhooks @@ -219,44 +236,32 @@ paths: - bearerAuth: [] requestBody: required: true - description: "The webhook subscription details including callback URL and event types." content: application/json: schema: type: object required: - url - - events properties: url: type: string - description: "The HTTPS callback URL to receive webhook payloads." - events: - type: array - description: "List of event types to subscribe to." - items: - type: string + description: "The HTTPS URL to receive webhook events." + # REMOVED: 'events' property that was required in base → Structural responses: "201": - description: Webhook subscription created + description: Subscribed "400": - description: Invalid webhook URL or events - /internal/health: - get: - summary: Health check - description: "Returns the current health status of the API. Used for monitoring and load balancer health checks." - operationId: healthCheck - tags: - - Internal - responses: - "200": - description: Service is healthy + description: Invalid URL components: securitySchemes: bearerAuth: type: http scheme: bearer - description: "JWT bearer token for API authentication." + apiKey: + type: apiKey + name: X-API-Key + in: header + description: "API key for legacy and payment endpoints." oauth2: type: oauth2 description: "OAuth 2.0 authorization for sensitive operations." @@ -266,16 +271,16 @@ components: tokenUrl: https://auth.acme.example.com/token scopes: payments:write: "Create and manage payments" - payments:read: "View payment history" users:admin: "Manage user accounts" schemas: User: type: object - description: "Represents a user account in the Acme platform." + description: "Represents a registered user account." required: - id - email - - name + # CHANGED: 'name' → 'username' (name removed from required, username added) + - username properties: id: type: string @@ -283,36 +288,43 @@ components: email: type: string description: "User's email address." - name: + # RENAMED: 'name' → 'username' (name property removed → Structural) + username: type: string - description: "User's display name." + description: "Display name (renamed from 'name' in v1)." phone: type: string - nullable: true - description: "User's phone number in E.164 format." + # CHANGED: nullable: true removed → Dangerous Non-Breaking (NULLABLE_REMOVED) + role: + type: string + description: "User role (e.g., admin, member)." created_at: type: string format: date-time - description: "Timestamp when the account was created." + description: "Account creation timestamp." CreateUserRequest: type: object - description: "Request body for creating a new user account." + description: "Request body for creating a new user." required: - email - name + # NEW REQUIRED FIELD: email_verified → Structural (request-property-became-required) + - email_verified properties: email: type: string - description: "Email address for the new account." + description: "User's email address." name: type: string - description: "Display name for the new account." + description: "User's full name." phone: type: string - description: "Optional phone number." + email_verified: + type: boolean + description: "Whether the email has been verified." Order: type: object - description: "Represents a customer order with line items and status." + description: "Represents a customer order." required: - id - user_id @@ -325,25 +337,26 @@ components: user_id: type: string description: "ID of the user who placed the order." + # TYPE CHANGE: total was 'number', now 'string' → Behavioral total: - type: number - description: "Order total in the specified currency." + type: string + description: "Order total (changed from number to string for precision)." currency: type: string - default: "USD" - description: "ISO 4217 currency code." + default: "EUR" + # CHANGED: default value changed from 'USD' to 'EUR' → Dangerous Non-Breaking + # ENUM CHANGE: removed 'pending' from enum → Behavioral status: type: string - enum: [pending, confirmed, shipped, delivered] - description: "Current order fulfillment status." + enum: [confirmed, shipped, delivered] + description: "Current order status." items: type: array - description: "Line items in the order." items: $ref: "#/components/schemas/OrderItem" OrderItem: type: object - description: "A single line item in an order." + description: "A single item in an order." required: - product_id - quantity @@ -357,7 +370,7 @@ components: description: "Number of units ordered." price: type: number - description: "Unit price at time of order." + description: "Unit price." CreateOrderRequest: type: object description: "Request body for creating a new order." @@ -375,7 +388,7 @@ components: $ref: "#/components/schemas/OrderItem" ChargeRequest: type: object - description: "Request body for processing a payment charge." + description: "Request body for processing a payment." required: - order_id - amount @@ -386,13 +399,13 @@ components: description: "ID of the order to charge." amount: type: number - description: "Amount to charge in the specified currency." + description: "Amount to charge." currency: type: string description: "ISO 4217 currency code." PaymentResult: type: object - description: "Result of a payment processing operation." + description: "Result of a payment operation." required: - transaction_id - status @@ -402,7 +415,7 @@ components: description: "Unique transaction identifier." status: type: string - description: "Payment status (success, declined, pending)." + description: "Payment status (e.g., success, failed)." TokenResponse: type: object description: "OAuth2 token response returned by the /auth/token endpoint." @@ -414,9 +427,6 @@ components: access_token: type: string description: "Bearer access token for API authentication." - refresh_token: - type: string - description: "Refresh token for obtaining new access tokens without re-authentication." token_type: type: string default: "Bearer" @@ -427,17 +437,17 @@ components: description: "Token lifetime in seconds." RefundRequest: type: object - description: "Request body for initiating a payment refund." + description: "Request body for processing a refund." required: - transaction_id - reason properties: transaction_id: type: string - description: "ID of the original transaction to refund." + description: "ID of the transaction to refund." reason: type: string - description: "Reason for the refund request." + description: "Reason for the refund." amount: type: number - description: "Partial refund amount. Omit for full refund." + description: "Partial refund amount. If omitted, full refund is issued."