Skip to content

ARC0028: Move inline generation to a generated parameter

Inside a model-bound command’s instance Handle(), Arc recognizes a concept’s X.New() or a GenerateValue.*(...) / Guid.NewGuid() result directly converted or wrapped into a self-generatable concept. Default severity: Info. Raw primitives, helpers outside Handle, and generation inside nested functions are not reported.

The examples use this identifier, the same declaration as in generated values:

using System;
using Cratis.Arc.Commands.ModelBound;
using Cratis.Concepts;
public record CartId(Guid Value) : ConceptAs<Guid>(Value), IGeneratable<CartId>
{
public static CartId New() => new(GenerateValue.Uuid());
}

Compile this command together with it:

[Command]
public record AllocateCartId
{
public CartId Handle() => CartId.New();
}

Move to a [GeneratedValue] parameter adds a concept-typed parameter and replaces the whole generation expression with its name:

[Command]
public record AllocateCartId
{
public CartId Handle([GeneratedValue] CartId cartId) => cartId;
}

The fix derives a name from the local variable, argument, or concept and avoids existing names. It keeps required parameters before optional or params parameters. Choose an explicit attribute name afterward if scenario pins should survive a C# parameter rename.

The fix is deliberately local; it does not update direct Handle callers or move generation inside loops, branches, nested functions, virtual/override methods, or interface implementations. Nonconstant strategy arguments also prevent the fix. These cases need a manual migration so you can preserve allocation timing and cardinality. No Fix All action is offered.

Review the concept’s factory before accepting: the parameter uses that factory, not arbitrary strategy arguments from the old expression. Follow migrating generated identifiers for scenario pins and context-dependent strategies.