Skip to content

Consolidate GTS ID logic into gts-id crate and add fallible type-safe constructors#101

Merged
Artifizer merged 8 commits into
GlobalTypeSystem:mainfrom
aviator5:gts-id-extraction
Jun 16, 2026
Merged

Consolidate GTS ID logic into gts-id crate and add fallible type-safe constructors#101
Artifizer merged 8 commits into
GlobalTypeSystem:mainfrom
aviator5:gts-id-extraction

Conversation

@aviator5

@aviator5 aviator5 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Centralizes all GTS ID-related logic into the gts-id crate. Previously, identifier handling was scattered between gts-id (parsing, validation) and gts (type/instance discrimination, UUID derivation, schema-aware wrappers). Now:

  • gts-id owns all ID primitives: parsing, validation, accessors, and UUID derivation (optional uuid feature)
  • gts re-exports primitives and provides only schema-aware wrappers (GtsTypeId, GtsInstanceId)

Key Changes:

  1. Modularized gts-id — Split into focused modules (parse, gts_id, gts_id_segment, gts_wildcard, error) with a tightened public API (field access via accessors: id(), segments(), into_segments())
  2. Type-safe constructors — Add GtsTypeId::try_new() and GtsInstanceId::try_new() for validating kind discrimination at compile time (replaces runtime ends_with('~') checks)
  3. UUID support in gts-id — Move UUID v5 derivation to gts-id as an optional feature. gts-macros depends on gts-id without it, keeping uuid out of the proc-macro build graph

Benefits

  • Single source of truth for ID logic
  • Cleaner separation of concerns
  • Type-safe discriminators reduce downstream errors
  • Lighter dependency graph for macros

Summary by CodeRabbit

Release Notes

  • New Features

    • Added optional UUID v5 deterministic generation for GTS identifiers.
    • Introduced pattern matching with wildcard support for flexible identifier queries.
  • Bug Fixes & Improvements

    • Enhanced error messages with precise segment location, offset, and expected format guidance.
    • Improved type safety through stricter identifier validation and concrete/wildcard discrimination.
    • Added path extraction support for identifiers with embedded routing information.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The gts-id crate is refactored from a monolithic lib.rs into five modules (error, parse, gts_id_segment, gts_id, gts_id_pattern). A new GtsId type replaces GtsID, GtsIdPattern replaces GtsWildcard, and GtsIdSegment exposes accessor methods instead of public fields. An opt-in uuid feature enables deterministic UUIDv5 generation. All consuming crates (gts, gts-macros, gts-validator) are migrated to the new API.

Changes

GTS ID Crate Extraction and System Migration

