Skip to content

Code Analysis Rules

This section documents the code analysis rules provided by the Chronicle Code Analyzer for the .NET client.

All rules follow the identifier format CHR####. Numbers are assigned sequentially; an occasional id is reserved for a rule still in progress, so a gap in the published set is expected.

Rule IDTitleSeverityDescription
CHR0001Event type must have [EventType] attributeErrorTypes appended to event sequences must be marked with [EventType] attribute
CHR0002Declarative projection event type must have [EventType] attributeErrorDeclarative projection generic arguments must reference types with [EventType] attribute
CHR0003Model bound projection attribute must reference event type with [EventType] attributeErrorModel bound projection attributes must reference types with [EventType] attribute
CHR0004Reactor method has a parameter that cannot be resolvedWarningReactor method dependencies must be resolvable from event context, read models, or services
CHR0005Reactor event parameter must have [EventType] attributeErrorEvent parameters in reactor methods must be marked with [EventType] attribute
CHR0006Reducer method signature must match allowed signaturesWarningReducer methods must follow allowed signatures
CHR0007Reducer event parameter must have [EventType] attributeErrorEvent parameters in reducer methods must be marked with [EventType] attribute
CHR0012Event types should avoid nullable propertiesWarningNullable properties are supported on events but are often better modeled as separate event types
CHR0013Reactor cannot combine EventStore with explicit event sequenceErrorReactors with [EventStore] must not also configure an explicit event sequence
CHR0014Reducer cannot combine EventStore with explicit event sequenceErrorReducers with [EventStore] must not also configure an explicit event sequence
CHR0015Projection must not have side effectsErrorProjections must not inject ICommandPipeline or IEventLog
CHR0016Projection Define() must not contain imperative codeErrorProjection Define() must only contain builder calls, not imperative statements
CHR0017Constraint must not have side effectsErrorConstraints must not inject ICommandPipeline or IEventLog
CHR0018Constraint Define() must not contain imperative codeErrorConstraint Define() must only contain builder calls, not imperative statements
CHR0019Projection expression lambda must only access membersErrorExpression lambdas in projection builder methods must be simple member-access expressions
CHR0020Constraint expression lambda must only access membersErrorExpression lambdas in constraint builder methods must be simple member-access expressions
CHR0021Event types should be record typesWarningEvent types should be declared as record types for immutability
CHR0022Reactor methods returning event side effects must be marked with [OnceOnly]WarningReactor methods that return events must be [OnceOnly] to avoid appending duplicates during replay
CHR0023Ambiguous parent key for [ChildrenFrom] collectionWarningParent-key inference is ambiguous when the child event has more than one property of the parent identifier type; specify parentKey
CHR0024Read model property has no mapping sourceWarningA model-bound read model property has no mapping attribute and no subscribed event carries a same-named property, so AutoMap can never populate it
CHR0025Explicitly sourced read model property may be overwritten by AutoMapInfoA property set with [SetFrom]/[SetValue]/… collides by name with another referenced event that AutoMap writes on top; add [NoAutoMap] or accept the update
CHR0026[Key] or [Subject] on an EventSourceId<T> is redundantWarningAn EventSourceId<T>-derived property already is the key and compliance subject, so [Key]/[Subject] on it is redundant — remove the attribute
CHR0027Ambiguous event stream idErrorA type both implements ICanProvideEventStreamId and declares a non-null [EventStreamId]; this throws at startup
CHR0028Redundant .AutoMap() callWarning.AutoMap() has no effect because AutoMap is enabled by default on projection builders; remove the call
CHR0029Redundant .Set().To() with matching property namesWarningA .Set(x => x.P).To(e => e.P) mapping with identical names duplicates what AutoMap already does; remove it
CHR0030[ChildrenFrom] child collection property auto-maps to nothingWarningA [ChildrenFrom] child collection property matching no event property and with no explicit mapping always projects empty; rename it or bridge with [SetFrom<T>]
CHR0031Reactor must not have mutable stateWarningReactors are re-created and replayed, so mutable instance state is unreliable; use readonly, primary-constructor-injected dependencies
CHR0032Reactor must not access storage directlyWarningInjecting a storage primitive like IMongoCollection<T> couples the reactor to a sink; read state via a read model or IReadModels.GetInstanceById
CHR0034[PII] cannot be applied to an EventSourceId<T>ErrorThe event source id is the encryption-key lookup identity, so it cannot be encrypted; [PII] on it throws PIINotSupportedOnEventSourceId at runtime
CHR0035Read model declares a reserved compliance subject propertyErrorChronicle reserves _subject, __subject, and __subjects for internal compliance-subject tracking; a same-named property collides with stored metadata
CHR0036Reducer must not have mutable stateWarningReducers are re-created and replayed, so mutable instance state or direct storage injection makes the fold non-deterministic; keep them stateless
CHR0037Event type migration generations must belong to one event typeWarningThe two generations referenced by an EventTypeMigration must resolve to the same event type id and differ only by generation, or the migration never applies — checked for both EventTypeGenerationFor<T> and the older explicit-id [EventType] style
CHR0039Assertion result is discarded and can never failWarningAn awaitable-returning Should* assertion on a Cratis testing surface whose result is discarded throws on an awaitable nobody observes, so the assertion silently passes regardless of behavior and CS4014 does not fire outside an async method
CHR0040Several [SetFromContext] for the same event type on one memberWarningThey write the same property in the definition, so only the last declared is kept and the earlier capture is silently dropped; capturing from several different event types is the supported use and is not flagged
CHR0041Event filter attribute on a projection has no effectWarningA projection observes every event of the types it declares and cannot filter on event metadata — only reactors and reducers can — so [EventStreamType], [EventSourceType], and [FilterEventsByTag] on a projection are silently ignored
CHR0042A joined property is also written locallyWarningA property written by both a local mapping and a join — model-bound or fluent — always ends up with the joined value regardless of arrival order, so a local write can never reset it; a flag latched from both sides silently sticks
CHR0043Key redirection carries a [PII] value across the compliance subjectWarningA root key or child parent-key redirect carries PII onto a document whose resolved compliance subject is not provably the value owner’s
CHR0045Event stream metadata attribute on an event type has no effectWarningAn append resolves its event source type and event stream type from the append itself, never from the event’s CLR type, so [EventStreamType] and [EventSourceType] on an [EventType] are read by nothing — declare them on the appending command, the observing reactor/reducer, or (for [EventStreamType]) the aggregate root whose appends they identify
CHR0046Passive read model redirects the document key away from the event’s own streamWarningA passive read model has no sink, so a read replays one event stream constrained to the requested key; a root key redirection points that replay at a stream the events were never appended to and the read returns a default-initialized model
CHR0047A clear declaration is never applied by projection constructionRetiredBoth declarations it reported - a null [SetValue] and a member-level [ClearWith] - are a working scalar clear now, so the rule was removed; the id stays reserved and is never reused
CHR0048A clear is declared for a member that cannot hold nullWarningClearing means returning a member to no value; a non-nullable member has no such state, so the only thing the projection could write is the type default - a different fact the read model cannot tell apart from a real value
CHR0049EventTypeGenerationFor<T> must reference a type marked with [EventType]ErrorA type marked with EventTypeGenerationFor<T> references a type that is not itself marked with [EventType], so there is no id to resolve the previous generation’s identity from
  • CHR0001, CHR0002, CHR0003, CHR0005, and CHR0007 provide a code fix that adds the missing [EventType] attribute to the referenced type.
  • CHR0026 provides a code fix that removes the redundant [Key]/[Subject] attribute.
  • CHR0028 provides a code fix that removes the redundant .AutoMap() call.
  • CHR0029 provides a code fix that removes the redundant .Set(...).To(...) mapping.

The analyzer is automatically included when you reference the Cratis.Chronicle NuGet package.