Skip to content

feat(gts-macros): added const_values, new_instance_with_defaults(), and parent metadata#64

Closed
Artifizer wants to merge 0 commit intoGlobalTypeSystem:mainfrom
Artifizer:main
Closed

feat(gts-macros): added const_values, new_instance_with_defaults(), and parent metadata#64
Artifizer wants to merge 0 commit intoGlobalTypeSystem:mainfrom
Artifizer:main

Conversation

@Artifizer
Copy link
Copy Markdown
Contributor

@Artifizer Artifizer commented Feb 21, 2026

feat(gts-macros): const_values, new_instance_with_defaults, and parent metadata
chore(gts-macros-cli): fix json schema generatio for 3rd level GTS structs

Summary by CodeRabbit

Release Notes v0.8.2

  • New Features

    • Added const_values parameter to the #[struct_to_gts_schema] macro for defining fixed constant values on struct fields in generated JSON schemas.
    • Introduced new_instance_with_defaults() constructor for base and derived structs with const values.
    • Added GTS_SCHEMA_ID_FIELD_NAME and GTS_INSTANCE_ID_FIELD_NAME public constants.
  • Documentation

    • Expanded README with comprehensive const_values usage patterns and examples.
    • Added "Generated API at a Glance" section documenting macro-emitted items.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 21, 2026

📝 Walkthrough

Walkthrough

This PR introduces const_values, an optional parameter for the #[struct_to_gts_schema] macro that enables per-field constant constraints in generated JSON schemas. Implementation spans macro expansion, CLI parsing, and schema generation, with comprehensive test coverage including type validation, malformed input handling, and multi-level inheritance scenarios.

Changes

