Summary
GTS Type Schema structural validation (GtsStore::validate_schema, gts/src/store.rs) does not verify that a registered type schema declares a valid $schema (JSON Schema dialect) keyword. A schema with a missing or non-string $schema is currently accepted, and downstream validation silently falls back to the validator's automatic draft detection (Draft 2020-12 when $schema is absent).
This was surfaced by a CodeRabbit review on #92 for the trait-validation path specifically, but it is a general structural-validation gap, not limited to traits.
Current behavior
validate_schema (gts/src/store.rs:649) validates $ref / x-gts-ref and compiles against the JSON Schema meta-schema (skipping compilation when the document contains gts:// refs), but it never asserts that $schema is present and is a recognized dialect URI.
- As a consequence,
validate_schema_traits (gts/src/store.rs:834) reads the leaf's $schema to pin the dialect for trait-value validation and falls back to None (default draft) when it is missing/non-string (gts/src/store.rs:~898-916). So an invalid leaf schema is not rejected, and its trait values may be validated under a different draft than intended.
Why it matters
- JSON Schema semantics differ across drafts (e.g.
exclusiveMinimum, $ref sibling keywords, additionalProperties vs unevaluatedProperties). Validating a schema body or its trait values under an unintended draft can both accept invalid input and reject valid input.
- The spec expects type schemas to declare their dialect via
$schema; the registry should enforce that rather than guess.
Proposed direction
Enforce $schema once, at the structural layer, so the guarantee is uniform for every registered type schema (bodies, traits, modifiers) instead of being special-cased in the OP#13 trait path:
- In
validate_schema (structural), require $schema to be present and a string — and ideally one of the supported dialect URIs — rejecting otherwise with a clear error.
- Once that holds,
validate_schema_traits can assume a present $schema and drop its silent None fallback.
Out of scope / notes
- Some unit-test fixtures in
gts/src/schema_traits.rs omit $schema and rely on the current fallback; they would need to declare an explicit $schema (or use a documented test-only path) once enforcement lands.
- This is intentionally broader than the trait path: the goal is a single place that guarantees every registered type schema has a valid dialect.
Originating review: #92 (CodeRabbit, gts/src/store.rs trait-dialect fallback).
Summary
GTS Type Schema structural validation (
GtsStore::validate_schema,gts/src/store.rs) does not verify that a registered type schema declares a valid$schema(JSON Schema dialect) keyword. A schema with a missing or non-string$schemais currently accepted, and downstream validation silently falls back to the validator's automatic draft detection (Draft 2020-12 when$schemais absent).This was surfaced by a CodeRabbit review on #92 for the trait-validation path specifically, but it is a general structural-validation gap, not limited to traits.
Current behavior
validate_schema(gts/src/store.rs:649) validates$ref/x-gts-refand compiles against the JSON Schema meta-schema (skipping compilation when the document containsgts://refs), but it never asserts that$schemais present and is a recognized dialect URI.validate_schema_traits(gts/src/store.rs:834) reads the leaf's$schemato pin the dialect for trait-value validation and falls back toNone(default draft) when it is missing/non-string (gts/src/store.rs:~898-916). So an invalid leaf schema is not rejected, and its trait values may be validated under a different draft than intended.Why it matters
exclusiveMinimum,$refsibling keywords,additionalPropertiesvsunevaluatedProperties). Validating a schema body or its trait values under an unintended draft can both accept invalid input and reject valid input.$schema; the registry should enforce that rather than guess.Proposed direction
Enforce
$schemaonce, at the structural layer, so the guarantee is uniform for every registered type schema (bodies, traits, modifiers) instead of being special-cased in the OP#13 trait path:validate_schema(structural), require$schemato be present and a string — and ideally one of the supported dialect URIs — rejecting otherwise with a clear error.validate_schema_traitscan assume a present$schemaand drop its silentNonefallback.Out of scope / notes
gts/src/schema_traits.rsomit$schemaand rely on the current fallback; they would need to declare an explicit$schema(or use a documented test-only path) once enforcement lands.Originating review: #92 (CodeRabbit,
gts/src/store.rstrait-dialect fallback).