Skip to content

feat(strings): add Semantics.Strings.Identifiers package (Phase 0)#108

Merged
matt-edmondson merged 16 commits into
mainfrom
feat/semantics-strings-identifiers
Jul 1, 2026
Merged

feat(strings): add Semantics.Strings.Identifiers package (Phase 0)#108
matt-edmondson merged 16 commits into
mainfrom
feat/semantics-strings-identifiers

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Summary

Adds a new ktsu.Semantics.Strings.Identifiers package — the first batteries-included concrete semantic-string types on top of the Semantics.Strings framework, which until now shipped only the validation framework with zero concrete types. This is Phase 0 of the semantic-domains roadmap (docs/roadmap-semantic-domains.md), scoped to the identifier subset.

Six validated identifier types, each a sealed record : SemanticString<T> with one package-local validation attribute:

Type Validation Normalisation
Uuid RFC 4122 canonical 8-4-4-4-12 hex lowercased, braces stripped
Ulid 26-char Crockford base32, timestamp-bounded first char uppercased
Iban structure + ISO 7064 mod-97-10 checksum whitespace stripped, uppercased
Isbn ISBN-10 (mod-11, X) or ISBN-13 (mod-10) check digit hyphens/spaces stripped, uppercased
CreditCardNumber 13–19 digits + Luhn spaces/hyphens stripped
JwtToken 3 base64url segments; header+payload decode to JSON objects none (opaque)

Design decisions

  • Framework stays generic. The six new check-digit/format validators live in the Identifiers package (subclassing the framework's public NativeSemanticStringValidationAttribute / ValidationAdapter); nothing domain-specific leaks into Semantics.Strings.
  • Empty is never valid. Unlike some framework attributes (e.g. IsEmailAddress) which pass on empty to compose with a length rule, identifier attributes reject ""Uuid.Create("") throws ArgumentException.
  • Pragmatic validation with documented limits (matches the IsEmailAddress precedent): real check-digit maths where a checksum exists; documented non-goals (e.g. JWT signature is not verified; IBAN per-country BBAN tables not enforced; no BIN/PCI for card numbers).
  • v1 is validation + type-safety only — no parsed accessors (ToGuid(), JWT claim decode); those are a clean follow-up (YAGNI).
  • Out of scope (deferred): encodings/notations (Base64, HexString, SemVer, HexColor) → future Semantics.Strings.Formats; web types (Email, Url, …) → future Semantics.Strings.Web.

Testing

  • 40 new MSTest tests across the six types (valid canonical, canonicalisation, bad-checksum, structural-invalid, empty-throws, plus an As<T> round-trip). Full suite: 944/944 passing, solution build clean (0 warnings across all five TFMs net10.0net8.0 + netstandard2.0/2.1).
  • Every checksum (Luhn, ISBN-10/13, IBAN mod-97) and the JWT base64url/JSON-object logic was independently hand-verified during review; the netstandard2.0 API surface was checked (JsonDocument.Parse(byte[]), Convert.FromBase64String, Regex timeouts all available).

Docs

  • Spec: docs/superpowers/specs/2026-07-01-concrete-semantic-strings-design.md
  • Plan: docs/superpowers/plans/2026-07-01-semantics-strings-identifiers.md
  • README "Batteries-included identifiers" subsection + CLAUDE.md project-layout row.

Note on versioning

New additive package — the merge commit should carry a [minor] tag per the ktsu versioning convention.

🤖 Generated with Claude Code

@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 85920aa into main Jul 1, 2026
6 checks passed
@matt-edmondson
matt-edmondson deleted the feat/semantics-strings-identifiers branch July 1, 2026 04:09
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