Cohort / File(s) Summary
Version Bumps
Cargo.toml, gts-id/Cargo.toml, gts-macros/Cargo.toml, gts-macros-cli/Cargo.toml, gts/Cargo.toml
All workspace packages updated from 0.8.1 to 0.8.2.
Documentation
README.md, gts-macros/README.md
Added "Const Values Pattern" sections explaining const_values syntax, behavior, interaction with new_instance_with_defaults(), and usage examples. New sections on generated API surface and base/derived struct differences.
Macro Core Implementation
gts-macros/src/lib.rs
Extended GtsSchemaArgs with const_values field; added parse_const_values_str utility for parsing; integrated const_values into schema generation with auto-injection logic for parent/child relationships; added compile-time validation for base-struct constraints; introduced GTS_SCHEMA_ID_FIELD_NAME and GTS_INSTANCE_ID_FIELD_NAME constants. Raw identifier (r#) field name normalization added.
CLI Implementation
gts-cli/src/gen_schemas.rs
Added const_values field to MacroAttrs; introduced parse_const_values_cli and unescape_rust_str utilities; extended parse_macro_attrs to populate const_values; threaded const_values through extract_and_generate_schemas and build_json_schema with pre-pass mapping for parent schema ID detection.
Compile-fail Tests: Type Mismatches
gts-macros/tests/compile_fail/const_values_type_mismatch_*.rs (8 files), .stderr counterparts
Tests validating compile-time type checking for const_values assignments (bool↔int, bool↔string, float↔int, int↔bool, int↔string, string↔bool, string↔float, string↔int). Each includes expected error snapshots.
Compile-fail Tests: Validation Errors
gts-macros/tests/compile_fail/const_values_malformed.rs, const_values_on_base.rs, const_values_unknown_field.rs, .stderr counterparts
Tests for malformed syntax (missing '='), disallowed const_values on base structs, and references to non-existent fields.
Compile-fail Tests: Structural
gts-macros/tests/compile_fail/base_parent_mismatch.rs, base_parent_no_generic.rs, two_instance_id_fields.rs, two_schema_id_fields.rs, .stderr counterparts
Updated/added tests for base struct validation and ambiguous field scenarios; updated error messages to reflect macro-evaluation panics.
Integration Tests
gts-macros/tests/const_fields_tests.rs
Comprehensive test module (1337 lines) covering: error hierarchies with const_values, all-type const patterns (bool, int, float, string), three-level inheritance with const injection, schema validation, instance construction, JSON serialization, and edge cases.
Test Updates
gts-macros/tests/inheritance_tests.rs, integration_tests.rs
Updated instance ID expectations and GTS schema ID segments; test data adjusted for new segment structures.
Base Schema Files
gts-macros/tests/schemas/gts.x.core.err.error.v1~.schema.json, gts.x.core.events.container.v1~.schema.json, gts.x.test.alert.base.v1~.schema.json, gts.x.test.const.types.v1~.schema.json, gts.x.test.single.segment.v1~.schema.json, gts.x.test.three.event.v1~.schema.json (6 files)
New base schema definitions for test scenarios covering error hierarchies, containers, alerts, const-value type testing, and three-level events.
Derived Schema Files
gts-macros/tests/schemas/gts.x.core.err.error.v1~x.core.http.*.v1~.schema.json (3 files: bad_request, conflict, unprocessable)
Derived error schemas with const constraints for HTTP status codes and messages.
Const-Values Schema Files
gts-macros/tests/schemas/gts.x.test.const.types.v1~x.test.types.*.v1~.schema.json (7 files: bool_false, bool_true, float, int, multi, neg_int, str_quoted, str_unquoted)
Type-specific const-value test schemas demonstrating boolean, integer, float, and string constants.
Multi-Level Hierarchy Schemas
gts-macros/tests/schemas/gts.x.test.three.event.v1~*.schema.json (4 files), gts.x.test.alert.base.v1~*.schema.json (1 file), gts.x.core.events.type.v1~*.schema.json (2 files), gts.x.core.events.gts_type.v1~.schema.json, gts.x.core.events.topic.v1~.schema.json, gts.x.test.versioned.*.schema.json (2 files)
Multi-level inheritance test schemas with const-value injection across parent-child relationships; updated topic schema with enhanced metadata.
Audit Event Schema
gts-macros-cli/src/schemas/gts.x.core.events.type.v1~x.core.audit.event.v1~.schema.json
Added event_type const property with fixed value.

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly Related PRs

Poem

🐰 Constants now dance in schemas grand,
Per-field constraints, just as planned!
From CLI args to JSON's embrace,
Const values find their rightful place,
Type-safe defaults, errors caught in advance! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main feature additions: const_values support, new_instance_with_defaults() functionality, and parent metadata improvements to gts-macros.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (1)
gts-macros/src/lib.rs (1)

1686-1688: Redundant is_unit_struct redefinition.

This variable is already computed earlier (line 1017 as struct_fields.is_none()), and this line shadows it with an equivalent check. Consider reusing the existing variable instead of recomputing.

♻️ Suggested simplification
-    // Check if this is a unit struct - we need to add an allow attribute for clippy
-    // because quote! may emit {} instead of ; for unit structs
-    let is_unit_struct = matches!(&input.data, Data::Struct(data_struct) if matches!(&data_struct.fields, Fields::Unit));
+    // is_unit_struct was already computed above (line 1017)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gts-macros/src/lib.rs` around lines 1686 - 1688, Remove the redundant
shadowing definition of is_unit_struct and reuse the earlier computed value
based on struct_fields (i.e., struct_fields.is_none()) instead of re-checking
matches!(&input.data, Data::Struct(...) if matches!(&data_struct.fields,
Fields::Unit)); delete the let is_unit_struct = ... line and update any
subsequent references to use the existing struct_fields.is_none() (or the
previously defined is_unit_struct) so you don't recompute/mask the value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@gts-cli/src/gen_schemas.rs`:
- Around line 460-471: After parsing attributes with
parse_macro_attrs(attr_body) you must validate that base structs do not have
const_values: after let Some(attrs) = parse_macro_attrs(attr_body) else { ... }
add a check that if attrs.base == BaseAttr::IsBase and
attrs.const_values.is_some() then return or emit a CLI error (matching the macro
behavior) instead of silently ignoring; update the error path to include context
(struct name from the parsed item) so the CLI rejects the input consistently
with the macro.
- Around line 438-449: The current Pass 1 loop that builds gts_schema_id_field
(in gen_schemas.rs) blindly maps struct_name -> field_name and overwrites when
multiple GtsSchemaId fields exist; change the logic inside the for cap in
re.captures_iter(content) / for field_cap in field_re.captures_iter(struct_body)
block to detect duplicates: maintain either a HashMap<String, Vec<String>> or a
HashMap<String, String> plus a HashSet<String> ambiguous set; when you encounter
a second GtsSchemaId for the same struct_name, mark that struct_name as
ambiguous (add to the ambiguous set or store multiple names) and ensure you do
not inject an auto const for any ambiguous struct_name later (skip or emit an
error/warning), so the gts_schema_id_field map only contains unambiguous
single-field entries and ambiguous structs are skipped/handled explicitly.

In `@gts-macros/README.md`:
- Line 37: The italicized parenthetical in the README table cell for
`new_instance_with_defaults(segment)` contains extra spaces inside the emphasis
markers (the text `*(only if struct has exactly one `GtsInstanceId` field)*`),
triggering markdownlint MD037; fix it by removing the space after the opening
`*` and before the closing `*` so the emphasis is `*(only if struct has exactly
one `GtsInstanceId` field)*` becomes `*(only if struct has exactly one
`GtsInstanceId` field)*` (or remove the emphasis entirely) to eliminate the
inner spacing issue.

In `@gts-macros/tests/compile_fail/const_values_malformed.rs`:
- Around line 5-15: The struct attribute uses base=true on MalformedConstV1 so
the const_values error is raised before malformed parsing; split into two
structs: keep a base struct (e.g., MalformedConstBase) annotated with
#[struct_to_gts_schema(... base = true ...)] and move the fields there (no
const_values), then add a derived struct (e.g., MalformedConstV1) annotated with
#[struct_to_gts_schema(... base = false, schema_id =
"gts.x.test.const.malformed.v1~", const_values = "value_without_equals",
properties = "value" ...)] that references/extends the base so the malformed
const_values path on the derived struct is reached and tested.

