Skip to content

[#984] Add compat CLI command for JSON Schema compatibility checking#697

Open
Mahaprasadnanda wants to merge 1 commit intosourcemeta:mainfrom
Mahaprasadnanda:compat-cli-checker
Open

[#984] Add compat CLI command for JSON Schema compatibility checking#697
Mahaprasadnanda wants to merge 1 commit intosourcemeta:mainfrom
Mahaprasadnanda:compat-cli-checker

Conversation

@Mahaprasadnanda
Copy link
Copy Markdown

Summary

This PR adds a new compat CLI command to compare two JSON Schema files and report compatibility changes between schema versions.

The goal is to provide an MVP for the compatibility-checking workflow proposed in json-schema-org/community#984, with a focus on practical breaking-change detection for schema evolution.

Usage:

jsonschema compat <old_schema.json> <new_schema.json>

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 12 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/compatibility.cc">

<violation number="1" location="src/compatibility.cc:209">
P2: Numeric constraint additions/removals are ignored because compare_numeric_keyword returns early unless both schemas define the keyword, so adding/removing maxLength/minLength/maximum/minimum is never reported.</violation>

<violation number="2" location="src/compatibility.cc:236">
P2: Boolean↔object schema transitions are silently ignored because the boolean branch returns early unless both sides are booleans.</violation>

<violation number="3" location="src/compatibility.cc:249">
P1: Enum compatibility logic conflates missing `enum` with an empty enum set, causing added enum constraints to be reported as safe and removed enum constraints as breaking.</violation>

<violation number="4" location="src/compatibility.cc:312">
P2: Type compatibility is only evaluated when both schemas define `type`, so adding or removing a `type` constraint is silently ignored, creating false negatives for narrowing/widening changes.</violation>
</file>

<file name="test/compat/fail_on_breaking.sh">

<violation number="1" location="test/compat/fail_on_breaking.sh:30">
P2: Failure-mode compat test validates only text output and does not assert `--json` structured error output, leaving JSON failure behavior untested.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

schema_label(path) + " now rejects every instance"});
} else if (old_schema.is_boolean() && !old_schema.to_boolean() &&
new_schema.is_boolean() && new_schema.to_boolean()) {
report.safe.push_back(
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Enum compatibility logic conflates missing enum with an empty enum set, causing added enum constraints to be reported as safe and removed enum constraints as breaking.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/compatibility.cc, line 249:

<comment>Enum compatibility logic conflates missing `enum` with an empty enum set, causing added enum constraints to be reported as safe and removed enum constraints as breaking.</comment>

<file context>
@@ -0,0 +1,436 @@
+           schema_label(path) + " now rejects every instance"});
+    } else if (old_schema.is_boolean() && !old_schema.to_boolean() &&
+               new_schema.is_boolean() && new_schema.to_boolean()) {
+      report.safe.push_back(
+          {sourcemeta::jsonschema::CompatibilitySeverity::Safe,
+           "boolean_schema", path,
</file context>
Fix with Cubic

-> void {
const auto old_value{optional_number_keyword(old_schema, keyword)};
const auto new_value{optional_number_keyword(new_schema, keyword)};
if (!old_value.has_value() || !new_value.has_value()) {
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Numeric constraint additions/removals are ignored because compare_numeric_keyword returns early unless both schemas define the keyword, so adding/removing maxLength/minLength/maximum/minimum is never reported.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/compatibility.cc, line 209:

<comment>Numeric constraint additions/removals are ignored because compare_numeric_keyword returns early unless both schemas define the keyword, so adding/removing maxLength/minLength/maximum/minimum is never reported.</comment>

<file context>
@@ -0,0 +1,436 @@
+    -> void {
+  const auto old_value{optional_number_keyword(old_schema, keyword)};
+  const auto new_value{optional_number_keyword(new_schema, keyword)};
+  if (!old_value.has_value() || !new_value.has_value()) {
+    return;
+  }
</file context>
Fix with Cubic


const auto old_types{parse_types(old_schema)};
const auto new_types{parse_types(new_schema)};
if (old_types.has_value() && new_types.has_value() &&
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Type compatibility is only evaluated when both schemas define type, so adding or removing a type constraint is silently ignored, creating false negatives for narrowing/widening changes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/compatibility.cc, line 312:

<comment>Type compatibility is only evaluated when both schemas define `type`, so adding or removing a `type` constraint is silently ignored, creating false negatives for narrowing/widening changes.</comment>

<file context>
@@ -0,0 +1,436 @@
+
+  const auto old_types{parse_types(old_schema)};
+  const auto new_types{parse_types(new_schema)};
+  if (old_types.has_value() && new_types.has_value() &&
+      old_types.value() != new_types.value()) {
+    const auto removed{typeset_difference(old_types.value(), new_types.value())};
</file context>
Fix with Cubic

const std::string &path,
sourcemeta::jsonschema::CompatibilityReport &report)
-> void {
if (old_schema.is_boolean() || new_schema.is_boolean()) {
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Boolean↔object schema transitions are silently ignored because the boolean branch returns early unless both sides are booleans.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/compatibility.cc, line 236:

<comment>Boolean↔object schema transitions are silently ignored because the boolean branch returns early unless both sides are booleans.</comment>

<file context>
@@ -0,0 +1,436 @@
+                    const std::string &path,
+                    sourcemeta::jsonschema::CompatibilityReport &report)
+    -> void {
+  if (old_schema.is_boolean() || new_schema.is_boolean()) {
+    if (old_schema == new_schema) {
+      return;
</file context>
Fix with Cubic

}
EOF

"$1" compat "$TMP/old.json" "$TMP/new.json" --fail-on-breaking > "$TMP/stdout" 2> "$TMP/stderr" && EXIT_CODE="$?" || EXIT_CODE="$?"
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Failure-mode compat test validates only text output and does not assert --json structured error output, leaving JSON failure behavior untested.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At test/compat/fail_on_breaking.sh, line 30:

<comment>Failure-mode compat test validates only text output and does not assert `--json` structured error output, leaving JSON failure behavior untested.</comment>

<file context>
@@ -0,0 +1,52 @@
+}
+EOF
+
+"$1" compat "$TMP/old.json" "$TMP/new.json" --fail-on-breaking > "$TMP/stdout" 2> "$TMP/stderr" && EXIT_CODE="$?" || EXIT_CODE="$?"
+
+if [ "$EXIT_CODE" != "2" ]
</file context>
Fix with Cubic

Signed-off-by: Mahaprasad <mahaprasad.programmer@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant