# authorship: generated by API Evangelist tooling (derive-rules.py, 2026-09-21). x-method: generated # Every rule below was MEASURED against Openhandle's own contract before it was written; a rule is present only # when the contract satisfies it at 80% or more. Severity: 100% -> error, >= 90% -> warn, else info. # Provenance: # - operation-has-operationid: 100% # - operation-has-summary: 100% # - operation-has-description: 99% # - operation-has-tags: 98% # - operation-has-success-response: 100% # - operation-declares-4xx: 99% # - operation-declares-401-or-403: 98% # - operation-declares-429: 98% # - operation-secured: 98% # - path-segment-casing-camel: 97% # - path-no-trailing-slash: 100% # - path-params-in-braces: 100% # - servers-https: 100% # - write-declares-request-body: 100% # - list-pagination-parameter: 89% # - response-media-type: 100% # - property-name-casing-camel: 100% # - info-has-description: 100% x-method: generated x-generator: derive-rules.py x-generated: '2026-09-21' x-source: - openapi/openhandle-openapi.yml extends: - - spectral:oas - recommended formats: - oas3 rules: operation-has-operationid: description: 'Every operation declares an operationId (measured: 100% of this contract)' severity: error given: $.paths[*][get,post,put,patch,delete] then: field: operationId function: truthy operation-has-summary: description: 'Every operation has a summary (measured: 100% of this contract)' severity: error given: $.paths[*][get,post,put,patch,delete] then: field: summary function: truthy operation-has-description: description: 'Every operation has a description (measured: 99% of this contract)' severity: warn given: $.paths[*][get,post,put,patch,delete] then: field: description function: truthy operation-has-tags: description: 'Every operation is tagged (measured: 98% of this contract)' severity: warn given: $.paths[*][get,post,put,patch,delete] then: field: tags function: truthy operation-has-success-response: description: 'Every operation declares a 2xx response (measured: 100% of this contract)' severity: error given: $.paths[*][get,post,put,patch,delete].responses then: function: schema functionOptions: schema: type: object patternProperties: ^2\d\d$: {} minProperties: 1 operation-declares-4xx: description: 'Every operation declares at least one 4xx response (measured: 99% of this contract)' severity: warn given: $.paths[*][get,post,put,patch,delete].responses then: function: schema functionOptions: schema: type: object patternProperties: ^4\d\d$: {} minProperties: 1 operation-declares-401-or-403: description: 'Every operation declares 401 or 403 (measured: 98% of this contract)' severity: warn given: $.paths[*][get,post,put,patch,delete].responses then: function: schema functionOptions: schema: type: object anyOf: - required: - '401' - required: - '403' operation-declares-429: description: 'Every operation declares 429 (rate limited) (measured: 98% of this contract)' severity: warn given: $.paths[*][get,post,put,patch,delete].responses then: field: '429' function: truthy operation-secured: description: 'Every operation is covered by a security requirement (measured: 98% of this contract)' severity: warn given: $.paths[*][get,post,put,patch,delete] then: field: security function: truthy path-segment-casing-camel: description: 'Path segments are camel case (measured: 97% of this contract)' severity: warn given: $.paths[*]~ then: function: pattern functionOptions: match: ^(/[a-z][a-zA-Z0-9]*|/\{[^}]+\})+/?$ path-no-trailing-slash: description: 'Paths carry no trailing slash (measured: 100% of this contract)' severity: error given: $.paths[*]~ then: function: pattern functionOptions: notMatch: ./$ path-params-in-braces: description: 'Path parameters use {braces}, not :colon (measured: 100% of this contract)' severity: error given: $.paths[*]~ then: function: pattern functionOptions: notMatch: ':' servers-https: description: 'Servers are https (measured: 100% of this contract)' severity: error given: $.servers[*].url then: function: pattern functionOptions: match: ^(https://|\{) write-declares-request-body: description: 'POST and PUT declare a request body (measured: 100% of this contract)' severity: error given: $.paths[*][post,put] then: field: requestBody function: truthy list-pagination-parameter: description: 'Collection GETs take the `cursor` pagination parameter (measured: 89% of this contract)' severity: info given: $.paths[*].get then: field: parameters function: schema functionOptions: schema: type: array contains: type: object properties: name: const: cursor required: - name response-media-type: description: 'Responses are served as application/json (measured: 100% of this contract)' severity: error given: $.paths[*][get,post,put,patch,delete].responses[*].content then: function: schema functionOptions: schema: type: object required: - application/json property-name-casing-camel: description: 'Schema property names are camel case (measured: 100% of this contract)' severity: error given: $.components.schemas[*].properties[*]~ then: function: casing functionOptions: type: camel info-has-description: description: 'The contract''s info block carries a description (measured: 100% of this contract)' severity: error given: $.info then: field: description function: truthy