In `@gts-macros/tests/compile_fail/two_instance_id_fields.rs`:
- Line 5: The test uses the non-canonical import path "use
gts::gts::{GtsInstanceId, GtsSchemaId};" — replace it with the crate-root
re-exports by importing "GtsInstanceId" and "GtsSchemaId" from "gts" directly
(i.e., use gts::GtsInstanceId; use gts::GtsSchemaId;) so the file follows the
same canonical import style as other compile-fail tests and references the same
symbols GtsInstanceId and GtsSchemaId.

In
`@gts-macros/tests/schemas/gts.x.core.events.type.v1`~x.core.simple.event.v1~.schema.json:
- Around line 9-23: The schema is missing event_type in its required array, so
add the "event_type" property name to the local "required" list in this JSON
Schema (the block defining properties with "event_type": { "const":
"gts.x.core.events.type.v1~x.core.simple.event.v1~" }), ensuring the schema
requires the event_type field in addition to "message" and "severity".

In `@gts-macros/tests/schemas/gts.x.test.alert.base.v1`~.schema.json:
- Line 5: Update the JSON schema "description" text to accurately reflect the
defined properties: replace the reference to "kind" with the actual property
names present (channel, data, recipient, severity, type) or add the missing
"kind" property if that was intended; locate the schema's top-level
"description" string and make it consistent with the properties array (channel,
data, recipient, severity, type) or adjust the properties to include "kind" and
its schema if needed.

In
`@gts-macros/tests/schemas/gts.x.test.alert.base.v1`~x.test.three.sms.v1~.schema.json:
- Around line 13-15: The derived schema places the "kind" const at top-level in
allOf[1].properties which violates the base schema's additionalProperties:false;
move the "kind" const into the "data" object's properties (i.e., under
data.properties.kind with the same const value) inside the derived schema so the
top-level only contains the allowed keys (channel, data, recipient, severity,
type); update the allOf entry that currently defines "kind" to nest it under
"data.properties" to satisfy the base schema and the expectation in
const_fields_tests.rs::test_three_event_l3_sms_has_conflicting_severity_const.

In
`@gts-macros/tests/schemas/gts.x.test.three.event.v1`~x.test.three.alert.v1~.schema.json:
- Around line 10-18: The base schema's additionalProperties: false blocks the
derived schema's top-level properties channel, data, and recipient (present in
the derived schema file) causing validation failures; fix by updating the base
schema to use "unevaluatedProperties": false instead of "additionalProperties":
false (JSON Schema 2019-09+) so derived schemas can add properties via
$ref/allOf, or alternatively move channel, data, and recipient under the
existing payload object in the derived schema so they are nested rather than
top-level — update the base schema's constraint or refactor the derived schema
(properties: channel, data, recipient) accordingly.

---

Nitpick comments:
In `@gts-macros/src/lib.rs`:
- Around line 1686-1688: Remove the redundant shadowing definition of
is_unit_struct and reuse the earlier computed value based on struct_fields
(i.e., struct_fields.is_none()) instead of re-checking matches!(&input.data,
Data::Struct(...) if matches!(&data_struct.fields, Fields::Unit)); delete the
let is_unit_struct = ... line and update any subsequent references to use the
existing struct_fields.is_none() (or the previously defined is_unit_struct) so
you don't recompute/mask the value.