Layer / File(s) Summary
Error types and UUID feature wiring
gts-id/Cargo.toml, gts-id/src/error.rs
Adds opt-in uuid feature to the crate manifest; defines GtsIdSegmentError (segment number, byte offset, raw text) and GtsIdError (input, cause, optional segment) with two-format Display and std::error::Error impls.
Low-level identifier parsing infrastructure
gts-id/src/parse.rs
Introduces GTS_PREFIX/GTS_MAX_LENGTH constants, is_uuid, is_valid_segment_token, parse_u32_exact helpers, and parse_gts_id enforcing prefix/length/lowercase/wildcard/UUID-tail/hyphen/single-segment-#37 rules with enriched per-segment error messages and tests.
Segment parsing and accessors
gts-id/src/gts_id_segment.rs
Defines GtsIdSegmentParts, the opaque GtsIdSegment wrapper over a private GtsIdSegmentKind (concrete/wildcard/UUID-tail), accessor methods, feature-gated uuid() decoder, crate-private parse and uuid_tail_segment constructors, and comprehensive tests.
Validated concrete identifier type
gts-id/src/gts_id.rs
Implements GtsId::try_new, accessors (id, segments, is_type, get_type_id), is_valid, matches_pattern, split_at_path, optional to_uuid, Display/FromStr/AsRef impls, and test suite.
Wildcard pattern type and matching
gts-id/src/gts_id_pattern.rs
Implements GtsIdPattern with segment-level wildcard matching semantics, prefix-based covers reasoning, try_new via parse_gts_id with wildcards enabled, trait impls, and tests.
GTS-ID crate module root
gts-id/src/lib.rs
Transforms crate root from inline validation into module wiring re-exporting GtsIdError, GtsIdSegmentError, GtsId, GtsIdSegment, GtsIdSegmentParts, GtsIdPattern, and constants; removes validate_gts_id and prior helpers.
GTS crate integration and schema-aware types
gts/Cargo.toml, gts/src/gts.rs, gts/src/lib.rs, README.md
Re-exports gts-id API, removes GtsError/GtsID/GtsWildcard, adds GtsInstanceId::try_new and GtsTypeId::try_new with type-vs-instance discrimination, updates serde deserialization, enables uuid feature, and revises README architecture and usage examples.
Proc-macro validation update and error formatting
gts-macros/src/instance.rs, gts-macros/src/lib.rs, gts-macros/tests/compile_fail/*
Switches macro validation from validate_gts_id to GtsId::try_new, simplifies error formatting to Display, updates docs, and refreshes all compile-fail stderr fixtures with segment/offset diagnostics.
Integration test and fixture updates
gts-macros/tests/integration_tests.rs, gts-macros/tests/inheritance_tests.rs, gts-macros/tests/value_dispatch_tests.rs
Migrates all test assertions to GtsId::try_new, segments(), and accessor methods; fixes segment literals to conform to updated validation rules; updates dispatch and inheritance fixtures.
Validator and GtsEntity migration
gts-validator/src/validator.rs, gts-validator/src/format/markdown.rs, gts-validator/src/normalize.rs, gts/src/entities.rs
Migrates validator to GtsId::try_new/GtsIdPattern::try_new with segment-based vendor extraction; migrates GtsEntity public field and constructor parameter to Option<GtsId> with accessor-based ID/segment access throughout; updates doc comments.
Ops and schema_cast migration
gts/src/ops.rs, gts/src/schema_cast.rs, gts/src/x_gts_ref.rs
Refactors validate_id, parse_id, match_id_pattern, uuid, attr, and get_entity to use GtsId/GtsIdPattern; updates cast direction inference to use segments().last() and ver_minor(); updates all is_valid calls in x_gts_ref.
Store and store_test migration
gts/src/store.rs, gts/src/store_test.rs
Refactors schema registration, chain/traits validation, instance lookup, cast, and query pattern matching to use GtsId/GtsIdPattern APIs; enforces gts:// refs as type IDs via GtsTypeId::try_new; updates test infrastructure to match via effective_id() and revised error messages.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant gts_macros as gts-macros (proc-macro)
  participant GtsId
  participant parse_gts_id
  participant GtsIdSegment

  rect rgba(70, 130, 180, 0.5)
    note over Client,GtsIdSegment: Compile-time validation (gts_instance! / struct_to_gts_schema)
    Client->>gts_macros: #[gts_instance!] or #[struct_to_gts_schema]
    gts_macros->>GtsId: try_new(id_literal)
    GtsId->>parse_gts_id: parse_gts_id(id, allow_wildcards=false)
    parse_gts_id->>GtsIdSegment: parse(num, segment, false)
    GtsIdSegment-->>parse_gts_id: Ok(GtsIdSegment) or Err(segment msg)
    parse_gts_id-->>GtsId: Ok(Vec~GtsIdSegment~) or GtsIdError{segment: Some(...)}
    GtsId-->>gts_macros: Ok(GtsId) or GtsIdError
    gts_macros-->>Client: compile error with segment `#N` @ offset M
  end

  rect rgba(60, 179, 113, 0.5)
    note over Client,GtsIdSegment: Runtime validation (serde deserialization)
    Client->>GtsInstanceId: deserialize(str)
    GtsInstanceId->>GtsId: try_new(str)
    GtsId-->>GtsInstanceId: Result~GtsId, GtsIdError~
    GtsInstanceId->>GtsInstanceId: is_type() == false check
    GtsInstanceId-->>Client: Ok(GtsInstanceId) or serde error
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • GlobalTypeSystem/gts-rust#61: Both PRs modify the gts-id parsing pipeline to handle the combined anonymous instance "UUID tail" format via is_uuid helpers and UUID-tail segment construction.
  • GlobalTypeSystem/gts-rust#81: This PR updates gts-macros validation to call gts_id::GtsId::try_new with richer GtsIdError diagnostics, directly replacing the macro validation infrastructure introduced in PR #81.
  • GlobalTypeSystem/gts-rust#51: This PR replaces gts_id::validate_gts_id-based compile-time schema validation in struct_to_gts_schema with GtsId::try_new, updating the same stderr fixtures first established in PR #51.

Suggested reviewers

  • Artifizer
  • MikeFalcon77

Poem

🐇 Hop, hop, the old GtsID is gone,
A shiny GtsId with accessors leads on!
Segments parsed, wildcards contained,
UUID tails and patterns explained.
The rabbit nods — this crate stands alone,
Clean modules, sharp types, a foundation well-sown! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: consolidating GTS ID logic into gts-id crate and adding type-safe constructors. It is specific, clear, and directly reflects the primary objectives of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codecov-commenter

codecov-commenter commented Jun 12, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 97.18805% with 48 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
gts-id/src/gts_id_segment.rs 96.96% 14 Missing ⚠️
gts-id/src/gts_id_pattern.rs 97.61% 9 Missing ⚠️
gts-id/src/parse.rs 98.02% 6 Missing ⚠️
gts-validator/src/validator.rs 54.54% 5 Missing ⚠️
gts/src/ops.rs 96.00% 4 Missing ⚠️
gts/src/store.rs 87.09% 4 Missing ⚠️
gts/src/entities.rs 90.90% 3 Missing ⚠️
gts/src/gts.rs 95.91% 2 Missing ⚠️
gts/src/store_test.rs 83.33% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
gts/src/gts.rs (1)

83-90: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate serde input through the typed constructors.

Line 89 and Line 293 now accept any string and wrap it directly, so invalid IDs or type/instance mismatches can be deserialized into GtsInstanceId / GtsTypeId without error. That breaks the new type-safe-constructor invariant right at the external input boundary.

Proposed fix
 impl<'de> serde::Deserialize<'de> for GtsInstanceId {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
         let s = String::deserialize(deserializer)?;
-        Ok(GtsInstanceId(GtsEntityId::new(&s)))
+        GtsInstanceId::try_new(&s).map_err(serde::de::Error::custom)
     }
 }
@@
 impl<'de> serde::Deserialize<'de> for GtsTypeId {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
         D: serde::Deserializer<'de>,
     {
         let s = String::deserialize(deserializer)?;
-        Ok(GtsTypeId(GtsEntityId::new(&s)))
+        GtsTypeId::try_new(&s).map_err(serde::de::Error::custom)
     }
 }

Also applies to: 287-294

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gts/src/gts.rs` around lines 83 - 90, The Deserialize impls currently accept
any string and wrap it directly (in impl serde::Deserialize for GtsInstanceId
and the analogous impl for GtsTypeId), bypassing the type-safe constructors;
change each impl to parse/validate the deserialized string via the public typed
constructor/validator (e.g., call GtsInstanceId::try_from /
GtsInstanceId::from_str / GtsInstanceId::parse or the crate's equivalent
validated constructor) and map any construction error into a serde error with
serde::de::Error::custom so invalid IDs fail deserialization rather than being
wrapped unvalidated. Ensure you apply the same pattern to the GtsTypeId
deserializer as well.
gts/src/entities.rs (1)

263-285: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Rebuild the parent chain without adding a second ~ separator.

Each GtsIdSegment.segment already carries its trailing ~ for type segments, so join("~") produces malformed parents once the chain is deeper than two segments. A schema like gts.a.v1~b.v1~c.v1~ will derive gts.a.v1~~b.v1~, which breaks type_id-based parent resolution.

Suggested fix
-                let parent_segments: Vec<&str> = gts_id
-                    .segments()
-                    .iter()
-                    .take(gts_id.segments().len() - 1)
-                    .map(|seg| seg.segment.as_str())
-                    .collect();
-                if !parent_segments.is_empty() {
-                    // Join segments - they already have ~ at the end if they're types
-                    // The full chain format is: gts.seg1~seg2~seg3~
-                    // For parent, we want: gts.seg1~ (if only one parent segment)
-                    // or gts.seg1~seg2~ (if multiple parent segments)
-                    let parent_id = format!("gts.{}", parent_segments.join("~"));
+                let parent_segments: Vec<&str> = gts_id
+                    .segments()
+                    .iter()
+                    .take(gts_id.segments().len() - 1)
+                    .map(|seg| seg.segment.as_str())
+                    .collect();
+                if !parent_segments.is_empty() {
+                    let parent_id = format!("gts.{}", parent_segments.concat());
                     // Ensure it ends with ~ (parent is always a schema)
                     let parent_id = if parent_id.ends_with('~') {
                         parent_id
                     } else {
                         format!("{parent_id}~")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gts/src/entities.rs` around lines 263 - 285, The parent chain construction is
adding extra "~" because each GtsIdSegment.segment already includes its trailing
"~"; in the block with self.gts_id (and variables parent_segments and parent_id)
stop using join("~") and instead concatenate the segment strings directly (e.g.,
join("") or fold) to avoid inserting another "~" between segments, then prefix
with "gts." and ensure a single trailing '~' (check parent_id.ends_with('~') and
append one only if missing).
🧹 Nitpick comments (1)
gts/src/ops.rs (1)

569-585: ⚡ Quick win

Add regression coverage for the new pattern parsing branches.

This path now depends on GtsWildcard::new continuing to accept zero-* concrete patterns, and on the new candidate.contains('*') branch behaving as intended. Please add one exact-pattern test and one wildcard-candidate test so future parser changes do not silently alter match_id_pattern semantics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gts/src/ops.rs` around lines 569 - 585, Add two unit tests for
match_id_pattern: one that passes a concrete pattern and concrete candidate (no
'*' in either) to verify GtsWildcard::new accepts zero-'*' patterns and
match_id_pattern returns a match for exact ids, and one that passes a wildcard
candidate (candidate contains '*') with a wildcard pattern to verify the
candidate.contains('*') branch uses GtsWildcard::new for the candidate and
matching behaves as expected; locate match_id_pattern and exercise it directly
in tests (e.g., test_exact_pattern_matches and test_wildcard_candidate_matches)
asserting the returned GtsIdMatchResult indicates success and the expected
matched segments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@gts-id/src/gts_id.rs`:
- Around line 99-106: is_valid currently checks GTS_PREFIX on the raw input so
strings with leading/trailing whitespace (which GtsID::new trims) are rejected;
fix is_valid by applying the same trimming as new() (trim the input string
first, e.g., to a trimmed &str) and then perform the prefix check and call
Self::new on the trimmed value so both methods accept the same inputs (refer to
is_valid, Self::new, and GTS_PREFIX).

In `@gts-id/src/gts_wildcard.rs`:
- Around line 126-178: The overlaps() and is_subset_of() helpers currently use
prefix_str and raw string prefix checks which miss segment-level rules (e.g.
absent ver_minor matches any minor); change both to parse the patterns into
segments using the same parser used by matches_segments() and perform
segment-wise comparisons: for overlaps(), determine whether there exists a
concrete ID that would satisfy both segment constraints (treat absent ver_minor
as a wildcard that matches any numeric minor), and for is_subset_of(), ensure
every segment in self is at least as specific as other (i.e. any absent/
wildcard in other accepts the concrete values in self, and a present concrete
minor in self must match other or be accepted by other’s wildcard/absent minor).
Replace uses of prefix_str in overlaps/is_subset_of with this segment-aware
logic and reuse/mirror matches_segments() semantics to keep behavior consistent.
- Around line 47-123: The function matches_segments currently returns true for
exact patterns even when the candidate is longer; change the final unconditional
"true" to require equal segment counts when no wildcard was hit by replacing the
final return with "pattern_segs.len() == candidate.len()". Keep existing early
return behavior inside the p_seg.is_wildcard branch (which should still accept
any remaining segments), and ensure this check is applied in matches_segments
(use the pattern_segs and candidate variables to locate the code).

In `@gts/src/store_test.rs`:
- Around line 2210-2214: The mock reader's read_by_id currently matches only on
e.g. gts_id but GtsStore::populate_from_reader() keys by effective_id(), so
update the read_by_id implementation to compare the provided entity_id against
the entity's effective_id() (call the GtsEntity method effective_id()) instead
of gts_id; keep the rest of the iterator chain and cloning behavior the same so
tests resolve entities addressable only via their effective ID.

---

Outside diff comments:
In `@gts/src/entities.rs`:
- Around line 263-285: The parent chain construction is adding extra "~" because
each GtsIdSegment.segment already includes its trailing "~"; in the block with
self.gts_id (and variables parent_segments and parent_id) stop using join("~")
and instead concatenate the segment strings directly (e.g., join("") or fold) to
avoid inserting another "~" between segments, then prefix with "gts." and ensure
a single trailing '~' (check parent_id.ends_with('~') and append one only if
missing).

In `@gts/src/gts.rs`:
- Around line 83-90: The Deserialize impls currently accept any string and wrap
it directly (in impl serde::Deserialize for GtsInstanceId and the analogous impl
for GtsTypeId), bypassing the type-safe constructors; change each impl to
parse/validate the deserialized string via the public typed
constructor/validator (e.g., call GtsInstanceId::try_from /
GtsInstanceId::from_str / GtsInstanceId::parse or the crate's equivalent
validated constructor) and map any construction error into a serde error with
serde::de::Error::custom so invalid IDs fail deserialization rather than being
wrapped unvalidated. Ensure you apply the same pattern to the GtsTypeId
deserializer as well.

---

Nitpick comments:
In `@gts/src/ops.rs`:
- Around line 569-585: Add two unit tests for match_id_pattern: one that passes
a concrete pattern and concrete candidate (no '*' in either) to verify
GtsWildcard::new accepts zero-'*' patterns and match_id_pattern returns a match
for exact ids, and one that passes a wildcard candidate (candidate contains '*')
with a wildcard pattern to verify the candidate.contains('*') branch uses
GtsWildcard::new for the candidate and matching behaves as expected; locate
match_id_pattern and exercise it directly in tests (e.g.,
test_exact_pattern_matches and test_wildcard_candidate_matches) asserting the
returned GtsIdMatchResult indicates success and the expected matched segments.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 169b359d-ec92-4065-b242-93753a39c308

📥 Commits

Reviewing files that changed from the base of the PR and between d3d4a40 and 715d929.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (28)
  • gts-id/Cargo.toml
  • gts-id/src/error.rs
  • gts-id/src/gts_id.rs
  • gts-id/src/gts_id_segment.rs
  • gts-id/src/gts_wildcard.rs
  • gts-id/src/lib.rs
  • gts-id/src/parse.rs
  • gts-macros/src/instance.rs
  • gts-macros/src/lib.rs
  • gts-macros/tests/compile_fail/instance_id_invalid_format.rs
  • gts-macros/tests/compile_fail/instance_id_invalid_format.stderr
  • gts-macros/tests/compile_fail/instance_id_wildcard_in_instance.rs
  • gts-macros/tests/compile_fail/instance_id_wildcard_in_instance.stderr
  • gts-macros/tests/compile_fail/instance_raw_no_tilde.stderr
  • gts-macros/tests/compile_fail/invalid_gts_id_missing_prefix.stderr
  • gts-macros/tests/compile_fail/invalid_gts_id_too_many_tokens.stderr
  • gts-macros/tests/compile_fail/version_missing_both.stderr
  • gts-macros/tests/compile_fail/version_missing_in_schema.stderr
  • gts-macros/tests/integration_tests.rs
  • gts-validator/src/validator.rs
  • gts/Cargo.toml
  • gts/src/entities.rs
  • gts/src/gts.rs
  • gts/src/lib.rs
  • gts/src/ops.rs
  • gts/src/schema_cast.rs
  • gts/src/store.rs
  • gts/src/store_test.rs

Comment thread gts-id/src/gts_id.rs
Comment thread gts-id/src/gts_id_pattern.rs Outdated
Comment thread gts-id/src/gts_id_pattern.rs Outdated
Comment thread gts/src/store_test.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
README.md (1)

57-78: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update the architecture section for the extracted gts-id crate.

This section still says the workspace is just gts plus gts-cli, and it still describes gts.rs as the home of ID parsing and wildcard matching. After this extraction, that crate boundary description is stale for readers following the new ID API.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 57 - 78, Update the architecture section to reflect
the extracted gts-id crate: replace references that say ID parsing/wildcard
matching live in gts.rs or the gts crate with a note that those responsibilities
are now provided by the new gts-id crate (mention gts-id crate name explicitly),
move "GTS ID parsing, validation, wildcard matching" from the gts (Library
Crate) entry to a new bullet for gts-id, and adjust the workspace list to
include three crates: gts, gts-id, and gts-cli so readers can find the new ID
API.
gts-id/src/parse.rs (1)

125-138: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Allow terminal *~ wildcard segments.

Line 132 only accepts wildcard IDs ending in .* or ~*, so patterns like gts.*~ or gts.x.core.events.event.v1.*~ are rejected before GtsIdSegment::parse can set is_type = true. That conflicts with the segment parser and with gts-id/src/gts_id_wildcard.rs, which already uses is_type() to distinguish wildcard type matching from instance matching. Widen the suffix gate to accept terminal *~ and add a regression test for it.

Proposed fix
-        if raw.contains('*') && !raw.ends_with(".*") && !raw.ends_with("~*") {
+        if raw.contains('*')
+            && !raw.ends_with(".*")
+            && !raw.ends_with("~*")
+            && !raw.ends_with("*~")
+        {
             return Err(GtsIdError::new(
                 id,
                 "The wildcard '*' token is allowed only at the end of the pattern",
             ));
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gts-id/src/parse.rs` around lines 125 - 138, The current gate in parse.rs (in
the allow_wildcards block checking raw.ends_with(".*") || raw.ends_with("~*"))
wrongly rejects terminal "*~" suffixes; update the condition to also accept
raw.ends_with("*~") so terminal "*~" wildcards like "gts.*~" or
"gts.x.core.events.event.v1.*~" pass through to GtsIdSegment::parse (which sets
is_type()) and remain consistent with gts-id/src/gts_id_wildcard.rs and its
is_type() behavior; after changing the suffix check, add a regression test that
parses a wildcard ID ending in "*~" and asserts it is accepted and treated as a
type wildcard.
gts/src/entities.rs (1)

268-285: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Rebuild the parent type_id without injecting extra ~ separators.

Line 279 joins GtsIdSegment::raw() with "~", but raw() already carries the trailing ~ for type segments. That makes 3+ segment schema chains derive invalid parents like gts.a~~b~, so nested schema lookup/cast logic ends up keyed by the wrong type_id.

Suggested fix
                 let parent_segments: Vec<&str> = gts_id
                     .segments()
                     .iter()
                     .take(gts_id.segments().len() - 1)
                     .map(gts_id::GtsIdSegment::raw)
                     .collect();
                 if !parent_segments.is_empty() {
-                    let parent_id = format!("gts.{}", parent_segments.join("~"));
-                    // Ensure it ends with ~ (parent is always a schema)
-                    let parent_id = if parent_id.ends_with('~') {
-                        parent_id
-                    } else {
-                        format!("{parent_id}~")
-                    };
+                    let parent_id = format!("gts.{}", parent_segments.join(""));
                     // Use parent from chain as type_id when current value isn't
                     // already a GTS Type Identifier (e.g. $schema held a JSON
                     // Schema dialect URL, or no $schema was present).

Cross-file evidence: gts-id/src/gts_id.rs reconstructs type IDs by concatenating GtsIdSegment::raw() values with join("").

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gts/src/entities.rs` around lines 268 - 285, The parent type_id is being
built by joining GtsIdSegment::raw() with "~", but raw() already includes
trailing '~', producing duplicate separators (e.g., "gts.a~~b~"); update the
construction in the block using parent_segments/GtsIdSegment::raw() so you
concatenate the raw pieces without inserting additional "~" (e.g., join with ""
or strip the extra "~" before joining), then ensure the final parent_id string
still ends with a single '~' (keep the existing ends_with check), so parent_id
is always "gts.<segments>~" with no doubled tildes.
♻️ Duplicate comments (1)
gts/src/store_test.rs (1)

2210-2215: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Past review concern remains unaddressed: mock should match on effective_id().

The refactor updated the accessor syntax to gts_id::GtsId::id, but the underlying issue flagged in the previous review persists: MockGtsReader::read_by_id still matches on e.gts_id instead of e.effective_id(), causing the mock to diverge from how GtsStore::populate_from_reader() keys entities.

🔧 Suggested fix
     fn read_by_id(&self, entity_id: &str) -> Option<GtsEntity> {
         self.entities
             .iter()
-            .find(|e| e.gts_id.as_ref().map(gts_id::GtsId::id) == Some(entity_id))
+            .find(|e| e.effective_id().as_deref() == Some(entity_id))
             .cloned()
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gts/src/store_test.rs` around lines 2210 - 2215, The mock's read_by_id
implementation is matching on the raw gts_id field instead of using the entity's
effective_id(), so update MockGtsReader::read_by_id to compare the passed
entity_id against e.effective_id() (mirroring GtsStore::populate_from_reader)
and return the cloned GtsEntity when they match; locate the read_by_id function
in the test and replace the current e.gts_id-based comparison with a call to the
GtsEntity::effective_id accessor (or equivalent) so the mock behavior matches
production keying.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@gts-id/src/gts_id_segment.rs`:
- Around line 44-52: The public enum GtsIdSegment exposes UuidTail(String)
allowing callers to forge invalid UUID tails; make the inner enum private
(rename or move the current GtsIdSegment to a private enum like
GtsIdSegmentInner) and provide a public opaque wrapper type (e.g., pub struct
GtsIdSegment) with controlled constructors such as
GtsIdSegment::from_uuid_tail(uuid::Uuid) and parsing constructors that validate
and only produce a UuidTail when the string is a valid UUID; make all enum
variants and their fields private, update the accessor uuid() to rely on the
validated internal representation and return a guaranteed Some(uuid::Uuid) (or
Option only when appropriate), and adjust parsing/creation call sites to use the
new public constructors and accessors so downstream crates cannot construct or
relabel variants directly.

In `@gts/src/ops.rs`:
- Around line 45-50: The serialization currently always sets
GtsIdSegmentInfo.ver_major to Some(seg.ver_major()), which turns the wildcard
sentinel 0 into an explicit 0; change the assignment in ops.rs so ver_major is
None when seg.ver_major() == 0 and Some(value) otherwise (i.e., preserve the "no
major version" sentinel), leaving ver_minor and other fields unchanged; locate
the code around the construction of GtsIdSegmentInfo (using symbols seg and
GtsIdSegmentInfo.ver_major) and replace the unconditional Some(...) with a
conditional mapping that returns None for 0.

In `@gts/src/store.rs`:
- Around line 604-606: The current check only calls GtsId::is_valid on the
stripped ref_uri which allows non-schema targets like instance IDs; change the
validation to reject non-schema IDs by either attempting to construct/parse a
schema/type ID (using the same constructor used by GtsRetriever::new) or at
minimum require the stripped gts_id to be a type/schema ID (e.g., ensure it ends
with the type marker `~`) before accepting the $ref; update the branch that
inspects ref_uri (and the GTS_URI_PREFIX check) to perform that stronger
validation so only schema/type targets accepted, matching entity.is_schema
registration in GtsRetriever::new.

In `@README.md`:
- Around line 567-570: The README examples use the removed field
GtsId::gts_id_segments and the old wildcard check GtsIdWildcard::matches(&id);
update those snippets to call the current public API instead: drop any direct
access to gts_id_segments and use GtsId's public accessor(s) or methods for
inspecting segments, and replace uses of GtsIdWildcard::matches(&id) with the
documented GtsId::wildcard_match call; apply the same fixes to both affected
examples (the snippet around the former gts_id_segments usage and the one at the
later location noted in the comment).

---

Outside diff comments:
In `@gts-id/src/parse.rs`:
- Around line 125-138: The current gate in parse.rs (in the allow_wildcards
block checking raw.ends_with(".*") || raw.ends_with("~*")) wrongly rejects
terminal "*~" suffixes; update the condition to also accept raw.ends_with("*~")
so terminal "*~" wildcards like "gts.*~" or "gts.x.core.events.event.v1.*~" pass
through to GtsIdSegment::parse (which sets is_type()) and remain consistent with
gts-id/src/gts_id_wildcard.rs and its is_type() behavior; after changing the
suffix check, add a regression test that parses a wildcard ID ending in "*~" and
asserts it is accepted and treated as a type wildcard.

In `@gts/src/entities.rs`:
- Around line 268-285: The parent type_id is being built by joining
GtsIdSegment::raw() with "~", but raw() already includes trailing '~', producing
duplicate separators (e.g., "gts.a~~b~"); update the construction in the block
using parent_segments/GtsIdSegment::raw() so you concatenate the raw pieces
without inserting additional "~" (e.g., join with "" or strip the extra "~"
before joining), then ensure the final parent_id string still ends with a single
'~' (keep the existing ends_with check), so parent_id is always
"gts.<segments>~" with no doubled tildes.

In `@README.md`:
- Around line 57-78: Update the architecture section to reflect the extracted
gts-id crate: replace references that say ID parsing/wildcard matching live in
gts.rs or the gts crate with a note that those responsibilities are now provided
by the new gts-id crate (mention gts-id crate name explicitly), move "GTS ID
parsing, validation, wildcard matching" from the gts (Library Crate) entry to a
new bullet for gts-id, and adjust the workspace list to include three crates:
gts, gts-id, and gts-cli so readers can find the new ID API.

---

Duplicate comments:
In `@gts/src/store_test.rs`:
- Around line 2210-2215: The mock's read_by_id implementation is matching on the
raw gts_id field instead of using the entity's effective_id(), so update
MockGtsReader::read_by_id to compare the passed entity_id against
e.effective_id() (mirroring GtsStore::populate_from_reader) and return the
cloned GtsEntity when they match; locate the read_by_id function in the test and
replace the current e.gts_id-based comparison with a call to the
GtsEntity::effective_id accessor (or equivalent) so the mock behavior matches
production keying.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ae460a03-4a8f-4c75-9a21-7d23a43bfca4

📥 Commits

Reviewing files that changed from the base of the PR and between 715d929 and c581c98.

📒 Files selected for processing (23)
  • README.md
  • gts-id/src/error.rs
  • gts-id/src/gts_id.rs
  • gts-id/src/gts_id_segment.rs
  • gts-id/src/gts_id_wildcard.rs
  • gts-id/src/lib.rs
  • gts-id/src/parse.rs
  • gts-macros/src/instance.rs
  • gts-macros/src/lib.rs
  • gts-macros/tests/compile_fail/instance_id_invalid_format.rs
  • gts-macros/tests/compile_fail/instance_id_wildcard_in_instance.rs
  • gts-macros/tests/integration_tests.rs
  • gts-validator/src/format/markdown.rs
  • gts-validator/src/normalize.rs
  • gts-validator/src/validator.rs
  • gts/src/entities.rs
  • gts/src/gts.rs
  • gts/src/lib.rs
  • gts/src/ops.rs
  • gts/src/schema_cast.rs
  • gts/src/store.rs
  • gts/src/store_test.rs
  • gts/src/x_gts_ref.rs
✅ Files skipped from review due to trivial changes (5)
  • gts-validator/src/format/markdown.rs
  • gts-macros/tests/compile_fail/instance_id_invalid_format.rs
  • gts-validator/src/normalize.rs
  • gts/src/x_gts_ref.rs
  • gts-macros/tests/compile_fail/instance_id_wildcard_in_instance.rs
🚧 Files skipped from review as they are similar to previous changes (6)
  • gts-macros/src/instance.rs
  • gts/src/schema_cast.rs
  • gts-validator/src/validator.rs
  • gts-id/src/error.rs
  • gts/src/gts.rs
  • gts-id/src/gts_id.rs

Comment thread gts-id/src/gts_id_segment.rs Outdated
Comment thread gts/src/ops.rs
Comment thread gts/src/store.rs Outdated
Comment thread README.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@gts-id/src/gts_id_segment.rs`:
- Around line 127-130: The is_wildcard method currently moves the
GtsIdSegmentKind out of self by using matches!(self.0, ...); change the pattern
to borrow the enum instead (match on &self.0) so you don't move the contained
String—update the matches! invocation in pub fn is_wildcard(&self) -> bool to
use &self.0 and keep the same pattern GtsIdSegmentKind::Wildcard(_) to avoid
ownership errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97c54a1e-9d45-4bfd-b1c3-96dcdda7aa05

📥 Commits

Reviewing files that changed from the base of the PR and between c581c98 and aa1c5d5.

📒 Files selected for processing (6)
  • README.md
  • gts-id/src/gts_id.rs
  • gts-id/src/gts_id_segment.rs
  • gts/src/ops.rs
  • gts/src/store.rs
  • gts/src/store_test.rs
💤 Files with no reviewable changes (1)
  • gts-id/src/gts_id.rs
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • gts/src/ops.rs

Comment thread gts-id/src/gts_id_segment.rs Outdated
@aviator5 aviator5 force-pushed the gts-id-extraction branch from aa1c5d5 to eee7b52 Compare June 12, 2026 14:26
Comment thread gts/src/gts.rs Outdated
{
let s = String::deserialize(deserializer)?;
Ok(GtsInstanceId(GtsEntityId(s)))
Ok(GtsInstanceId(GtsEntityId::new(&s)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Serde deserialization still bypasses the new validated constructors. This accepts invalid IDs and also allows a type ID to deserialize as GtsInstanceId even though GtsInstanceId::try_new rejects it. Could we route this through the validated constructor instead, e.g. GtsInstanceId::try_new(&s).map_err(serde::de::Error::custom)? Same issue applies to GtsTypeId below, which should use GtsTypeId::try_new(&s).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

@Artifizer

Copy link
Copy Markdown
Contributor

One remaining issue I noticed in gts/src/entities.rs around the parent-chain reconstruction (let parent_id = format!("gts.{}", parent_segments.join("~"));): GtsIdSegment::raw() already includes the trailing ~ for type segments, so joining those raw segments with another "~" introduces double tildes for parent chains with more than one parent segment, e.g. gts.seg1~~seg2~. GtsId::get_type_id() already computes this parent ID correctly by joining raw segments with ""; could we use that here instead of hand-rolling the reconstruction?

Comment thread gts-id/src/gts_id.rs
// Delegate all parsing to the shared parser (single source of truth).
// `allow_wildcards = false`: a concrete identifier never contains '*'.
let segments = parse_gts_id(raw, false)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This changes GtsId::new/GtsId::is_valid behavior compared with the current gts::GtsID: the old constructor delegated to validate_gts_id(raw, true), so strings like gts.x.core.* were considered valid by GtsID::is_valid, while this now rejects wildcards. That tightening may be the right model for a concrete GtsId, but it affects every migrated is_valid call site (for example ref discovery / pointer-resolved values that may contain wildcard refs). Could we call this out in the PR description and add a regression test for the intended behavior?

@aviator5 aviator5 Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Now there are two structs in gts-id crate:

  1. GtsId - validated GTS identifier.
  2. GtsIdPattern - GTS identifier match pattern (exact or trailing-* wildcard).

Both structs have try_new() constructors and is_valid() helper-methods that could be used for different cases. So, for example, for ref discovery, you need to use GtsIdPattern, for validating concrete id in the macros - GtsId, etc.

I've prepared gts-id/README.md where shortly described all available functionality of the gts-id crate.

Comment thread gts-id/src/parse.rs Outdated
"The wildcard '*' token is allowed only once",
));
}
if raw.contains('*') && !raw.ends_with(".*") && !raw.ends_with("~*") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There is still an inconsistency around *~: the pattern-level rule only accepts wildcard patterns ending in .* or ~*, so gts.a.b.*~ is rejected here, but GtsIdSegment::parse can parse *~ as a wildcard with is_type = true, and matches_segments has an is_type check in its wildcard arm. Since the PR is centralizing parsing semantics, could we either accept *~ at the pattern level or remove the unreachable wildcard-is_type handling from the segment parser/matcher?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

@Artifizer

Copy link
Copy Markdown
Contributor

Versioning/rebase note: this branch is behind origin/main (main has the v0.10.1 bump), while the PR branch still declares 0.10.0. The PR also removes/renames public APIs across gts/gts-id (GtsError, GtsID, GtsWildcard, field-access GtsIdSegment, validate_gts_id/validate_segment/ParsedSegment, and GtsEntityId is no longer public). Before publishing, could we rebase onto main and bump the affected crates to the next breaking version, e.g. 0.11.0?

@aviator5 aviator5 force-pushed the gts-id-extraction branch 3 times, most recently from 53de854 to 6f2829f Compare June 15, 2026 11:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@gts-id/src/gts_id.rs`:
- Around line 373-377: The test cases in test_gts_id_invalid_characters function
are incomplete GTS IDs that fail on segment count validation before testing the
invalid character handling. Modify each test input to be a complete,
structurally valid GTS ID with the proper number of segments, but keep only the
target token malformed with invalid characters. This ensures the assertions
actually exercise the invalid-character validation logic rather than passing on
a "too few segments" error. Apply the same fix pattern to all similar
malformed-token test cases in the test suite that currently use incomplete ID
inputs.

In `@gts-macros/tests/inheritance_tests.rs`:
- Around line 841-843: The test in inheritance_tests.rs uses weak assertions
with contains() and ends_with() to validate the generated instance ID, which
could pass even with unexpected intermediate text. Since the generated ID is
deterministic, replace the two separate assert! calls (the one checking for
contains("gts.x.core.events.topic.v1~") and the one checking for
ends_with(segment)) with a single assert_eq! that validates the exact expected
ID value constructed from the known prefix and the segment variable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 772062a6-8b03-4e8c-b121-cceb301029b2

📥 Commits

Reviewing files that changed from the base of the PR and between aa1c5d5 and 6f2829f.

📒 Files selected for processing (17)
  • README.md
  • gts-id/src/gts_id.rs
  • gts-id/src/gts_id_segment.rs
  • gts-id/src/gts_id_wildcard.rs
  • gts-id/src/parse.rs
  • gts-macros/tests/inheritance_tests.rs
  • gts-macros/tests/integration_tests.rs
  • gts-macros/tests/value_dispatch_tests.rs
  • gts-validator/src/format/markdown.rs
  • gts-validator/src/normalize.rs
  • gts-validator/src/validator.rs
  • gts/src/entities.rs
  • gts/src/gts.rs
  • gts/src/ops.rs
  • gts/src/schema_cast.rs
  • gts/src/store.rs
  • gts/src/store_test.rs
✅ Files skipped from review due to trivial changes (4)
  • gts-validator/src/format/markdown.rs
  • gts-macros/tests/value_dispatch_tests.rs
  • README.md
  • gts-validator/src/normalize.rs
🚧 Files skipped from review as they are similar to previous changes (10)
  • gts/src/schema_cast.rs
  • gts-validator/src/validator.rs
  • gts/src/store_test.rs
  • gts-id/src/parse.rs
  • gts-macros/tests/integration_tests.rs
  • gts/src/ops.rs
  • gts/src/gts.rs
  • gts/src/entities.rs
  • gts/src/store.rs
  • gts-id/src/gts_id_segment.rs

Comment thread gts-id/src/gts_id.rs
Comment thread gts-macros/tests/inheritance_tests.rs Outdated
@aviator5 aviator5 force-pushed the gts-id-extraction branch from 6f2829f to cf2afe8 Compare June 15, 2026 13:15

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
gts-id/src/gts_id.rs (1)

373-414: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use complete IDs in the malformed-token tests.

These test inputs have fewer than the required six parts (e.g., gts.x.test!.v1~ has only four: prefix, vendor, malformed-package, version), so they fail on segment-count validation before the parser can exercise the targeted invalid-character or invalid-start rules.

Constructing each test case with the full gts.vendor.package.namespace.type.version structure—inserting the malformed token into one of the five required fields—will ensure the assertions actually validate the intended character/start rules.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gts-id/src/gts_id.rs` around lines 373 - 414, The test cases in
test_gts_id_invalid_characters, test_gts_id_uppercase_rejected,
test_gts_id_hyphen_rejected, test_gts_id_digit_start_segment, and
test_gts_id_segment_start_underscore are using incomplete GtsId structures with
fewer than six required parts. These incomplete IDs fail segment-count
validation before the parser can exercise the targeted character or
start-position validation rules. Update each test case to use the complete
six-part structure gts.vendor.package.namespace.type.version by inserting the
malformed token into the appropriate segment being tested while providing valid
values for all other required segments. For example, in
test_gts_id_invalid_characters, expand inputs like gts.x.test!.v1~ to
gts.x.test!.namespace.type.v1~ to ensure the invalid-character validation
actually executes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@gts-id/src/gts_id.rs`:
- Around line 373-414: The test cases in test_gts_id_invalid_characters,
test_gts_id_uppercase_rejected, test_gts_id_hyphen_rejected,
test_gts_id_digit_start_segment, and test_gts_id_segment_start_underscore are
using incomplete GtsId structures with fewer than six required parts. These
incomplete IDs fail segment-count validation before the parser can exercise the
targeted character or start-position validation rules. Update each test case to
use the complete six-part structure gts.vendor.package.namespace.type.version by
inserting the malformed token into the appropriate segment being tested while
providing valid values for all other required segments. For example, in
test_gts_id_invalid_characters, expand inputs like gts.x.test!.v1~ to
gts.x.test!.namespace.type.v1~ to ensure the invalid-character validation
actually executes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4dc1c32d-e404-452f-8e76-45456b3065c2

📥 Commits

Reviewing files that changed from the base of the PR and between 6f2829f and cf2afe8.

📒 Files selected for processing (23)
  • README.md
  • gts-id/src/gts_id.rs
  • gts-id/src/gts_id_pattern.rs
  • gts-id/src/gts_id_segment.rs
  • gts-id/src/lib.rs
  • gts-id/src/parse.rs
  • gts-macros/src/instance.rs
  • gts-macros/src/lib.rs
  • gts-macros/tests/compile_fail/instance_id_invalid_format.rs
  • gts-macros/tests/compile_fail/instance_id_wildcard_in_instance.rs
  • gts-macros/tests/inheritance_tests.rs
  • gts-macros/tests/integration_tests.rs
  • gts-macros/tests/value_dispatch_tests.rs
  • gts-validator/src/format/markdown.rs
  • gts-validator/src/normalize.rs
  • gts-validator/src/validator.rs
  • gts/src/entities.rs
  • gts/src/gts.rs
  • gts/src/lib.rs
  • gts/src/ops.rs
  • gts/src/schema_cast.rs
  • gts/src/store.rs
  • gts/src/store_test.rs
✅ Files skipped from review due to trivial changes (6)
  • gts-macros/tests/compile_fail/instance_id_invalid_format.rs
  • gts-validator/src/format/markdown.rs
  • gts-macros/tests/compile_fail/instance_id_wildcard_in_instance.rs
  • gts-validator/src/normalize.rs
  • gts-macros/tests/value_dispatch_tests.rs
  • README.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • gts/src/schema_cast.rs
  • gts/src/store_test.rs
  • gts-macros/tests/inheritance_tests.rs
  • gts-id/src/gts_id_segment.rs
  • gts-macros/tests/integration_tests.rs
  • gts/src/store.rs
  • gts/src/entities.rs
  • gts-id/src/parse.rs

@aviator5 aviator5 force-pushed the gts-id-extraction branch 6 times, most recently from 2c79348 to 2c0694d Compare June 15, 2026 15:54
aviator5 added 6 commits June 15, 2026 19:45
Split the monolithic gts-id crate into focused modules (parse, gts_id,
gts_id_segment, gts_wildcard, error). GtsID / GtsWildcard fields are now
private behind accessors (id(), segments(), into_segments()), and the
error type is the GtsIdError struct.

Move deterministic UUID v5 derivation into gts-id as a GtsID::to_uuid
inherent method, gated behind the crate's optional `uuid` feature (off by
default). The gts crate enables the feature; gts-macros depends on gts-id
without it, so uuid stays out of the proc-macro build graph and out of
gts-id's default public API. This replaces the former GtsIdUuidExt
extension trait that previously lived in the gts crate.

Adapt the dependent crates to the tightened API: field access -> accessor
methods, gts_id_segments -> segments(), GtsError -> GtsIdError. gts.rs is
slimmed to re-export the id primitives from gts-id and keep the
schema-aware GtsTypeId / GtsInstanceId wrappers.

Signed-off-by: Aviator 5 <ai.agent.tor@gmail.com>
Add validating constructors that enforce the type/instance discrimination
via the type system instead of downstream `ends_with('~')` checks:

- `GtsTypeId::try_new` accepts only trailing-`~` type ids.
- `GtsInstanceId::try_new` accepts only chained, non-`~` instance ids.

Both parse and structurally validate via `GtsID::new`, then classify by
kind, returning `GtsIdError` on a malformed string or a kind mismatch.

Signed-off-by: Aviator 5 <ai.agent.tor@gmail.com>
- GtsIdSegment is now an enum (Concrete / UuidTail variants) instead of a plain struct
- Rename GtsID → GtsId, GtsWildcard → GtsIdPattern, GtsSegmentError → GtsIdSegmentError
- Rename new() → try_new() to follow Rust convention for fallible constructors
- Privatise segment fields; expose them via accessor methods
- Add gts-id/README.md with full API usage examples

Signed-off-by: Aviator 5 <ai.agent.tor@gmail.com>
…tern

- Implements From<&GtsId> and From<GtsId> for GtsIdPattern, reusing validated segments without re-parsing
- Adds ergonomic GtsId::to_pattern() borrowing form as an alias for From<&GtsId>
- Adds tests covering roundtrip fidelity, chained instance ids, derived-type coverage (spec §3.6), and From ref/owned agreement

Signed-off-by: Aviator 5 <ai.agent.tor@gmail.com>
- Accept the glued `v*` version wildcard (spec §10 rule 4): a `v*` token at
  the version position parses as a wildcard meaning "any version". Simplify the
  structural wildcard gate to require `*` as the terminal character, which
  admits `v*` for free while still rejecting `*~`, mid-chain wildcards, and
  partial-token wildcards like `msg*`.
- Reimplement `GtsIdPattern::covers` over segments instead of string prefixes so
  minor-version flexibility is honoured: `…v1~*` now covers `…v1.0~*` and
  `…v1~` covers `…v1.0~` (the string-prefix test missed these). Drop the
  now-unused `prefix_str` helper.
- Correct stale docs: a concrete pattern is not exact-match — it covers derived
  chains per spec §3.6 implicit derived-type coverage.
- Add unit tests for v* parsing/matching/rejections and minor-version covers.

Signed-off-by: Aviator 5 <ai.agent.tor@gmail.com>
Signed-off-by: Aviator 5 <ai.agent.tor@gmail.com>
@aviator5 aviator5 force-pushed the gts-id-extraction branch from 7f73558 to cc0fb6c Compare June 15, 2026 16:47
@aviator5

Copy link
Copy Markdown
Contributor Author

Versioning/rebase note: this branch is behind origin/main (main has the v0.10.1 bump), while the PR branch still declares 0.10.0. The PR also removes/renames public APIs across gts/gts-id (GtsError, GtsID, GtsWildcard, field-access GtsIdSegment, validate_gts_id/validate_segment/ParsedSegment, and GtsEntityId is no longer public). Before publishing, could we rebase onto main and bump the affected crates to the next breaking version, e.g. 0.11.0?

yes, rebased and bumped in the last commit

@aviator5

Copy link
Copy Markdown
Contributor Author

One remaining issue I noticed in gts/src/entities.rs around the parent-chain reconstruction (let parent_id = format!("gts.{}", parent_segments.join("~"));): GtsIdSegment::raw() already includes the trailing ~ for type segments, so joining those raw segments with another "~" introduces double tildes for parent chains with more than one parent segment, e.g. gts.seg1~~seg2~. GtsId::get_type_id() already computes this parent ID correctly by joining raw segments with ""; could we use that here instead of hand-rolling the reconstruction?

good catch, fixed
p.s.: it's not a bug in the new code, it's relevant for the "main" branch too

@aviator5 aviator5 requested a review from Artifizer June 15, 2026 19:53
aviator5 added 2 commits June 15, 2026 23:39
…tests

- Add public getter methods to GtsIdSegmentParts for all fields (vendor, package, namespace, type_name, ver_major, ver_minor, is_type, raw)
- Add comprehensive tests for segment parts accessors covering all field combinations
- Improve UUID tail and pattern matching test cases with explicit assertions

Signed-off-by: Aviator 5 <ai.agent.tor@gmail.com>
Signed-off-by: Aviator 5 <ai.agent.tor@gmail.com>
@aviator5 aviator5 force-pushed the gts-id-extraction branch from 1613359 to e403309 Compare June 15, 2026 20:39
@Artifizer Artifizer merged commit fbb8b1c into GlobalTypeSystem:main Jun 16, 2026
7 checks passed
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.

3 participants