1.0 readiness: the review findings of 2026-09-18 (0.15.0) - #130
Merged
Merged
Conversation
…s directional rewrite Require rasuvaeff/openapi-contract ^0.12. Operation::$serverBases is gone (the first server's base already carried it), so a hand-built operation without servers is materialized against the root. The request body and responses are typed shapes now, so the guards that re-checked them are removed along with the tests that fed hand-built shapes the type excludes. The directional schema rewrite is delegated to SchemaCheck::effective(): this package carried its own copy, which never recursed into additionalProperties. The contract's view keeps a readOnly property declared and typed (only its required entry goes), so whether such a property is generated is now the compiler's decision: given a direction, an object never emits a property the other direction owns and never generates an undeclared member under its name either, because the contract would type-check that member as the declared property. The negative body witnesses skip those properties for the same reason. A JSON media type without a schema, or with the true schema, is generated unconstrained, as the contract reads it. The dead JsonException branch in WitnessCheck goes.
… a JSON multipart part A float went on the wire through (string), which rounds to precision=14 and put a different number there for any value that needed more digits; it is spelled as json_encode spells it now. The multipleOf generator also rounded k * m back to the decimal it meant, which from about 64 upwards is one ulp away from the product the validator computes and tolerates — the decimal spelling is kept only where the validator agrees with it (#117). + leaves RESERVED_RAW: a raw plus in a query is a space to the validator and to every SAPI (#119). A multipart part declared application/json carries the JSON encoding of its value; text/* and application/octet-stream stay verbatim, and any other part media type fails closed (#122).
…ced in their operation, redaction reachable from the suite OpenApiPropertyTestingException is implemented by every exception the package throws. A case that does not have the shape the package writes is InvalidCase, not UnsupportedGeneration: the latter is a document limitation, the former a caller error. Psr15Transport's configuration error is a SuiteConfigurationError. A schema refusal names the operation and the parameter or body it was compiling (#127). ContractSuite::redaction() applies a policy to both the curl reproducer and the minimal case OperationPropertyFailed prints; the counterexample keeps the case as generated (#124). CheckFailed::$result is readonly, assigned through the constructor (#126). ResponseMaterializer builds its @internal collaborators itself (#125).
…s out of missing-required Every integer is also a number, and JSON Schema reads 1.0 as an integer, so oneOf over the two was never a choice between disjoint branches: half the draws matched both and the contract rejected them. The number branch is generated without integral values, the integer branch keeps only what the number branch's bounds and multiple refuse, and a number branch that admits every value outside the integer branch's reach fails closed (#121). A required path parameter cannot be omitted into invalidity: dropping it leaves the template literal in the request target, which a string schema accepts. It is out of the missing-required category and of negativeCoverage(), and an operation with no other required component names the reason (#118).
…r member as the wire does A header value is judged the way the validator and RFC 9110 read it: obs-text is a field value (a UTF-8 enum member travels), whitespace at either end is stripped by the reader and so refused, an interior space is read as sent and so kept — enum: ["New York"] is generated and accepted (#129). A header const or enum member no field value can carry is refused when the operation is compiled, not discovered as an exhaustion. A path or header pattern none of whose strings survives the wire is probed at compile time and refused by name. An object meets minProperties and maxProperties by construction — an optional past the ceiling is left out, one needed for the floor brought in — instead of drawing independent presence choices and filtering three runs in four away. uniqueItems over a bounded integer domain smaller than minItems fails closed (#123).
A form property with an object schema and explode: true is written as flat member=value pairs, and the contract claims only the declared members for it: an undeclared member the generator added landed as a top-level member of the body, where it collided with a declared property or violated additionalProperties: false. Such an object is compiled without extras, and one whose minProperties its declared properties cannot meet fails closed when the operation is compiled (#120).
CaseData and its parts (ParameterMap, PartData, BodyData, MisuseData) live on ContractSuite and are imported everywhere else; the RequestCaseData and NegativeRequestCaseData aliases and the inline copies in the materializer and the reproducer are gone. checkValid(), checkNegative(), reproduce(), redact() and RequestMaterializer::materialize() refuse a case missing a key with InvalidCase naming it — a hand-written case without misuse used to raise a warning and pass checkValid() (#128).
…les; zoo for the five new rules; 0.15.0 Requires openapi-contract ^0.12 and accepts property-testing-core ^0.11. Five zoo operations exercise the header-member judgement, object cardinality by construction, oneOf over integer and number, the nested exploded form object and numbers at full precision beside allowReserved; the contract's generated corpus is re-recorded from them (openapi-contract#152).
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…and the contract's verdict there is its own
The compile-time probes catch GenerationExhaustedException by name, which exists since the core's 0.10 contract freeze, so ^0.5–^0.9 are no longer accepted (Prefer lowest was red on the symbol). Testo maps mutants by #[Covers]: WireAgreementTest now covers the composition, scalar and parameter-schema compilers it exercises, and the new behaviour is pinned where the coverage is — object cardinality by construction, the bounded integer domain, every integer/number oneOf branch outcome (an empty branch is dropped, the union refused only when both are), the comma as a separator only in a list or object header, the reproduce() policy precedence, the case-shape check at every entry point.
…1.96% on 4040 mutants The wave added ~630 mutants. What is killable is killed (a disjoint branch declared first, a bounded number item, a domain away from zero, a scalar and a non-exploded object before the refused one, an exploded object with neither floor nor members); what remains is recorded by class in AGENTS.md, and the gate sits below the score again, as its own comment requires.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The 1.0-readiness review of 2026-09-18, every open finding of this package: #117–#129. Released as 0.15.0 (minor on 0.x —
ResponseMaterializer's constructor narrows, theOperationPropertyFailedfactories take one more argument, theRequestCaseData/NegativeRequestCaseDatapsalm aliases are gone, case-shape errors are a type of their own).Fixed
(string)(precision=14). Spelled asjson_encodespells them now; themultipleOfgenerator also roundedk×mto a decimal one ulp away from the product the validator computes and tolerates (1e-14, less than an ulp from ~64 up) — a third of the draws for0.1were rejected. The decimal is kept only where the validator agrees. Underext-bcmaththe contract's verdict is its own: openapi-contract#151.missing-requiredno longer targets a path parameter (omitting it leaves the template literal, which astringschema accepts);negativeCoverage()follows.+stays%2BunderallowReserved.minPropertiesfails closed at compile time.oneOfoverintegerandnumber: the number branch without integral values, the integer branch only where the number branch's keywords refuse, fail-closed when nothing can be kept apart.text/*/application/octet-streamverbatim; anything else fails closed.isHeaderSafe(); a path/headerpatternnone of whose strings survives the wire is probed and refused at compile time; object cardinality is met by construction (no more presence-choice filter);uniqueItemsover a bounded integer domain smaller thanminItemsfails closed.Contract
ContractSuite::redaction()/redact(); the minimal case inOperationPropertyFailedis printed through the policy; the docs no longer claimCookieis default-redacted.ResponseMaterializerbuilds its@internalcollaborators itself.CheckFailed::$resultis readonly.OpenApiPropertyTestingExceptionmarker on every exception;InvalidCasefor a malformed case;Psr15TransportthrowsSuiteConfigurationError;UnsupportedGeneration::inOperation()names the operation and the parameter/body.CaseData(+ParameterMap,BodyData,PartData,MisuseData) onContractSuite;Internal\CaseShape::assert()at every@apientry point.Dependencies
openapi-contract ^0.12(the directional rewrite is the contract's; the request body and responses arrive typed) andproperty-testing-core ^0.11accepted.Zoo and corpus
labels.get,sparse.create,amounts.create,settings.create,precise.get; corpus re-recorded, 435 → 515 cases: openapi-contract#152 (the contract's suite is green against it).Fixes #117
Fixes #118
Fixes #119
Fixes #120
Fixes #121
Fixes #122
Fixes #123
Fixes #124
Fixes #125
Fixes #126
Fixes #127
Fixes #128
Fixes #129
Validation