Comment thread gts-cli/src/gen_schemas.rs Outdated
Comment on lines +438 to +449
// Pass 1: build a map of struct_name -> name of the GtsSchemaId field (for auto const injection)
let mut gts_schema_id_field: HashMap<String, String> = HashMap::new();
for cap in re.captures_iter(content) {
let struct_name = cap[2].to_owned();
let struct_body = cap.get(4).map_or("", |m| m.as_str());
for field_cap in field_re.captures_iter(struct_body) {
let field_name = &field_cap[2];
let field_type = field_cap[3].trim().trim_end_matches(',');
if field_type == "GtsSchemaId" {
gts_schema_id_field.insert(struct_name.clone(), field_name.to_owned());
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid ambiguous parent schema-id auto‑injection.
If a parent has multiple GtsSchemaId fields, the current map overwrites and still injects, which conflicts with the macro’s ambiguity rules. Track duplicates and skip/err to avoid silently picking one.

Suggested fix (track ambiguity and skip injection)
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
@@
-let mut gts_schema_id_field: HashMap<String, String> = HashMap::new();
+let mut gts_schema_id_field: HashMap<String, String> = HashMap::new();
+let mut ambiguous_schema_id_structs: HashSet<String> = HashSet::new();
@@
-            if field_type == "GtsSchemaId" {
-                gts_schema_id_field.insert(struct_name.clone(), field_name.to_owned());
-            }
+            if field_type == "GtsSchemaId" {
+                if gts_schema_id_field
+                    .insert(struct_name.clone(), field_name.to_owned())
+                    .is_some()
+                {
+                    ambiguous_schema_id_structs.insert(struct_name.clone());
+                }
+            }
@@
-        let parent_schema_id_field: Option<&str> = match &attrs.base {
-            BaseAttr::Parent(parent_name) => {
-                gts_schema_id_field.get(parent_name).map(String::as_str)
-            }
+        let parent_schema_id_field: Option<&str> = match &attrs.base {
+            BaseAttr::Parent(parent_name) => {
+                if ambiguous_schema_id_structs.contains(parent_name) {
+                    None
+                } else {
+                    gts_schema_id_field.get(parent_name).map(String::as_str)
+                }
+            }
             BaseAttr::IsBase => None,
         };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gts-cli/src/gen_schemas.rs` around lines 438 - 449, The current Pass 1 loop
that builds gts_schema_id_field (in gen_schemas.rs) blindly maps struct_name ->
field_name and overwrites when multiple GtsSchemaId fields exist; change the
logic inside the for cap in re.captures_iter(content) / for field_cap in
field_re.captures_iter(struct_body) block to detect duplicates: maintain either
a HashMap<String, Vec<String>> or a HashMap<String, String> plus a
HashSet<String> ambiguous set; when you encounter a second GtsSchemaId for the
same struct_name, mark that struct_name as ambiguous (add to the ambiguous set
or store multiple names) and ensure you do not inject an auto const for any
ambiguous struct_name later (skip or emit an error/warning), so the
gts_schema_id_field map only contains unambiguous single-field entries and
ambiguous structs are skipped/handled explicitly.

Comment thread gts-cli/src/gen_schemas.rs Outdated
Comment on lines +460 to +471
// Parse macro attributes
let Some(attrs) = parse_macro_attrs(attr_body) else {
continue;
};

// Determine parent's GtsSchemaId field name for auto const injection
let parent_schema_id_field: Option<&str> = match &attrs.base {
BaseAttr::Parent(parent_name) => {
gts_schema_id_field.get(parent_name).map(String::as_str)
}
BaseAttr::IsBase => None,
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

CLI should reject const_values on base structs (currently ignored).
The macro explicitly errors on base = true + const_values, but the CLI accepts and silently drops them in the base branch. That can mask misconfigurations and diverge from macro behavior.

Suggested fix (validate after parsing)
-        let Some(attrs) = parse_macro_attrs(attr_body) else {
+        let Some(attrs) = parse_macro_attrs(attr_body) else {
             continue;
         };
+        if matches!(attrs.base, BaseAttr::IsBase) && !attrs.const_values.is_empty() {
+            bail!(
+                "const_values is not allowed on base structs (base = true): {}",
+                struct_name
+            );
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Parse macro attributes
let Some(attrs) = parse_macro_attrs(attr_body) else {
continue;
};
// Determine parent's GtsSchemaId field name for auto const injection
let parent_schema_id_field: Option<&str> = match &attrs.base {
BaseAttr::Parent(parent_name) => {
gts_schema_id_field.get(parent_name).map(String::as_str)
}
BaseAttr::IsBase => None,
};
// Parse macro attributes
let Some(attrs) = parse_macro_attrs(attr_body) else {
continue;
};
if matches!(attrs.base, BaseAttr::IsBase) && !attrs.const_values.is_empty() {
bail!(
"const_values is not allowed on base structs (base = true): {}",
struct_name
);
}
// Determine parent's GtsSchemaId field name for auto const injection
let parent_schema_id_field: Option<&str> = match &attrs.base {
BaseAttr::Parent(parent_name) => {
gts_schema_id_field.get(parent_name).map(String::as_str)
}
BaseAttr::IsBase => None,
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gts-cli/src/gen_schemas.rs` around lines 460 - 471, After parsing attributes
with parse_macro_attrs(attr_body) you must validate that base structs do not
have const_values: after let Some(attrs) = parse_macro_attrs(attr_body) else {
... } add a check that if attrs.base == BaseAttr::IsBase and
attrs.const_values.is_some() then return or emit a CLI error (matching the macro
behavior) instead of silently ignoring; update the error path to include context
(struct name from the parsed item) so the CLI rejects the input consistently
with the macro.

Comment thread gts-macros/README.md Outdated
| Generated Item | Kind | Description |
|---|---|---|
| `new_instance_with_defaults()` | `fn -> Self` | Create instance with all fields defaulted; `GtsSchemaId` fields set to `M::SCHEMA_ID` |
| `new_instance_with_defaults(segment)` | `fn(&str) -> Self` | *(only if struct has exactly one `GtsInstanceId` field)* Same as above, plus builds the instance ID from `M::SCHEMA_ID` + segment |
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix markdown emphasis spacing.

Static analysis (markdownlint MD037) flags spaces inside emphasis markers. The italicized text *(only if struct has exactly one GtsInstanceId field)* has a space after the opening *.

📝 Proposed fix
-| `new_instance_with_defaults(segment)` | `fn(&str) -> Self` | *(only if struct has exactly one `GtsInstanceId` field)* Same as above, plus builds the instance ID from `M::SCHEMA_ID` + segment |
+| `new_instance_with_defaults(segment)` | `fn(&str) -> Self` | *(only if struct has exactly one `GtsInstanceId` field)* Same as above, plus builds the instance ID from `M::SCHEMA_ID` + segment |

Alternatively, remove the emphasis or ensure no spaces directly after *:

-*(only if struct has exactly one `GtsInstanceId` field)*
+*only if struct has exactly one `GtsInstanceId` field*
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 37-37: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gts-macros/README.md` at line 37, The italicized parenthetical in the README
table cell for `new_instance_with_defaults(segment)` contains extra spaces
inside the emphasis markers (the text `*(only if struct has exactly one
`GtsInstanceId` field)*`), triggering markdownlint MD037; fix it by removing the
space after the opening `*` and before the closing `*` so the emphasis is
`*(only if struct has exactly one `GtsInstanceId` field)*` becomes `*(only if
struct has exactly one `GtsInstanceId` field)*` (or remove the emphasis
entirely) to eliminate the inner spacing issue.

Comment on lines +5 to +15
#[struct_to_gts_schema(
dir_path = "schemas",
base = true,
schema_id = "gts.x.test.const.malformed.v1~",
description = "Malformed const_values test",
properties = "value",
const_values = "value_without_equals"
)]
pub struct MalformedConstV1 {
pub value: String,
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Malformed const_values is never reached due to base=true.
Line 7 makes this a base struct, and Line 11 then triggers the “const_values not allowed on base” error before malformed parsing is exercised. Consider splitting into a base struct plus a derived struct that carries the malformed const_values.

💡 Suggested restructure to exercise malformed parsing
 #[struct_to_gts_schema(
     dir_path = "schemas",
     base = true,
-    schema_id = "gts.x.test.const.malformed.v1~",
-    description = "Malformed const_values test",
-    properties = "value",
-    const_values = "value_without_equals"
+    schema_id = "gts.x.test.const.malformed.base.v1~",
+    description = "Malformed const_values test base",
+    properties = "value"
 )]
-pub struct MalformedConstV1 {
+pub struct MalformedConstBaseV1 {
     pub value: String,
 }
 
+#[struct_to_gts_schema(
+    dir_path = "schemas",
+    base = MalformedConstBaseV1,
+    schema_id = "gts.x.test.const.malformed.base.v1~x.test.const.malformed.v1~",
+    description = "Malformed const_values test",
+    properties = "",
+    const_values = "value_without_equals"
+)]
+pub struct MalformedConstV1;
+
 fn main() {}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[struct_to_gts_schema(
dir_path = "schemas",
base = true,
schema_id = "gts.x.test.const.malformed.v1~",
description = "Malformed const_values test",
properties = "value",
const_values = "value_without_equals"
)]
pub struct MalformedConstV1 {
pub value: String,
}
#[struct_to_gts_schema(
dir_path = "schemas",
base = true,
schema_id = "gts.x.test.const.malformed.base.v1~",
description = "Malformed const_values test base",
properties = "value"
)]
pub struct MalformedConstBaseV1 {
pub value: String,
}
#[struct_to_gts_schema(
dir_path = "schemas",
base = MalformedConstBaseV1,
schema_id = "gts.x.test.const.malformed.base.v1~x.test.const.malformed.v1~",
description = "Malformed const_values test",
properties = "",
const_values = "value_without_equals"
)]
pub struct MalformedConstV1;
fn main() {}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gts-macros/tests/compile_fail/const_values_malformed.rs` around lines 5 - 15,
The struct attribute uses base=true on MalformedConstV1 so the const_values
error is raised before malformed parsing; split into two structs: keep a base
struct (e.g., MalformedConstBase) annotated with #[struct_to_gts_schema(... base
= true ...)] and move the fields there (no const_values), then add a derived
struct (e.g., MalformedConstV1) annotated with #[struct_to_gts_schema(... base =
false, schema_id = "gts.x.test.const.malformed.v1~", const_values =
"value_without_equals", properties = "value" ...)] that references/extends the
base so the malformed const_values path on the derived struct is reached and
tested.

