Skip to content

Check values against validation rules

Use SemanticValidationRules.Check from the Cratis.Screenplay .NET library when you already have semantic model objects and need the same value-rule meaning as the reference evaluator. You do not need a command, query or execution plan. This API checks rules only: it does not validate an application’s structure, authorize a caller, allocate generated values or execute opaque code.

To check the declaration itself—its generation options, generation-rule proofs and required ESM version—use Check a concept declaration. For chronological comparisons on command Date and DateTime properties, use Check command date comparisons.

All types below are in Cratis.Screenplay.Semantics; collections use System.Collections.Immutable.

CallResult
Check(SemanticValidationRule rule, SemanticValue value)One SemanticRuleCheck.
Check(SemanticConcept concept, SemanticValue value)An ImmutableArray<SemanticRuleCheck> in rule declaration order, with the concept identity on each result.
Check(SemanticApplication application, SemanticTypeReference type, SemanticValue value)An ImmutableArray<SemanticRuleCheck> walking concept values through collections and composites.

Pass contract-validated rules, types and values, such as those from a bound or deserialized executable semantic model. The application overload resolves concept and composite identities from that application. It traverses array elements and supplied composite properties in value order, then each concept’s rules in declaration order. A primitive contributes no rules. An empty or absent collection, or an absent composite, contributes no values to check. An absent scalar concept still checks its rules.

This standalone example checks an invoice-number prefix:

using Cratis.Screenplay.Semantics;
var rule = new SemanticValidationRule(
default,
SemanticValidationRuleKind.StartsWith,
SemanticValue.Text("INV-"),
"An invoice number must start with INV-.");
var check = SemanticValidationRules.Check(rule, SemanticValue.Text("PO-42"));
Console.WriteLine(check.Status);
Console.WriteLine(check.Message);

Output:

Failed
An invoice number must start with INV-.

SemanticRuleCheck carries these members:

MemberMeaning
StatusNotEvaluable = 0 (also the default), Satisfied or Failed. Never treat NotEvaluable as a pass.
RuleThe original rule, including operand, severity, authored message and requirement identity.
MessageA non-nullable string: the authored message or the default rejection text, including on satisfied results. For NotEvaluable, the reason the rule cannot run.
ConceptThe concept identity for a concept check or application walk; otherwise null.
PatternThe PortableMatchCheck for a Matches rule with a text operand; otherwise null.

Messages beginning with $strings. remain unresolved string keys. Resolve them in the consuming application’s locale. Without an authored message, NotEmpty uses A required value is empty. for a single-rule check and A required concept value is empty. for a concept check or application walk. Other defaults describe the bound, comparison, pattern or checksum.

Rule severity is presentation data, not permission to ignore a failure. The reference evaluator rejects failed rules at every severity.

Use SemanticValue.Null for absence. Every evaluable rule except NotEmpty is satisfied by absence; presence needs its own rule. Unsupported rules and patterns remain NotEvaluable even for an absent value.

SemanticValidationRuleKindMeaning for a present value
NotEmptyRejects empty or Unicode-whitespace-only text and empty arrays. Numbers, booleans and composites are present.
Maximum, MinimumInclusive numeric bounds, or bounds on text length.
Equal, NotEqualSemantic equality or inequality; text comparison is ordinal and case-sensitive.
GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqualNumeric comparison against the operand.
LengthText length equals the numeric operand.
DecimalPlacesA decimal number has at most the operand’s number of decimal places; trailing zeros do not count. The operand is a whole number from 0 to 28.
AllGreaterThan, AllGreaterThanOrEqualEvery collection element satisfies the numeric comparison. An empty collection passes. These rules belong on collection properties, not scalar concepts.
MatchesSearches using the portable match dialect; ^ and $ anchor to the whole input.
ChecksumText ends in the exact check digits for luhn, mod11 or mod97; see patterns and checksums.
Contains, NotContains, StartsWith, EndsWithOrdinal, case-sensitive literal text comparisons.
RulePredicate, CodeValidation, UnknownNotEvaluable; the reference implementation cannot execute these rules.

Text comparisons use UTF-16 code units, without culture-dependent casing or Unicode normalization. Length counts code units too: a supplementary character represented by a surrogate pair has length two. Numeric values and operands use exact .NET decimal, not binary floating point. Empty text operands are valid: Contains, StartsWith and EndsWith pass for present text, while NotContains fails.

A value or operand incompatible with a rule’s required kind throws InvalidSemanticContract, rather than returning Failed. For example, Length requires text and a numeric operand. Ordering requires numbers, not text lengths; quantified comparisons require every element to be numeric, even after an earlier comparison fails. Equality requires matching scalar text, number or boolean kinds, or a null operand. Operand kinds are checked even for absent values and empty collections. This is not a general type-validation API; validate the input contract before checking rules.

Matches calls the public pattern admission check before matching. Admitted patterns run on Screenplay’s deterministic linear matcher, with no platform regex or timeout. Invalid patterns and constructs outside the dialect return NotEvaluable; Pattern carries the diagnostic code, construct, offset and suggestion, and Message carries the admission explanation.

Recognized deprecated Studio lookaround shapes are evaluated as their first-class replacement, including in older ESM documents. Rule still contains the original Matches rule, while Pattern.Status is Deprecated and Pattern.Replacement describes the literal comparison. The default message describes that replacement, not a regex failure.

The API does not change ESM bytes or select a new ESM version. It is a .NET value-checking surface; the TypeScript compiler exposes pattern admission, not this semantic value evaluator. For execution ordering and where concept rules are enforced, see concept validation.