fix: mark removed schema properties as backward incompatible
What
Removing a property from a request or response schema is now reported as backward incompatible. Adding properties remains backward compatible.
The verdict is gated by two new config flags (both enabled by default), so it can be tuned per direction like the other schema rules:
incompatible.request.properties.decreased(REQUEST_PROPERTIES_DECREASED)incompatible.response.properties.decreased(RESPONSE_PROPERTIES_DECREASED)
Removal of a previously required response property is now governed by RESPONSE_PROPERTIES_DECREASED. RESPONSE_REQUIRED_DECREASED is unchanged where it is still meaningful: a property that keeps existing but moves from required to optional in a response.
Why
Previously only removing a required property from a response schema was incompatible. Removing an optional property - or any property from a request schema - was reported as backward compatible, so clients depending on the deleted property went unnoticed.
For renames, no rename heuristic is attempted (too risky to guess intent); a renamed property surfaces as the missing old property, which is now incompatible, so a rename is no longer silently reported as backward compatible.
Fixes #673, and addresses the schema-property part of #611 (metadata/description changes being reported as compatible is a separate topic). Related context: #724 discusses configurable compatibility rules, #264/#490 already confirmed that adding optional properties must stay compatible (kept as is), and #940 applied the same directional gating pattern to request-body requiredness.
How
ChangedSchema.compatibleForRequest() / compatibleForResponse() now check missingProperties through the new BackwardIncompatibleProp entries, mirroring the directional pattern already used by ChangedEnum (REQUEST_ENUM_DECREASED) and ChangedOneOfSchema (REQUEST_ONEOF_DECREASED / RESPONSE_ONEOF_INCREASED).
Notes on scope:
- Properties that are
readOnlyin a request context orwriteOnlyin a response context were already filtered out ofmissingPropertiesbySchemaDiffResult.filterProperties, so they remain unflagged. - A discriminator property-name change short-circuits the property diff in
ComposedSchemaDiffResult, so that path is unaffected.
Tests:
SchemaBCTest: flag tests for request property removal, response property removal, response required-property removal, plus response property addition (compatible).SchemaDiffTest: model tests - property removed -> incompatible, property added -> compatible, required property removed -> incompatible.testAnyOfDiff/testAllOfDiffnow expect incompatible because their fixtures remove a property, andaddPropertyHandlingTestcompares the pair in the direction that actually adds the property (its fixtures date back to the module split; 1 -> 2 was a removal).- Several BC fixtures (
bc_schema_pattern_changed,bc_schema_type_changed,bc_request_schema_props_put_increased,bc_response_schema_props_required_decreased,bc_schema_changed_but_compatible) incidentally dropped optional properties fromWidget; those incidental removals are now incompatible, so the fixtures were cleaned up to keep testing only what they meant to test. AsciidocRenderTest.validateAsciiDocChangeFileasserts the exact render output for a removed-property spec; the expected output now showsBroken compatibility, the missing property line, and the WARNING footer.
CLI check on a minimal spec pair (GET/POST returning a schema with foo):
- removing
foo:Schema: Broken compatibility,Missing property: foo (string), exit code 1 with--fail-on-incompatible(wasBackward compatible, exit 0) - renaming
foo->bar: reported viaMissing property: foo, exit 1 - adding
bar:API changes are backward compatible, exit 0 - both new flags set to
falsevia--config-file: back toBackward compatible, exit 0
Summary by cubic
Removing a property from a request or response schema is now reported as backward incompatible, so clients that depend on the deleted property no longer go unnoticed. Previously only removing a required response property was flagged; removing optional properties or any request property was reported as compatible.
Adding properties stays compatible, and no rename heuristic is attempted, so renames surface as missing properties.
- New config flags
REQUEST_PROPERTIES_DECREASEDandRESPONSE_PROPERTIES_DECREASEDgate the verdict per direction, both enabled by default. RESPONSE_REQUIRED_DECREASEDnow only covers properties that remain but move from required to optional.