//! new_instance_with_defaults() is NOT generated — it would be ambiguous
//! which field to populate. Calling it must produce a compile error.

use gts::gts::{GtsInstanceId, GtsSchemaId};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check import patterns in compile_fail tests
echo "=== Import patterns in compile_fail tests ==="
rg -n "use gts::" gts-macros/tests/compile_fail/ -A 1

echo ""
echo "=== Check if GtsSchemaId is re-exported ==="
rg -n "pub use.*GtsSchemaId" --type rust

echo ""
echo "=== Check gts crate lib.rs structure ==="
find . -name "lib.rs" -path "*/gts/*" | head -5

Repository: GlobalTypeSystem/gts-rust

Length of output: 5219


Use the canonical import path for consistency.

Both gts::gts::{GtsInstanceId, GtsSchemaId} and gts::GtsSchemaId work because GtsSchemaId and GtsInstanceId are re-exported at the crate root in gts/src/lib.rs. However, the majority of compile-fail tests use the shorter canonical path use gts::GtsSchemaId; and use gts::GtsInstanceId;. Align this file with that convention:

-use gts::gts::{GtsInstanceId, GtsSchemaId};
+use gts::{GtsInstanceId, GtsSchemaId};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
use gts::gts::{GtsInstanceId, GtsSchemaId};
use gts::{GtsInstanceId, GtsSchemaId};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gts-macros/tests/compile_fail/two_instance_id_fields.rs` at line 5, The test
uses the non-canonical import path "use gts::gts::{GtsInstanceId, GtsSchemaId};"
— replace it with the crate-root re-exports by importing "GtsInstanceId" and
"GtsSchemaId" from "gts" directly (i.e., use gts::GtsInstanceId; use
gts::GtsSchemaId;) so the file follows the same canonical import style as other
compile-fail tests and references the same symbols GtsInstanceId and
GtsSchemaId.

Comment on lines +9 to +23
"properties": {
"event_type": {
"const": "gts.x.core.events.type.v1~x.core.simple.event.v1~"
},
"message": {
"type": "string"
},
"severity": {
"type": "integer"
}
},
"required": [
"message",
"severity"
]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

fd 'gts.x.core.events.type.v1~' gts-macros/tests/schemas --type f

Repository: GlobalTypeSystem/gts-rust

Length of output: 424


🏁 Script executed:

cat gts-macros/tests/schemas/gts.x.core.events.type.v1~.schema.json

Repository: GlobalTypeSystem/gts-rust

Length of output: 803


🏁 Script executed:

cat gts-macros/tests/schemas/gts.x.core.events.type.v1~x.core.simple.event.v1~.schema.json

Repository: GlobalTypeSystem/gts-rust

Length of output: 742


Add event_type to the required list.

The base schema gts.x.core.events.type.v1~ does not define or require event_type. Since const alone doesn't enforce property presence in JSON Schema, payloads without event_type would still validate. Include it in the local required list:

       "required": [
+        "event_type",
         "message",
         "severity"
       ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"properties": {
"event_type": {
"const": "gts.x.core.events.type.v1~x.core.simple.event.v1~"
},
"message": {
"type": "string"
},
"severity": {
"type": "integer"
}
},
"required": [
"message",
"severity"
]
"properties": {
"event_type": {
"const": "gts.x.core.events.type.v1~x.core.simple.event.v1~"
},
"message": {
"type": "string"
},
"severity": {
"type": "integer"
}
},
"required": [
"event_type",
"message",
"severity"
]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@gts-macros/tests/schemas/gts.x.core.events.type.v1`~x.core.simple.event.v1~.schema.json
around lines 9 - 23, The schema is missing event_type in its required array, so
add the "event_type" property name to the local "required" list in this JSON
Schema (the block defining properties with "event_type": { "const":
"gts.x.core.events.type.v1~x.core.simple.event.v1~" }), ensuring the schema
requires the event_type field in addition to "message" and "severity".

