Skip to content

XGtsRefValidator does not traverse oneOf/anyOf/allOf subschemas #56

@GeraBart

Description

@GeraBart

Bug Description

XGtsRefValidator::visit_instance() only recurses into properties (for objects) and items (for arrays), but does not traverse into JSON Schema combinators (oneOf, anyOf, allOf). This means x-gts-ref constraints nested inside these combinators are silently ignored during instance validation.

Additionally, remove_x_gts_ref_fields() in store.rs strips all x-gts-ref fields before passing the schema to the jsonschema crate. Subschemas containing only x-gts-ref become empty schemas {}. When placed inside oneOf, both empty subschemas match any value, causing oneOf to always fail (it requires exactly 1 match out of N).

The combined effect: x-gts-ref inside oneOf/anyOf/allOf is broken at both validation layers.

This is the same issue as GlobalTypeSystem/gts-ts#10 in the TypeScript adapter.

Root Cause

In gts/src/x_gts_ref.rs, visit_instance() (lines ~165-220) handles:

  • schema.properties — recurses into object properties
  • schema.items — recurses into array items
  • schema.oneOfnot traversed
  • schema.anyOfnot traversed
  • schema.allOfnot traversed

Note that visit_schema() does correctly handle combinators because it generically iterates over all keys. The inconsistency is only in visit_instance().

Reproduction

Schema (action.v1.json)

{
  "$id": "gts://gts.hai3.mfes.comm.action.v1~",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "type": {
      "x-gts-ref": "/$id"
    },
    "target": {
      "type": "string",
      "oneOf": [
        { "x-gts-ref": "gts.hai3.mfes.ext.domain.v1~*" },
        { "x-gts-ref": "gts.hai3.mfes.ext.extension.v1~*" }
      ]
    }
  },
  "required": ["type", "target"]
}

Instance (valid action targeting a domain)

{
  "type": "gts.hai3.mfes.comm.action.v1~hai3.mfes.ext.mount_ext.v1",
  "target": "gts.hai3.mfes.ext.domain.v1~hai3.screensets.layout.screen.v1"
}

Expected behavior

Validation passes — target matches the first x-gts-ref pattern (gts.hai3.mfes.ext.domain.v1~*).

Actual behavior

Validation fails. The jsonschema crate sees both oneOf subschemas as {} (since x-gts-ref was stripped), both match the string value, and oneOf fails because 2 subschemas matched instead of 1. Meanwhile, visit_instance() never sees the x-gts-ref constraints at all because it does not recurse into oneOf branches.

Suggested Fix

visit_instance() should recurse into combinator subschemas:

// After handling properties and items:
for combinator in &["oneOf", "anyOf", "allOf"] {
    if let Some(Value::Array(sub_schemas)) = sch_obj.get(*combinator) {
        for sub_schema in sub_schemas {
            self.visit_instance(inst, sub_schema, root_schema, path, errors);
        }
    }
}

For oneOf semantics specifically, the validator should check that the instance matches exactly one x-gts-ref pattern among the subschemas (mirroring JSON Schema oneOf semantics).

Impact

This bug blocks any schema that uses x-gts-ref inside JSON Schema combinators. The workaround is to flatten x-gts-ref to the property level (e.g., using a broader wildcard pattern), but this loses the ability to express "target must be one of these specific type families."

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions