Generated values and command responses
A create command can return its new identifier without accepting that identifier from the caller. Stage renders generated concepts as Arc Handle parameters and carries scalar or named responses back to the caller. ESM v15 adds strategy-specific factories and atomic freshness guards; v20 admits rules on generated concepts. The generated backend takes its exact Arc pin from Stage’s Directory.Packages.props.
This page is the terse reference. To follow one model from .play to rendered C# and its runtime behavior, read Generate identifiers and values from a model.
Model to C# mapping
Section titled “Model to C# mapping”This state-change slice generates an event-source identifier and returns it. It declares no strategy, so the model stays below ESM v15:
concept ProjectId : Uuidmodule Storefront feature Projects slice StateChange Register command RegisterProject projectId ProjectId generated identifier name String produces event ProjectRegistered name String = name returns projectId specification RegisteringWithAPin when RegisterProject for "11111111-1111-1111-1111-111111111111" name = "Apollo" then ProjectRegistered name = "Apollo" then returns "11111111-1111-1111-1111-111111111111"Stage renders the identifier concept and the command with its event. These are excerpts with doc comments omitted. Types use their short names; a namespace the project’s global usings already import needs no using directive.
namespace Acme.Shop.Common;
public record ProjectId(Guid Value) : EventSourceId<Guid>(Value), IGeneratable<ProjectId>{ public static readonly ProjectId NotSet = new(Guid.Empty);
public static ProjectId New() => new(GenerateValue.Uuid());
public static implicit operator ProjectId(Guid value) => new(value);}using Acme.Shop.Common;
namespace Acme.Shop.Storefront.Projects.Register;
[Command][AllowAnonymous]public record RegisterProject(string Name){ public (ProjectId, EventForEventSourceId) Handle([GeneratedValue("projectId", Freshness = GeneratedValueFreshness.Unguarded)] ProjectId projectId) { return (projectId, new EventForEventSourceId(projectId, new ProjectRegistered(Name))); }}The generated property is absent from the command constructor and request inputs. Its modeled name becomes the case-sensitive generated-value name. Mappings read the Handle parameter. An event targeting that identifier uses an explicit EventForEventSourceId; GetEventSourceId() never references a removed request property.
A generated concept that is not an identifier derives from ConceptAs<T>. It implements IGeneratable<T> with New() for non-time-ordered strategies, or IGeneratableInContext<T> with New(GenerationContext context) for time-ordered strategies. The example above uses implicit UUID generation and stays below ESM v15; its handler remains unguarded and returns one EventForEventSourceId.
Version admission
Section titled “Version admission”Stage admits exact ESM v1.0–v34.0 and v36.0 language/semantic pairs, not v35 or arbitrary minor versions. Version admission does not imply support for every strategy:
| Version | Generation support |
|---|---|
| v15 | UUID, UUID-v7, ULID, TypeID, NanoID and bytes factories |
| v20 | Rules on generated concepts; unpinned rendered specifications require every rule to be proven |
| v21 | Pattern and inclusive Int64 random generation; checksum validation; verified C# generate rule bodies render through IGeneratableInContext<T>; executor runs pinned String rule values without invoking the body; Host refuses commands generating rule values |
The Host samples pattern and random values through the Fundamentals release pinned in Stage’s Directory.Packages.props. The independent specification executor requires deterministic fixtures, just like Screenplay 4.182.0. Both paths enforce the reference strategy shapes and checksum rules. For generate rule, the executor accepts any String fixture that satisfies the concept’s rules and never invokes the implementation body; missing pins remain Unsupported(IdentityAllocation). An unused rule-generation concept does not block the Host or executor. The Host refuses each command that generates a rule value with STAGE-ESM-028, naming the command, property, concept and rule (or the requirement id when the requirements are unavailable). This is by design: a generate rule always has an implementation body that Stage’s interpreter never runs or replaces, so render the application to run it. The supported generation subset is the built-in strategies (uuid, uuidv7, ulid, typeid, nanoid, bytes, pattern (optionally with a checksum), and random): the Host generates them and checks them against the concept’s rules, while the executor checks pinned fixtures for them. The renderer compile-checks and emits verified C# rule bodies; the legacy syntax engine still refuses generate rule with STAGE-ESM-028. The legacy syntax renderer still refuses checksum and unknown validation rule kinds with STAGE-ESM-042 rather than omitting the check. No artifacts are published for a refused semantic render plan.
Rule generation
Section titled “Rule generation”A String concept’s generate rule body renders as a private static String method, called by New(GenerationContext context) through IGeneratableInContext<T>. Arc supplies the command receipt time as context.Now and the operation’s tenant as context.Tenant. Bodies may use BCL APIs such as Guid.NewGuid() and Fundamentals APIs such as GenerateValue.Ulid(context); the latter binds to the Cratis C# target’s context type.
Pass the implementation requirements, resolved contents and typed-context descriptors from the same Screenplay compilation to the renderer; ESM bytes alone do not carry the factory body. Stage verifies the attachment’s content hash and typed-context envelope, parses one complete C# statement block, and compile-checks it against embedded BCL and Fundamentals metadata references. The pinned Fundamentals DLL is a build-only input embedded in the renderer, not a runtime or package dependency. It does not run the body while rendering or apply the reducer/policy purity gate. Compilation errors and warnings report STAGE-ESM-019 at the body location, because the generated application treats warnings as errors; namespace or type shadowing reports STAGE-ESM-022. Missing or unresolved attachments fail STAGE-ESM-020; rendering does not replace them with stubs.
Any concept rule makes rule generation Unproven, so rendered specifications need a pin (STAGE-ESM-038). A rule-generated concept with no validation rules can generate unpinned through the context factory. Verified pure C# Boolean concept rule bodies render as app-local typed-context validators, including checks on pinned generated values. Verified pure C# concept code-validation iterators also render, adding one error per yielded message. Iterator interpolations use invariant formatting, not the host culture; reads of validator context Tenant, CausedBy or Occurred fail with STAGE-ESM-015. The reference and executor still require pins, and the Host interpreter still refuses commands that generate rule values.
Checksum rules
Section titled “Checksum rules”Declare validate checksum luhn, validate checksum mod11 or validate checksum mod97 on a String concept. The rendered validator calls GenerateValue.HasValidChecksum(value, Checksum.Luhn) (or Mod11 / Mod97), retaining the authored message and severity.
The final one digit (Luhn/Mod11) or two digits (Mod97) must exactly match the checksum of the preceding ASCII digits. Printable non-digits in the payload, including lowercase letters and spaces, are ignored; they are not converted to numbers. Control characters and non-ASCII characters anywhere in the value fail validation. Empty values and non-digit suffixes fail too. Mod11 payloads whose check digit would be 10 have no valid one-digit suffix. For example, 79927398713 passes Luhn, abc98 passes Mod97, and 79927398714 fails Luhn. A checksum is not a length or format constraint; declare those separately.
The specification executor and generated-fixture admission check concept rules through Screenplay’s public SemanticValidationRules.Check API. Generated C# continues to use Fundamentals for runtime checks.
When a concept declares checksum validation, pinned generated fixtures must satisfy it as well as the generation shape. A bad pin blocks rendering with STAGE-ESM-011; it is not treated as invalid caller input.
Pattern and random strategies
Section titled “Pattern and random strategies”| Strategy | Backing type | Rendered factory |
|---|---|---|
pattern "REF-?{16}" | String | GenerateValue.Pattern("REF-?{16}") through IGeneratable<T>.New() |
pattern "{yyyy}-{MM}-{dd}-?{16}" | String | GenerateValue.Pattern(pattern, context) through IGeneratableInContext<T>.New(context) |
pattern "#{16}" checksum luhn | String | GenerateValue.Pattern(pattern, Checksum.Luhn); Mod11 and Mod97 use the corresponding enum values |
random a..b | Int | GenerateValue.Integer(a, b) through IGeneratable<T>.New(); both Int64 endpoints are inclusive |
Pattern factories sample distinct strings uniformly from the finite language. Dated patterns expand every date segment from the operation’s captured UTC date, not the render-time clock. The date-free factory does not require a context. Random values remain numeric throughout Host execution and generated specifications. ESM v21 whole-number concepts render as long, so the compiler’s entire Int64 random range is representable without an Int32 range refusal.
A pattern fixture checks language membership, including trailing digit width for a generation checksum. It does not check checksum arithmetic unless you also declare validate checksum. Without an authored clock, date positions in a pin need only have the correct digit widths; with a clock, all repeated date segments must match that exact UTC date. A random fixture must be an integral number inside the inclusive range. Neither strategy guarantees uniqueness: generated destinations retain the existing freshness guard, and constrained payloads retain append-time collision handling.
ESM v15 strategies
Section titled “ESM v15 strategies”Declare a strategy on the concept, for example generate uuidv7 under a Uuid concept or generate bytes 16 hex case upper under a String concept. The command property still says generated. To pick one, see Choosing a strategy.
| Strategy | Backing type | Factory and default shape |
|---|---|---|
uuid | Uuid or String | GenerateValue.Uuid(); version 4, RFC variant, lowercase hyphenated text |
uuidv7 | Uuid or String | GenerateValue.UuidV7(context); version 7, RFC variant |
ulid | String | GenerateValue.Ulid(context); 26 uppercase Crockford symbols |
typeid "user" | String | GenerateValue.TypeId("user", context); lowercase prefix, underscore and a UUID-v7 Crockford suffix; an empty prefix omits the underscore |
nanoid | String | GenerateValue.NanoId(size, alphabet); default size 21 and URL-safe alphabet; custom size 1–256 |
bytes n base64url | String | GenerateValue.Bytes(n, ValueEncoding.Base64Url); URL-safe text without padding |
bytes n hex | String | GenerateValue.Bytes(n, ValueEncoding.Hex); lowercase hexadecimal |
bytes n base32 | String | GenerateValue.Bytes(n, ValueEncoding.Base32); uppercase base32 without padding |
String-backed strategies accept the modifiers admitted by Screenplay: prefix adds printable ASCII text before the generated portion, and case upper or case lower selects its casing without changing the prefix. Bytes accept counts 1–512; unused trailing encoding bits must be zero. Screenplay refuses unsupported strategies and identifiers below 64 random bits before rendering. It still refuses compliance markers (pii, secret) on a generated concept with PLAY0268, so a secret cannot be generated yet. Validation rules are admitted from ESM v20, subject to the limits below. See Keep the secret out of the identity.
Time-ordered concepts implement IGeneratableInContext<T> instead of IGeneratable<T>. Arc supplies a GenerationContext whose Now is the command’s ReceivedAt, and its tenant. Ulid, TypeId and UuidV7 read only Now. An event that maps $context.occurred takes the same receipt time, truncated to a millisecond, for its payload and its Occurred metadata, so the value’s time component and that mapping agree to the millisecond. An event that does not map it carries no occurrence time from Arc, and Chronicle stamps the append time. Hand-written calls to these concepts must now pass a context to New(context); the parameterless New() is no longer emitted. uuid, nanoid and bytes retain New().
Rules on generated concepts
Section titled “Rules on generated concepts”At ESM v20, Stage renders a generated concept’s factory together with its ConceptValidator<T>. Arc validates the factory output or pinned value before calling Handle. A failing rule is a server generation defect: the command result carries an exception, no input ValidationResults, and no appended events. The Host’s evaluator checks the generated output’s strategy shape and rules only after authorization and ordinary input checks. A generated-fixture contract rejection then becomes a server exception, including for reaction-invoked commands; denial and input validation keep their ordinary results.
The reference and independent specification executor report Rejected(Contract) with Generated fixture '<property>' fails concept '<Concept>' rules, not the rule’s authored validation message. They check each supplied fixture’s shape and then rules in fixture order, before reporting missing fixtures. This represents the same generation defect, not a caller-correctable validation failure.
Rendered specifications may leave a generated property unpinned when every concept rule is proven. Stage derives each rule’s proof status with Screenplay’s RuleConsistency.Check rather than reading it from ESM. Any unproven or refuted rule requires a pin (STAGE-ESM-038); this check applies to explicit strategies and implicit UUID generation. A pin failing its shape or rules fails STAGE-ESM-011; Stage does not render it as an input-validation assertion or an exception assertion. The command and concept can still render without that specification. Opaque or unsupported rules are refused before any pin is evaluated: STAGE-ESM-005 identifies the pinned specification, generated concept and rule rather than throwing during planning.
Warning- and information-severity rules on generated concepts render alongside error-severity rules. Arc rejects generated values failing a rule of any severity as server generation defects. Rule severity is separate from Screenplay’s proof diagnostics: PLAY0688 refuses a refuted rule and PLAY0689 warns that a rule is unproven.
Fresh event sources
Section titled “Fresh event sources”In an application with at least one explicit concept generation strategy, a command that produces facts on a generated destination returns EventsWithConcurrencyScopes, with one ConcurrencyScope(EventSequenceNumber.BeforeFirst, EventSourceId: id) per generated source. Chronicle checks every scope in a batch once, against the state before the batch, so several initial facts in the same invocation are allowed. One violated scope rejects the entire batch and appends nothing; Arc reports it as ValidationResultReason.ConcurrencyViolation. When a storage append loses a sequence-number race, Chronicle renumbers the batch and validates the scopes again before retrying. It does so from Chronicle 19.40.1 (verified in the 19.55.2 kernel). See Chronicle concurrency. Generated rejection specifications assert that reason rather than Arc’s message text.
The Host and specification executor use the reference freshness message: “A generated event source already has facts; retry the command with a fresh generated value.” Earlier facts without a destination never make the generated source stale. A generated value that is not the destination, such as an invite code appended to a customer stream, adds a scope only when its text equals the destination’s, so it makes no freshness claim about that stream. An application using only implicit UUID generation remains unguarded, including at v16–v21; the schema version alone does not activate freshness. Generated handle parameters declare Freshness = GeneratedValueFreshness.Unguarded so that Arc’s own guard, which is Guarded by default from Arc 22.100, does not apply on top of these scopes. The explicit scopes will move to Arc’s generated-identifier freshness contract (Arc #3129).
Unique generated payloads
Section titled “Unique generated payloads”The shop’s InviteCode can be a short NanoID without becoming the event-source identifier:
concept InviteCode : String generate nanoid 6 alphabet "AB"module Shop feature Invitations slice StateChange ReleaseInvite event InviteReleased command ReleaseInviteCode inviteId String identifier produces InviteReleased for inviteId slice StateChange Invite constraint UniqueInviteCode unique code on Invited released by InviteReleased message "Invite code is already in use" event Invited code InviteCode command InviteCustomer inviteId String identifier inviteCode InviteCode generated produces Invited for inviteId code = inviteCode specification Collision given Invited for "A" code = "AAAAAA" when InviteCustomer inviteId = "B" generated inviteCode = "AAAAAA" then error "Invite code is already in use"Chronicle checks uniqueness at append, not with a preflight query. If another event source holds the generated code, the command is rejected with ValidationResultReason.ConstraintViolation, the authored constraint name and its message; no event is appended. The caller retries the rejected command and gets a fresh generated value. Stage does not automatically retry, regenerate or rerun the handler, and a new draw is not guaranteed to succeed in a small or exhausted code space. Retry only a known rejection, not an unknown commit outcome.
This is current-claim uniqueness, not all-time uniqueness. The same source may reclaim its own code, replacing a claim frees the previous code, and InviteReleased frees the owner’s claim for reuse. ignore casing compares codes without case, so distinct generated spellings can still collide. High entropy lowers collision probability; it does not prove uniqueness. A returned candidate on a failed command is not a committed code.
Generated constraints retain the ordinary admission limits: one required scalar text property, event-sequence scope, and only one affected claim or release event per command batch. String-backed UUID, UUID-v7, ULID, TypeID, NanoID (sizes 1–256) and bytes (counts 1–512) can supply that property. UUID-backed payloads remain refused under STAGE-ESM-014. Short non-identifier codes are admitted; Screenplay’s 64-bit minimum for generated identifiers still applies. Only ordinary constrained request inputs receive the not-null validator; generated values remain Handle parameters.
Conditional productions and shared slices
Section titled “Conditional productions and shared slices”A StateChange slice can declare several commands. Each command keeps its own validator, response and specifications, while sharing the slice’s event contracts and source file.
Portable produces when conditions read command inputs and generated values. Stage evaluates each condition once and returns a typed collection of EventForEventSourceId values containing only the taken productions. When the application uses explicit concept generation, freshness scopes cover only sources targeted by those productions. If every production is skipped, the command is accepted, appends nothing and still returns its response, even if the generated source already has facts.
Conditions support text and Boolean equality, numeric equality and ordering, and and/or. Enum operands and expression-valued Condition nodes remain refused with STAGE-ESM-006; production route overrides on an unkeyed stream under a keyed command route, or with the literal stream id Default, are not admitted yet and are refused with STAGE-ESM-036. A specification that reads a generated property in a production condition must pin it, so the expected production sequence can be determined before rendering.
Commands without production conditions retain their existing generated Handle shape.
Responses
Section titled “Responses”| Screenplay contract | C# Handle response |
|---|---|
returns projectId | The property’s type, paired with the event result |
returns block | A <Command>Response record, paired with the event result |
| Response-only command | The scalar or response record directly, without an event tuple |
A response block names each field independently of its source property. Each field keeps the source type, including optionality. Generated parameters and ordinary command properties can supply response values, including composite type values; a composite response renders as the app-local record and serializes as the same JSON object. Collection responses are refused with STAGE-ESM-038. Arc uses the tuple’s response element as CommandResult<T>.Response; it does not expose the event wrapper as the response.
The generated TypeScript proxy carries the response type too. A UUID-backed scalar response uses Command<IRegisterProject, Guid>; a named response uses Command<IRegisterReceipt, RegisterReceiptResponse>. The event wrapper is not the client response type.
When <Command>Response would collide with another generated type in the application, such as a command named IssueInvoiceResponse beside IssueInvoice, or with one of the record’s own fields, Stage renders the record as <Command>Response_ and reports STAGE-ESM-050. Field names are never renamed, so the response JSON stays the same. Response fields that collide with each other or with a record member such as EqualityContract are refused with STAGE-ESM-038.
A generated concept named New keeps its name: its factory implements IGeneratable<New>.New explicitly instead of declaring a public New member, which C# forbids on a type of the same name.
Fixtures and testing
Section titled “Fixtures and testing”A specification’s when ... for <uuid> pins a generated identifier. generated receipt = "<uuid>" pins a generated non-identifier property. Stage emits PinGeneratedValue before executing the scenario, using the concept type rather than a raw Guid.
For the model above, the generated specification when_registering_with_a_pin.cs declares the pinned value and pins it before executing the command:
static readonly ProjectId _projectId = new ProjectId(Guid.Parse("11111111-1111-1111-1111-111111111111"));
void Establish(){ _scenario.PinGeneratedValue("projectId", _projectId);}Pinned event and then returns assertions compare the authored values. A named return expectation can assert a subset of the response fields.
When a rendered specification omits a fixture, Stage calls _scenario.AllowGeneration(). Ordered event destinations and payload mappings that depend on that unpinned property compare against _scenario.GeneratedValues.Last<T>(name), and response assertions compare against the same capture. Below v15, the UUID must be nonempty. At v15, every unpinned capture must also match its strategy’s derived encoding shape. These are relational assertions, not assertions that random generation equals an authored UUID literal. Unordered or projected expectations require pins. A generated value involved in an asserted constraint collision also requires a deterministic pin. Stage requires a pin when prior claims on other sources could make an unpinned draw change success into rejection; unrelated unpinned relational specifications still render.
For an unpinned time-ordered value, Stage emits _scenario.Clock(new DateTimeOffset(2026, 1, 2, 3, 4, 5, 678, TimeSpan.Zero)) as the first setup statement, before policy registration and givens. A should_generate_<name>_at_the_receipt_time fact checks the capture’s encoded millisecond prefix as well as its shape. The random portion remains unpinned. If a command specification states given clock, Stage uses that authored instant instead, normalized to UTC, for both the scenario clock and the receipt-time prefix assertion. Authored clocks also produce clock setup for fully pinned commands and commands without time-ordered generation. Without an authored clock, those specifications get no clock setup. Clocks must be millisecond-aligned and at or after the Unix epoch; when clock, query-only, append and reaction clocks remain refused.
Dated pattern captures use the same deterministic scenario clock as time-ordered values and assert the expanded UTC date in their shape. Random captures assert the inclusive range. Date-pattern rule proofs use the authored UTC year, or the fixed scenario year 2026 when no clock is authored, keeping rendered bytes deterministic.
The in-memory specification executor requires deterministic fixtures, just like the Screenplay evaluator. Missing fixtures produce an Unsupported(IdentityAllocation) outcome; they do not silently allocate a value and pass. It compares scalar responses and each asserted named field after successful execution.
Rendering is not compilation or execution. Build the generated project in Debug, then run its Debug specifications. A successful run proves that Arc resolves the parameters, the events land on the intended streams, and the response assertions execute.
Partial-perform runtime
Section titled “Partial-perform runtime”The live semantic runtime supplies a value from the concept’s strategy for every generated property, including validation-only requests: a semantic number for random, and semantic text for the other strategies. Applications without explicit concept generation retain implicit UUID generation, regardless of their schema version. It rejects attempts to supply generated properties as request inputs. Validation-only requests do not append facts or reserve the generated UUID for a later execution.
For time-ordered strategies, the Host uses the same occurrence instant for generation and event metadata. It takes that instant from CommandContext.ReceivedAt, retaining a UTC wall-clock fallback only for hand-built contexts without a receipt. Reaction-invoked Host commands use the triggering command’s occurrence; rendered reactions dispatch through Arc and use their own pipeline receipt.
An accepted scalar response becomes the HTTP command result’s response value. A named response becomes an object with camelCase field names. Rejected or unauthorized results carry no response. The Stage frontend passes the accepted response through Scene’s CommandOutcome.response.
A form’s successful on submit continuation can use the command’s scalar return name or a named response field as a value in navigation arguments, subsequent command arguments or messages. Generated applications and the live Host carry the response and destination types to Scene; incompatible or unknown contracts prevent submission rather than falling back to request fields or selected rows. Named fields use the backend’s camelCase wire names. Form fields and behavior parameters shadow matching response names.
This first continuation slice supports primitive and concept values, including optional values and collections, and named records of those values. Non-command success branches retain the response. A nested command success uses that command’s response; captures of an outer response across nested command success, failure or result branches are refused during translation. Guarded submit triggers are also refused because the pinned Scene form continuation cannot represent their guard. Composite response contracts and response-to-state assignments remain unsupported. These limits do not restrict generated TypeScript proxies, which expose the command’s declared response independently of form continuations.
Limits and diagnostics
Section titled “Limits and diagnostics”Generated property names may match renderer locals such as operation, occurred, stageEvents, stageProduces0, streamIdPart0 or source. The Cratis renderer renames its locals with the first free numeric suffix; generated-value parameter names and their bindings stay unchanged. These names do not restrict Host or specification-executor admission.
Commands with generated properties can route events to the generated identifier within a named stream. Stream ids must come from request values or literals, never generated properties: Screenplay resolves the route before generation. When concept generation is enabled, generated destination freshness spans all streams of that event source, even when a source definition declares narrower concurrency dimensions. Bare generate uuid is normalized to legacy implicit UUID generation and does not enable this guard on its own; use an explicit strategy such as generate uuidv7 when requiring freshness.
Routed commands can return a scalar or named response, including the generated identifier and request values. Conditional productions return the response even when no event is selected. Generated TypeScript proxies expose the response type, not the routing or event wrappers.
Route-format failures append no events, but do not promise effect-free generation. In a rendered app, route checks stay in Handle and return a ValidationResult after Arc resolves generated parameters; the reference evaluator rejects the route as Contract before generation. Deterministic pins that fail generation shape or concept rules are already refused at render time with STAGE-ESM-011.
Commands with generated properties can validate and require request values. Requirements run before generation: an unmet requirement rejects the request without drawing a generated value or appending events. Rules on generated concepts are checked during generation; pin those values in specifications when their rules are unproven. Command rules and requirements cannot read a generated property because it does not exist during request validation; Screenplay rejects those reads, and Stage refuses hand-built models containing them with STAGE-ESM-038.
| Diagnostic | Refused shape |
|---|---|
PLAY0268 (Screenplay) | Compliance markers on a generated concept |
STAGE-ESM-028 | Host (by design): each command generating a rule value, not unused rule concepts; the rule body is never run by the interpreter. The semantic renderer emits verified C# rule bodies; the executor admits pinned String rule values. Unknown generation strategies, non-concept generated values, optional values and collections remain refused, and the diagnostic names the offending shape (optional, collection, primitive or composite type) and the Screenplay contract that a generated property must be a required, non-collection generatable concept (PLAY0483); the legacy syntax engine refuses every explicit strategy, including rule, and generated properties whose concepts have rules |
STAGE-ESM-042 | Unsupported validation rule kinds in the legacy syntax renderer, including checksum; semantic checksum rules are supported |
STAGE-ESM-011 | A generated fixture that fails its required strategy shape or concept rules |
STAGE-ESM-004 | StateChange slices without a command |
STAGE-ESM-006 | Unsupported production destinations, mappings, tags, types, or conditions, including enum operands and nonnumeric ordering. Described handlers own payload and destination and retain STAGE-IMPL-002 instead of this code for those two checks |
STAGE-ESM-053 | A declarative command production with neither its own nor the command’s destination. Stage does not yet render event-source identity allocation for it (Stage#629); the message names the command and event |
STAGE-ESM-038 | Command rules or requirements that read a generated property; collection responses, responses from a source that is not a command property of the same type, or response fields whose C# members collide; the message names the reason |
STAGE-ESM-038 | Unpinned generation on a concept with any unproven rule, read by a production condition, or with unordered event, read-model or query expectations, or a generated constrained value whose unpinned draw could change the asserted collision outcome |
STAGE-ESM-038 | A generated identifier combined with a destination-less plain production |
The last case retains STAGE-ESM-038, before destination admission, and is not shorthand for using the generated identifier. Screenplay keeps legacy allocation in a separate AllocatedIdentities channel. Use an inline produces event declaration as above, or an explicit production destination. Stage refuses the ambiguous combination instead of sending the event to a different stream than the evaluator.
Time-ordered factories (uuidv7, ulid, typeid) follow Arc’s ReceivedAt, with no wall-clock fallback in the rendered app. Missing receipt times fail generation. Pins bypass the factory and need not encode the receipt time. Values reveal the receipt time and are not monotonic within a millisecond. Screenplay given clock is supported on otherwise admitted command specifications from ESM v6. Fixed $context.occurred payload assertions use that instant; a wrong expected instant fails rather than changing the clock. The executor also uses the authored instant for stored occurrence metadata, while retaining deterministic generated fixtures. Authored clocks with reactions, when clock and sequence remain unsupported. The executor can run pinned rule values without executing bodies. The Host interpreter refuses commands generating them; rendered applications execute the verified bodies through the context factory.
Pitfalls
Section titled “Pitfalls”- Do not put a generated identifier back into the request to make a spec deterministic. Pin it in the scenario instead.
- Do not edit generated commands or concepts to select a strategy. Declare it on the concept in the model.
- Adding an explicit strategy anywhere in the application, or rules on the generated UUID concept itself, requires its fixture to be a lowercase version-4 UUID with the RFC variant. A pin such as
11111111-1111-1111-1111-111111111111no longer matches; uppercase Uuid text is noncanonical even before the strategy check. - A pin has the exact concept type and modeled name. A raw UUID or differently cased name is not the same fixture.
- A returned UUID is not proof that a projection is ready, an external effect succeeded, or an identifier is absent from storage.
For the complete target admission table, see Build a renderer target.