"$id": "gts://gts.x.test.alert.base.v1~",
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"description": "Alert payload base with channel, severity, kind, data fields",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Description mentions "kind" field that doesn't exist in properties.

The description states "Alert payload base with channel, severity, kind, data fields" but the schema defines channel, data, recipient, severity, and type — no kind property. Consider updating the description to match the actual fields.

📝 Suggested fix
-  "description": "Alert payload base with channel, severity, kind, data fields",
+  "description": "Alert payload base with channel, data, recipient, severity, type fields",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"description": "Alert payload base with channel, severity, kind, data fields",
"description": "Alert payload base with channel, data, recipient, severity, type fields",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gts-macros/tests/schemas/gts.x.test.alert.base.v1`~.schema.json at line 5,
Update the JSON schema "description" text to accurately reflect the defined
properties: replace the reference to "kind" with the actual property names
present (channel, data, recipient, severity, type) or add the missing "kind"
property if that was intended; locate the schema's top-level "description"
string and make it consistent with the properties array (channel, data,
recipient, severity, type) or adjust the properties to include "kind" and its
schema if needed.

Comment on lines +13 to +15
"kind": {
"const": "traffic"
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's locate the base schema file
find . -name "*gts.x.test.alert.base.v1~*" -type f | head -20

Repository: GlobalTypeSystem/gts-rust

Length of output: 218


🏁 Script executed:

# Also check the derived schema file being reviewed
find . -name "*gts.x.test.alert.base.v1~x.test.three.sms.v1~*" -type f

Repository: GlobalTypeSystem/gts-rust

Length of output: 153


🏁 Script executed:

# Read the base schema file
echo "=== BASE SCHEMA ==="
cat ./gts-macros/tests/schemas/gts.x.test.alert.base.v1~.schema.json

Repository: GlobalTypeSystem/gts-rust

Length of output: 842


🏁 Script executed:

# Read the derived schema file
echo "=== DERIVED SCHEMA ==="
cat ./gts-macros/tests/schemas/gts.x.test.alert.base.v1~x.test.three.sms.v1~.schema.json

Repository: GlobalTypeSystem/gts-rust

Length of output: 766


🏁 Script executed:

# Check if there are any test files or examples using these schemas
find . -type f -name "*.json" -o -name "*.rs" | xargs grep -l "gts.x.test.alert.base.v1~x.test.three.sms.v1~" 2>/dev/null | head -10

Repository: GlobalTypeSystem/gts-rust

Length of output: 194


🏁 Script executed:

# Also check for any test data or examples in the test schemas directory
ls -la ./gts-macros/tests/schemas/ | grep -i alert

Repository: GlobalTypeSystem/gts-rust

Length of output: 500


🏁 Script executed:

# Examine the test file that references this schema
cat ./gts-macros/tests/const_fields_tests.rs

Repository: GlobalTypeSystem/gts-rust

Length of output: 50381


🏁 Script executed:

# Check the structure of the SMS alert schema more carefully
cat ./gts-macros/tests/schemas/gts.x.test.alert.base.v1~x.test.three.sms.v1~.schema.json | jq '.allOf[1].properties | keys'

Repository: GlobalTypeSystem/gts-rust

Length of output: 118


🏁 Script executed:

# Verify if "data" has nested properties in the schema
cat ./gts-macros/tests/schemas/gts.x.test.alert.base.v1~x.test.three.sms.v1~.schema.json | jq '.allOf[1].properties.data'

Repository: GlobalTypeSystem/gts-rust

Length of output: 73


🏁 Script executed:

# Check if there are any test cases that try to validate instances against this schema
grep -r "gts.x.test.alert.base.v1~x.test.three.sms.v1~" . --include="*.rs" -A 5 -B 5

Repository: GlobalTypeSystem/gts-rust

Length of output: 3690


🏁 Script executed:

# Let's run the test that validates this schema to see if it actually fails
cd ./gts-macros && cargo test test_sms_schema_chain_child_valid -- --nocapture 2>&1 | tail -100

Repository: GlobalTypeSystem/gts-rust

Length of output: 315


Fix schema constraint violation: kind property must be nested under data, not flat in allOf.

The base schema gts.x.test.alert.base.v1~ has additionalProperties: false and defines only channel, data, recipient, severity, and type. The derived schema adds kind as a flat property in allOf[1].properties, which violates the base schema's additionalProperties constraint during validation.

The test expectations in const_fields_tests.rs (specifically test_three_event_l3_sms_has_conflicting_severity_const) document that kind should be nested under data.properties rather than placed flat at the top level. Move the kind const constraint into the data object structure to align with the base schema's property definitions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@gts-macros/tests/schemas/gts.x.test.alert.base.v1`~x.test.three.sms.v1~.schema.json
around lines 13 - 15, The derived schema places the "kind" const at top-level in
allOf[1].properties which violates the base schema's additionalProperties:false;
move the "kind" const into the "data" object's properties (i.e., under
data.properties.kind with the same const value) inside the derived schema so the
top-level only contains the allowed keys (channel, data, recipient, severity,
type); update the allOf entry that currently defines "kind" to nest it under
"data.properties" to satisfy the base schema and the expectation in
const_fields_tests.rs::test_three_event_l3_sms_has_conflicting_severity_const.

Comment on lines +10 to +18
"channel": {
"type": "string"
},
"data": {
"type": "object"
},
"recipient": {
"type": "string"
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find and examine the base schema file
find . -name "*gts.x.test.three.event.v1~*.schema.json" -type f | head -20

Repository: GlobalTypeSystem/gts-rust

Length of output: 332


🏁 Script executed:

# Examine the base schema
echo "=== BASE SCHEMA ==="
cat ./gts-macros/tests/schemas/gts.x.test.three.event.v1~.schema.json | jq .

echo ""
echo "=== DERIVED SCHEMA ==="
cat ./gts-macros/tests/schemas/gts.x.test.three.event.v1~x.test.three.alert.v1~.schema.json | jq .

Repository: GlobalTypeSystem/gts-rust

Length of output: 1680


🏁 Script executed:

# Let's check if there are any other schema files or test files that might indicate
# whether this is actually used with strict validation or if it's documented
find . -name "*.rs" -path "*/tests/*" | xargs grep -l "gts.x.test.three.event.v1" | head -5

Repository: GlobalTypeSystem/gts-rust

Length of output: 109


🏁 Script executed:

# Examine the test file to see how schemas are validated
cat ./gts-macros/tests/const_fields_tests.rs

Repository: GlobalTypeSystem/gts-rust

Length of output: 50381


Schema validation fails due to additionalProperties: false conflict in base.

The derived schema adds channel, data, and recipient properties, but the base schema has additionalProperties: false with only payload, severity, source, and type. This causes validation failures when instances include the derived properties—a known limitation documented in the test suite where schema chain validation explicitly rejects this structure with an "additionalProperties" error.

To resolve, consider:

  1. Using unevaluatedProperties: false (JSON Schema Draft 2019-09+) instead of additionalProperties: false in the base, or
  2. Nesting derived properties under the generic field (e.g., under payload) instead of placing them flat at the top level.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@gts-macros/tests/schemas/gts.x.test.three.event.v1`~x.test.three.alert.v1~.schema.json
around lines 10 - 18, The base schema's additionalProperties: false blocks the
derived schema's top-level properties channel, data, and recipient (present in
the derived schema file) causing validation failures; fix by updating the base
schema to use "unevaluatedProperties": false instead of "additionalProperties":
false (JSON Schema 2019-09+) so derived schemas can add properties via
$ref/allOf, or alternatively move channel, data, and recipient under the
existing payload object in the derived schema so they are nested rather than
top-level — update the base schema's constraint or refactor the derived schema
(properties: channel, data, recipient) accordingly.

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